乐趣区

关于小游戏:21天徒手撸一个游戏引擎6自运动及在Sprite中实现碰撞检测

sprite.js 中的 constructor 函数中减少:

this.vx = 0
this.vy = 0

sprite.js 中的 update 函数:

this.x += this.vx
this.y += this.vy

这样,只有设置 vx 或 vy,它就能够本人动了。

在 Sprite.js 中的 constructor 函数设置:

this.on_update = () => {}

这是一个空办法,就是为了在实例化 sprite 时去设置 update 办法

相应地,Sprite.js 中:

  update() {
    this.x += this.vx
    this.y += this.vy
    this.on_update()}

则在更新本身坐标后调用了 on_update 办法。

在 Sprite.js 中新增:

  remove_from(arr) {const index = arr.indexOf(this)
    if (index != -1) {arr.splice(index, 1)
    }
  }

这样,就能够从 update 中写判断来从数组中移除本人。

在 game.js 中:

bullet.vy = -5
bullet.on_update = () => {if (bullet.y <= 0 - bullet.height) {bullet.remove_from(bullets)
    }
}

即敌机坐标超过屏幕下方,就从敌机数组中移除。

同样,把碰撞检测函数放到 Sprite.js 里:

collision_with(arr) {
    const self = this
    return arr.filter(item => {
      return item.x + item.width * this.collision_buff > self.x &&
        item.x < self.x + item.width * this.collision_buff && self.y + self.height * this.collision_buff > item.y &&
        self.y < item.y + item.height * this.collision_buff
    })
}

这时,对 player 而言,如果找到产生碰撞的敌机,则游戏完结:

player.on_update = () => {const arr = player.collision_with(enemys)
    if (arr.length > 0) {gameover = true}
}

对于子弹:

const collisioned = bullet.collision_with(enemys)
collisioned.map(item => {
    score += 1
    item.remove_from(enemys)
})
if (collisioned.length > 0) {bullet.remove_from(bullets)
}

当初,game.js 全副代码为:

import './libs/weapp-adapter'
import './libs/symbol'
import {
  ResLoader,
  Sprite
} from './codetyphon/index'
const context = canvas.getContext('2d')
const {
  windowWidth,
  windowHeight
} = wx.getSystemInfoSync()

let time = 0
let enemys = []
let bullets = []
let gameover = false
let score = 0

function rand(min, max) {return Math.round(Math.random() * (max - min) + min);
}

const loader = new ResLoader()
loader.add('player', 'images/player.png')
loader.add('enemy', 'images/enemy.png')
loader.add('gameover', 'images/gameover.png')
loader.add('bullet', 'images/bullet.png')
loader.on_load_finish((res) => {const player = new Sprite(0, 0, res['player'], 0.5)
  player.setPosition(windowWidth / 2, windowHeight - player.height)
  player.on_update = () => {const arr = player.collision_with(enemys)
    if (arr.length > 0) {gameover = true}
  }
  const update = () => {player.update()
    enemys.map((enemy, enemy_index) => {enemy.update()
    })
    bullets.map((bullet, bullet_index) => {bullet.update()
    })
  }
  const draw = () => {player.draw(context)
    enemys.map(enemy => {enemy.draw(context)
    })
    bullets.map(bullet => {bullet.draw(context)
    })
    context.font = 'normal 20px sans-serif';
    context.fillStyle = '#fff'
    context.fillText(score, 10, 30)
  }
  const step = (timestamp) => {context.clearRect(0, 0, windowWidth, windowHeight)
    //update
    if (!gameover) {
      time += 1;
      if (time % 60 == 0) {const enemy = new Sprite(0, 0, res['enemy'], 0.5)
        enemy.setPosition(rand(0, windowWidth - enemy.width), 0)
        enemy.vy = 3
        enemy.on_update = () => {if (enemy.y > windowHeight) {enemy.remove_from(enemys)
          }
        }
        enemys.push(enemy)
      }
      update()}
    draw()
    if (gameover) {context.drawImage(res['gameover'], windowWidth / 2 - res['gameover'].width / 4, windowHeight / 2 - res['gameover'].height / 4, res['gameover'].width / 2, res['gameover'].height / 2)
    }
    window.requestAnimationFrame(step);
  }
  window.requestAnimationFrame(step);
  wx.onTouchMove(function (res) {if (!gameover) {const x = res.changedTouches[0].clientX
      const y = res.changedTouches[0].clientY
      player.setPosition(x, y)
    }
  })
  wx.onTouchEnd((result) => {if (!gameover) {const bullet = new Sprite(0, 0, res['bullet'], 0.1)
      bullet.setPosition(player.x, player.y)
      bullet.vy = -5
      bullet.on_update = () => {if (bullet.y <= 0 - bullet.height) {bullet.remove_from(bullets)
        } else {const collisioned = bullet.collision_with(enemys)
          collisioned.map(item => {
            score += 1
            item.remove_from(enemys)
          })
          if (collisioned.length > 0) {bullet.remove_from(bullets)
          }
        }
      }
      bullets.push(bullet)
    }
  })
})
退出移动版