Canvas 2D矩形碰撞检测实现:碰撞时阻挡玩家移入方块
Canvas 2D 玩家与方块碰撞阻挡实现方案
原代码核心问题
- 遍历逻辑错误:双层
forEach嵌套遍历cubeX和cubeY会把所有X坐标和Y坐标随机配对,生成大量实际不存在的虚拟方块,检测对象从根上就出错。 - 判定逻辑错误:轴对齐碰撞的判定条件写反,比如Y轴的两个判断条件互斥,永远不可能触发碰撞分支。
- 缺少碰撞响应逻辑:只留了方向注释,没有实际的坐标修正代码,就算检测到碰撞也不会阻挡玩家移动。
前置数据修正
不推荐分开用两个数组存储方块的X、Y坐标,很容易出现坐标配对错误,优先改成方块对象数组存储属性:
// 推荐数据结构,每个方块的坐标、宽高一一对应 const cubes = [ {x: 100, y: 100, w: 50, h: 50}, {x: 220, y: 160, w: 50, h: 50}, // 其余方块配置 ]
如果暂时无法修改原有cubeX/cubeY数组结构,遍历的时候必须按下标配对坐标,禁止双层嵌套遍历:
// 原有数组的正确遍历方式 for (let i = 0; i < cubeX.length; i++) { const currentCube = { x: cubeX[i], y: cubeY[i], w: cube.w, // 替换为实际存储方块宽度的变量 h: cube.h // 替换为实际存储方块高度的变量 } // 针对当前真实存在的方块做碰撞检测 }
核心碰撞实现
1. 轴对齐矩形(AABB)碰撞判定
两个无旋转的矩形发生碰撞的充要条件是X、Y轴同时存在重叠,封装通用判定函数:
// 传入两个带x/y/w/h属性的矩形,碰撞返回true,否则返回false function checkAABBCollide(rect1, rect2) { return rect1.x < rect2.x + rect2.w && rect1.x + rect1.w > rect2.x && rect1.y < rect2.y + rect2.h && rect1.y + rect1.h > rect2.y }
2. 碰撞后方向判定与位置修正
碰撞发生后,计算玩家和方块在X、Y轴的重叠深度,重叠量更小的轴就是碰撞的入射方向,沿这个轴把玩家推到方块边界外即可实现阻挡效果:
function fixPlayerCollision() { // 遍历所有真实方块 for (let i = 0; i < cubeX.length; i++) { const cube = { x: cubeX[i], y: cubeY[i], w: cube.w, h: cube.h } // 没碰撞直接跳过 if (!checkAABBCollide(player, cube)) continue // 计算X、Y轴的重叠深度 const overlapX = Math.min( player.x + player.w - cube.x, // 玩家从左侧撞方块的重叠量 cube.x + cube.w - player.x // 玩家从右侧撞方块的重叠量 ) const overlapY = Math.min( player.y + player.h - cube.y, // 玩家从顶部撞方块的重叠量 cube.y + cube.h - player.y // 玩家从底部撞方块的重叠量 ) // 沿重叠量更小的轴修正玩家位置 if (overlapX < overlapY) { // X轴方向碰撞 player.x = player.x < cube.x ? cube.x - player.w : cube.x + cube.w } else { // Y轴方向碰撞 player.y = player.y < cube.y ? cube.y - player.h : cube.y + cube.h } } }
渲染循环执行顺序
因为逻辑跑在requestAnimationFrame()驱动的循环里,每帧执行顺序不能乱,否则会出现穿模、碰撞延迟:
- 读取WASD按键状态,计算本帧玩家位移,先更新
player.x、player.y到未做碰撞检测的目标位置 - 调用
fixPlayerCollision()遍历所有方块,修正玩家碰撞后的位置 - 清空画布,依次绘制所有方块、修正位置后的玩家
注意事项
- 不要在更新玩家坐标之前做碰撞检测,否则会出现一帧的穿模延迟。
- 普通WASD移动速度下上述逻辑足够稳定,如果玩家单帧移动距离超过方块厚度(高速移动场景),可以额外补充扫掠碰撞检测避免穿模。
- 不需要给四个碰撞方向单独写冗余的判定分支,通过重叠深度判断方向的代码更简洁,也不容易出现条件写反的问题。
内容的提问来源于stack exchange,提问作者user19143897
相关产品推荐
相关产品推荐

