微信小游戲 demo 飛機大戰 代碼分析(四)(enemy.js, bullet.js, index.js)
微信小游戲 demo 飛機大戰 代碼分析(一)(main.js)
微信小游戲 demo 飛機大戰 代碼分析(二)(databus.js)
微信小游戲 demo 飛機大戰 代碼分析(三)(spirit.js, animation.js)
本博客將使用逐行代碼分析的方式講解該demo,本文適用於對其他高級語言熟悉,對js還未深入了解的同學,博主會盡可能將所有遇到的不明白的部分標注清楚,若有不正確或不清楚的地方,歡迎在評論中指正
本文的代碼均由微信小游戲自動生成的demo飛機大戰中獲取
enemy.js
用於實現敵人對象
代碼
import Animation from '../base/animation'
import DataBus from '../databus'
const ENEMY_IMG_SRC = 'images/enemy.png'
const ENEMY_WIDTH = 60
const ENEMY_HEIGHT = 60
const __ = {
speed: Symbol('speed')
}
let databus = new DataBus()
function rnd(start, end){
return Math.floor(Math.random() * (end - start) + start)
}
export default class Enemy extends Animation {
constructor() {
super(ENEMY_IMG_SRC, ENEMY_WIDTH, ENEMY_HEIGHT)
this.initExplosionAnimation()
}
init(speed) {
this.x = rnd(0, window.innerWidth - ENEMY_WIDTH)
this.y = -this.height
this[__.speed] = speed
this.visible = true
}
// 預定義爆炸的幀動畫
initExplosionAnimation() {
let frames = []
const EXPLO_IMG_PREFIX = 'images/explosion'
const EXPLO_FRAME_COUNT = 19
for ( let i = 0;i < EXPLO_FRAME_COUNT;i++ ) {
frames.push(EXPLO_IMG_PREFIX + (i + 1) + '.png')
}
this.initFrames(frames)
}
// 每一幀更新子彈位置
update() {
this.y += this[__.speed]
// 對象回收
if ( this.y > window.innerHeight + this.height )
databus.removeEnemey(this)
}
}
初始化
導入相應文件
創建所需常量
分別是敵機的圖片位置,高度和寬度
創建symbol常量和databus對象
- symbol的解釋見 微信小游戲 demo 飛機大戰 代碼分析 2(databus.js)
rnd(start,end)
- Math.random() 用於提供[0,1)區間的浮點數
- Math.floor() 返回小於等於該數字最大的整數
- 該函數的作用是返回一個start到end區間(end不取)返回內的一個隨機數
- 在后面該函數用於生成敵機的位置
Enemy
敵人類,繼承與Animation類
constructor()
構造器
- 根據提供的常量初始化敵機對象
- 並且初始化爆炸動畫,該函數在之后實現
init(speed)
初始化敵機速度
- 獲取隨機生成x坐標作為起始x位置
- 獲取其本身的高度取負值作為起始y坐標(一開始整個敵機還未進入屏幕,慢慢一點一點進入)
- js中坐標原點為屏幕左上角,以原點向左為x正方向,原點向下為y正方向,
initExplosionAnimation()
定義爆炸幀動畫
- 創建一個數組
- 設定爆炸的每一幀動畫的具體位置,以及數量
- 創建一個frames數組,將圖片按順序讀取並加入數組中
- 將該數組作為Animation類中定義的方法initFrames的參數初始化爆炸動畫
update()
邏輯更新函數,更新物體的參數,基本每個具體物體都具有該函數
-
按速度沒回合加上一定的y坐標(由於敵機是往下走的,因此加上)
-
若發現對象移動出屏幕,則將其回收
bullet.js
子彈的實現
初始化
導入相應包
定義需要的基本常量
定義symbol和生成databus
- symbol的解釋見 微信小游戲 demo 飛機大戰 代碼分析 2(databus.js)
Bullet
子彈實現類,繼承於精靈類(沒有繼承於動畫類,其無需動畫)
代碼
import Sprite from '../base/sprite'
import DataBus from '../databus'
const BULLET_IMG_SRC = 'images/bullet.png'
const BULLET_WIDTH = 16
const BULLET_HEIGHT = 30
const __ = {
speed: Symbol('speed')
}
let databus = new DataBus()
export default class Bullet extends Sprite {
constructor() {
super(BULLET_IMG_SRC, BULLET_WIDTH, BULLET_HEIGHT)
}
init(x, y, speed) {
this.x = x
this.y = y
this[__.speed] = speed
this.visible = true
}
// 每一幀更新子彈位置
update() {
this.y -= this[__.speed]
// 超出屏幕外回收自身
if ( this.y < -this.height )
databus.removeBullets(this)
}
}
constructor
構造器
- 通過預設置的常量初始化超類
init(x, y, speed)
初始化坐標位置和速度
update()
邏輯更新函數
- 為y坐標向上增加速度的大小,即應該減去速度的數值
- 將整個子彈超出屏幕外的(因此是小於-this.height而不是0)移入對象池中,即出游戲
index.js
玩家類
代碼
import Sprite from '../base/sprite'
import Bullet from './bullet'
import DataBus from '../databus'
const screenWidth = window.innerWidth
const screenHeight = window.innerHeight
// 玩家相關常量設置
const PLAYER_IMG_SRC = 'images/hero.png'
const PLAYER_WIDTH = 80
const PLAYER_HEIGHT = 80
let databus = new DataBus()
export default class Player extends Sprite {
constructor() {
super(PLAYER_IMG_SRC, PLAYER_WIDTH, PLAYER_HEIGHT)
// 玩家默認處於屏幕底部居中位置
this.x = screenWidth / 2 - this.width / 2
this.y = screenHeight - this.height - 30
// 用於在手指移動的時候標識手指是否已經在飛機上了
this.touched = false
this.bullets = []
// 初始化事件監聽
this.initEvent()
}
/**
* 當手指觸摸屏幕的時候
* 判斷手指是否在飛機上
* @param {Number} x: 手指的X軸坐標
* @param {Number} y: 手指的Y軸坐標
* @return {Boolean}: 用於標識手指是否在飛機上的布爾值
*/
checkIsFingerOnAir(x, y) {
const deviation = 30
return !!( x >= this.x - deviation
&& y >= this.y - deviation
&& x <= this.x + this.width + deviation
&& y <= this.y + this.height + deviation )
}
/**
* 根據手指的位置設置飛機的位置
* 保證手指處於飛機中間
* 同時限定飛機的活動范圍限制在屏幕中
*/
setAirPosAcrossFingerPosZ(x, y) {
let disX = x - this.width / 2
let disY = y - this.height / 2
if ( disX < 0 )
disX = 0
else if ( disX > screenWidth - this.width )
disX = screenWidth - this.width
if ( disY <= 0 )
disY = 0
else if ( disY > screenHeight - this.height )
disY = screenHeight - this.height
this.x = disX
this.y = disY
}
/**
* 玩家響應手指的觸摸事件
* 改變戰機的位置
*/
initEvent() {
canvas.addEventListener('touchstart', ((e) => {
e.preventDefault()
let x = e.touches[0].clientX
let y = e.touches[0].clientY
//
if ( this.checkIsFingerOnAir(x, y) ) {
this.touched = true
this.setAirPosAcrossFingerPosZ(x, y)
}
}).bind(this))
canvas.addEventListener('touchmove', ((e) => {
e.preventDefault()
let x = e.touches[0].clientX
let y = e.touches[0].clientY
if ( this.touched )
this.setAirPosAcrossFingerPosZ(x, y)
}).bind(this))
canvas.addEventListener('touchend', ((e) => {
e.preventDefault()
this.touched = false
}).bind(this))
}
/**
* 玩家射擊操作
* 射擊時機由外部決定
*/
shoot() {
let bullet = databus.pool.getItemByClass('bullet', Bullet)
bullet.init(
this.x + this.width / 2 - bullet.width / 2,
this.y - 10,
10
)
databus.bullets.push(bullet)
}
}
初始化
導入相應文件
獲取屏幕大小作為常量
創建基本常量
Player
玩家類,繼承於Spirit類
構造器
- 初始化超類
- 設置玩家初始位置,位於屏幕底部並且居中(應注意判斷位置是判斷其左上角位置)
- 設定判斷是否有觸碰的變量和子彈數組
- 初始化事件監聽函數
- 事件監聽相當於是在等待事件的發生,一旦發生就會隨之執行的函數
checkIsFingerOnAir(x, y)
判斷玩家手指是否在飛機上
- deviation變量相當於是擴展玩家手指對飛機控制的范圍設定的參數
- 判斷手指與飛機的關系和位置
setAirPosAcrossFingerPosZ(x, y)
根據手指的位置設置飛機的位置
保證手指處於飛機中間
同時限定飛機的活動范圍限制在屏幕中
initEvent()
監聽函數
- 綁定touchstart事件, 即開始觸碰事件,並傳入一個匿名函數作為回調函數,作為觸發該事件時的回調
- 若觸碰時觸碰的是飛機則將飛機被觸碰設置為真並且將飛機中心移動到手指中心
- e.preventDefault() 這是取消事件本身的默認動作的函數
- 綁定touchmove事件,即觸碰移動
- 若觸碰飛機情況為真,則將飛機移動到相應位置
- 綁定touchend事件,即觸碰結束
shoot()
玩家射擊函數
- 從對象池中取一個子彈
- 根據玩家位置初始化子彈位置