关于小游戏:21天徒手撸一个游戏引擎4碰撞检测

65次阅读

共计 4721 个字符,预计需要花费 12 分钟才能阅读完成。

增加 gameover 素材。

loader.add('enemy', 'images/gameover.png')

减少一个 gameover 变量:

let gameover = false

在敌人的循环中,减少碰撞检测代码:

if(enemy.x + enemy.width > player.x && 
    enemy.x < player.x + enemy.width && 
    player.y + player.height > enemy.y && 
    player.y < enemy.y + enemy.height){gameover = true}

在 step 中,减少:

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)
      return
}

当初 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
const enemys = []
let gameover = false

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.on_load_finish((res) => {const player = new Sprite(0, 0, res['player'], 0.5)
  player.setPosition(windowWidth / 2, windowHeight - player.height)
  const step = (timestamp) => {context.clearRect(0, 0, windowWidth, windowHeight)
    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)
      return
    }
    time += 1;
    if (time % 150 == 0) {const enemy = new Sprite(0, 0, res['enemy'], 0.5)
      enemy.setPosition(rand(0, windowWidth), 0)
      enemys.push(enemy)
    }

    player.update()
    player.draw(context)
    enemys.map(enemy => {
      enemy.y++;
      enemy.draw(context)
      //collision
      if (enemy.x + enemy.width > player.x &&
        enemy.x < player.x + enemy.width && player.y + player.height > enemy.y &&
        player.y < enemy.y + enemy.height) {gameover = true}
    })
    window.requestAnimationFrame(step);
  }
  window.requestAnimationFrame(step);
  wx.onTouchMove(function (res) {const x = res.changedTouches[0].clientX
    const y = res.changedTouches[0].clientY
    player.setPosition(x, y)
  })
})

当初成果如下:

gameover 进去后,之前的游戏界面就没了。
所以须要对 update 和 draw 拆开:

const step = (timestamp) => {context.clearRect(0, 0, windowWidth, windowHeight)
    //update
    if(!gameover){
      time += 1;
      if (time % 150 == 0) {const enemy = new Sprite(0, 0, res['enemy'], 0.5)
        enemy.setPosition(rand(0, windowWidth), 0)
        enemys.push(enemy)
      }
      player.update()
      enemys.map(enemy => {
        enemy.y++;
        //collision
        if (enemy.x + enemy.width > player.x &&
          enemy.x < player.x + enemy.width && player.y + player.height > enemy.y &&
          player.y < enemy.y + enemy.height) {gameover = true}
      })
    }
    //draw
    player.draw(context)
    enemys.map(enemy => {enemy.draw(context)
    })
    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);
  }

当初成果如下:

然而游戏完结后,player 居然还能够拖动。当初 wx.onTouchMove ~~~~ 这里再改一下:

wx.onTouchMove(function (res) {if (!gameover) {const x = res.changedTouches[0].clientX
      const y = res.changedTouches[0].clientY
      player.setPosition(x, y)
    }
})

当初是成果:

然而发现,其实飞机并没有碰上。为什么呢?

因为这里的碰撞检测仅仅是用矩形。而飞机素材是通明的,因而碰撞到的其实是图片矩形,而飞机素材有透明度,所以看起来仿佛没有碰撞到。这怎么办呢?

要么做像素级的碰撞检测,要么进行多边形像素检测。简单的碰撞检测当前再做,这里先设置一个宽度,既碰撞到肯定水平才确定为碰撞到。

当初,碰撞检测代码变为:

const collision_buff = 0.8
if (enemy.x + enemy.width * collision_buff > player.x &&
          enemy.x < player.x + enemy.width * collision_buff && player.y + player.height * collision_buff > enemy.y &&
          player.y < enemy.y + enemy.height * collision_buff) {gameover = true}

当初,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
const enemys = []
let gameover = false
const collision_buff = 0.8

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.on_load_finish((res) => {const player = new Sprite(0, 0, res['player'], 0.5)
  player.setPosition(windowWidth / 2, windowHeight - player.height)
  const step = (timestamp) => {context.clearRect(0, 0, windowWidth, windowHeight)
    //update
    if (!gameover) {
      time += 1;
      if (time % 150 == 0) {const enemy = new Sprite(0, 0, res['enemy'], 0.5)
        enemy.setPosition(rand(0, windowWidth), 0)
        enemys.push(enemy)
      }
      player.update()
      enemys.map(enemy => {
        enemy.y++;
        //collision
        if (enemy.x + enemy.width * collision_buff > player.x &&
          enemy.x < player.x + enemy.width * collision_buff && player.y + player.height * collision_buff > enemy.y &&
          player.y < enemy.y + enemy.height * collision_buff) {gameover = true}
      })
    }
    //draw
    player.draw(context)
    enemys.map(enemy => {enemy.draw(context)
    })
    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)
    }
  })
})

成果如下

正文完
 0