JavaScript俯视角碰撞检测:如何判断碰撞发生的轴
解决俯视角游戏碰撞检测的轴判断问题
嘿,这个问题我之前做2D俯视角RPG的时候也踩过坑!核心就是只知道碰撞发生了,但没搞清楚是哪个轴触发的碰撞,结果误把两个方向的移动都锁死了。其实用AABB(轴对齐边界框)的重叠量对比就能轻松搞定,下面给你一步步拆解:
核心思路:通过重叠量判断碰撞轴
对于俯视角里绝大多数的轴对齐矩形碰撞来说,碰撞发生时两个物体在X、Y轴上都会有重叠,但重叠量更小的那个轴,就是碰撞的“主要接触轴”——简单说就是物体是从这个轴的方向撞过来的,我们只需要阻挡这个轴的移动,另一个轴的操作可以正常保留。
举个实际场景:你同时按上+右,右边有墙。此时X轴的重叠量会远小于Y轴(因为玩家是向右移动撞上墙,Y轴的重叠是两个物体本来的上下覆盖),所以我们只锁X轴,让玩家能正常向上走。
具体实现步骤
1. 预判玩家的下一个位置
在执行实际移动前,先计算玩家按当前方向键移动后的位置,这样能提前检测碰撞,避免撞上去再修正的生硬感:
// 假设player有dx(X方向速度)、dy(Y方向速度)、width、height属性 const nextPlayerPos = { x: player.x + player.dx, y: player.y + player.dy, width: player.width, height: player.height };
2. 检测碰撞并计算重叠量
遍历场景中的障碍物,找到和玩家预判位置碰撞的物体,然后分别计算X、Y轴的重叠量:
// 基础AABB碰撞检测函数 function checkAABBCollision(rectA, rectB) { return rectA.x < rectB.x + rectB.width && rectA.x + rectA.width > rectB.x && rectA.y < rectB.y + rectB.height && rectA.y + rectA.height > rectB.y; } // 计算两个矩形的轴重叠量 function getCollisionOverlap(rectA, rectB) { const overlapX = Math.min(rectA.x + rectA.width, rectB.x + rectB.width) - Math.max(rectA.x, rectB.x); const overlapY = Math.min(rectA.y + rectA.height, rectB.y + rectB.height) - Math.max(rectA.y, rectB.y); return { overlapX, overlapY }; } // 假设obstacles是场景中所有障碍物的数组 const collidedObstacle = obstacles.find(obstacle => checkAABBCollision(nextPlayerPos, obstacle) ); if (collidedObstacle) { const { overlapX, overlapY } = getCollisionOverlap(nextPlayerPos, collidedObstacle);
3. 根据重叠量判断阻挡轴
对比两个重叠量的绝对值,小的那个就是需要阻挡的轴:
if (Math.abs(overlapX) < Math.abs(overlapY)) { // X轴重叠更小,碰撞来自X方向,阻挡X移动,保留Y移动 player.y = nextPlayerPos.y; // 可选:微调X位置避免卡墙,比如向右撞墙时设为player.x = collidedObstacle.x - player.width } else { // Y轴重叠更小,碰撞来自Y方向,阻挡Y移动,保留X移动 player.x = nextPlayerPos.x; // 可选:微调Y位置避免卡墙,比如向上撞墙时设为player.y = collidedObstacle.y - player.height } } else { // 没有碰撞,正常执行移动 player.x = nextPlayerPos.x; player.y = nextPlayerPos.y; }
补充:处理多障碍物碰撞
如果玩家同时撞到多个障碍物,可以遍历所有碰撞的障碍物,计算每个的重叠量,取最小重叠量对应的轴作为阻挡轴——这样能保证玩家只被最“先接触”的那个方向阻挡,不会出现多个方向同时锁死的情况。
为什么这个方法有效?
轴对齐矩形碰撞时,重叠量小的轴是物体“刚接触”的轴,另一个轴的重叠是因为两个物体本来就在那个轴上有覆盖。比如玩家向右撞墙,X轴刚重叠一点,Y轴可能已经有很大的重叠(因为玩家和墙高度相近),所以只锁X轴就对了。
内容的提问来源于stack exchange,提问作者Sodex234
相关产品推荐
相关产品推荐

