21天徒手撸一个游戏引擎(4)碰撞检测

codetyphon

添加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)
  })
})

现在效果如下:

image

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

现在效果如下:

image

但是游戏结束后,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)
    }
})

现在是效果:

image

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

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

要么做像素级的碰撞检测,要么进行多边形像素检测。复杂的碰撞检测以后再做,这里先设置一个宽度,既碰撞到一定程度才确定为碰撞到。

现在,碰撞检测代码变为:

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

效果如下

image

阅读 592

17 声望
0 粉丝
0 条评论
17 声望
0 粉丝
文章目录
宣传栏