大家好,我们都知道,在一些游戏中,玩家和地图间的碰撞效果是必不可少的,但是有时自己做出的效果不尽人意,要不就是产生许多空气墙,要不就是直接穿墙。那么今天就为大家介绍如何用JavaScript完美实现碰撞检测。
开始之前我们定义一个示例:
map = [
[1,1,1,1,1,1,1,1],
[1,0,0,0,0,0,0,1],
[1,0,0,0,0,0,0,1],
[1,0,0,1,1,0,0,1],
[1,0,0,1,1,0,0,1],
[1,0,0,0,0,0,0,1],
[1,0,0,0,0,0,0,1],
[1,1,1,1,1,1,1,1],
];//地图数据
solidBlock = [1];//储存实体方块的id
player = {
top:1,
left:2,
speed:0.1
};//储存玩家位置信息,速度
首先,我们要知道,一个玩家可以站在1个方块,2个方块甚至4个方块上(玩家体型和单个方块差不多时),
我们就需要判定所处的4个方块是否有实体方块,
并且,在以上示例中,玩家的坐标可能会出现有小数的情况,
如果我们用 map[player.top][player.left] 读取是不行的,
我们就需要两个函数: Math.floor(num.) 向下取整和 Math.ceil(num.) 向上取整
例如,当玩家处于四个方块之间时,可以用以下代码获取:
map[Math.floor(player.top)][Math.floor(player.left)]//左上角方块的ID(或者说是编号)
map[Math.ceil(player.top)][Math.floor(player.left)]//左下角方块的ID(或者说是编号)
map[Math.floor(player.top)][Math.ceil(player.left)]//右上角方块的ID(或者说是编号)
map[Math.ceil(player.top)][Math.ceil(player.left)]//右下角方块的ID(或者说是编号)
数组.indexOf(项) 表示在数组中搜索这个项,
如果有则返回项的位置,没有则返回-1
solidBlock.indexOf(方块Id) == -1 表示判断这个方块是否为非实体方块,
由此我们可以做出第一个碰撞判断:
move = (direction/*方向*/)=>{
if (player.speed <= 1) {
//速度不超过一格时
if (direction == "up") {
//向屏幕上方移动时
if (solidBlock.indexOf(map[Math.floor(player.top - player.speed)][Math.ceil(player.left)]) == -1) {
if (solidBlock.indexOf(map[Math.floor(player.top - player.speed)][Math.floor(player.left)]) == -1) {
//假设移动前的位置刚好没有实体方块,那么移动后只需判断移动的方向轴即可(比如向上走时判定左上角和右上角)
player.top -= player.speed;
}
}
else if (solidBlock.indexOf(map[Math.floor(player.top)][Math.ceil(player.left)]) == -1) {
if (solidBlock.indexOf(map[Math.floor(player.top)][Math.floor(player.left)]) == -1) {
//如果原速度已经无法行走,但是可以通过 Math.floor() 和 Math.ceil() 将玩家贴在墙壁边时则进行校准
//如果缺少这部分校准,则会在实体方块边上留间隙无法填满,下同
player.top = Math.floor(player.top);
}
}//校准
}
else if (direction == "down") {
//向屏幕下方移动时
if (solidBlock.indexOf(map[Math.ceil(player.top + player.speed)][Math.ceil(player.left)]) == -1) {
if (solidBlock.indexOf(map[Math.ceil(player.top + player.speed)][Math.floor(player.left)]) == -1