JS碰撞检测器问题:区分角色撞墙与落地的碰撞差异
解决玩家碰撞方块顶部与侧面的区分问题
嘿,我完全懂你现在的困扰——当前的碰撞逻辑不管玩家是从上方稳稳落到方块上,还是不小心从侧面撞过去,都会直接把玩家“拎”到方块顶部,这肯定不是你想要的效果。咱们来一步步搞定这个问题。
问题根源
你的hitTest函数只做了“是否碰撞”的判断,没有区分碰撞的方向。所以每次检测到碰撞,代码都会执行myPlayer.y = blocks[i].y - myPlayer.h,把玩家强行放到方块顶部,完全忽略了侧面碰撞的情况。
解决方案:判断碰撞方向
核心思路是:当检测到碰撞时,通过计算玩家与方块的重叠区域,结合玩家的移动速度,判断出碰撞的主要方向(顶部/左侧/右侧/底部),再针对不同方向执行对应的逻辑。
修改后的碰撞检测代码
function collisionDetector(){ // 画布边界碰撞逻辑保持不变 if(myPlayer.y + myPlayer.h > c.height){ myPlayer.vy = 0; myPlayer.ay = 0; myPlayer.y = c.height - myPlayer.h; myPlayer.onGround = true; } if(myPlayer.x + myPlayer.w >= c.width){ myPlayer.x = c.width - myPlayer.w; myPlayer.vx = 0; } if(myPlayer.x <= 0){ myPlayer.x = 0; myPlayer.vx = 0; } // 碰撞检测核心函数 function hitTest(a,b){ return a.y + a.h > b.y && a.y < b.y + b.h && a.x + a.w > b.x && a.x < b.x + b.w; } for(var i = 0; i < blocks.length; i++){ var block = blocks[i]; if(hitTest(myPlayer, block)){ // 计算各个方向的重叠量(重叠越小,说明碰撞越先发生在这个方向) var overlapTop = (myPlayer.y + myPlayer.h) - block.y; // 玩家底部撞方块顶部的重叠 var overlapBottom = (block.y + block.h) - myPlayer.y; // 玩家顶部撞方块底部的重叠 var overlapLeft = (myPlayer.x + myPlayer.w) - block.x; // 玩家右侧撞方块左侧的重叠 var overlapRight = (block.x + block.w) - myPlayer.x; // 玩家左侧撞方块右侧的重叠 // 确定碰撞的主要方向 var minOverlap = Math.min(overlapTop, overlapBottom, overlapLeft, overlapRight); // 根据不同方向处理碰撞 if(minOverlap === overlapTop && myPlayer.vy > 0){ // 顶部碰撞:玩家从上方落到方块上 myPlayer.y = block.y - myPlayer.h; myPlayer.vy = 0; // 停止垂直运动 myPlayer.onGround = true; } else if(minOverlap === overlapLeft){ // 左侧碰撞:玩家撞向方块右侧 myPlayer.x = block.x - myPlayer.w; myPlayer.vx = 0; // 停止水平运动 } else if(minOverlap === overlapRight){ // 右侧碰撞:玩家撞向方块左侧 myPlayer.x = block.x + block.w; myPlayer.vx = 0; // 停止水平运动 } else if(minOverlap === overlapBottom){ // 底部碰撞:玩家从下方顶到方块(比如跳起来撞方块底部) myPlayer.y = block.y + block.h; myPlayer.vy = 0; } } } }
代码解释
- 重叠量计算:通过计算玩家和方块在四个方向上的重叠长度,判断哪个方向是碰撞的“主要来源”——重叠量最小的方向,就是玩家最先接触到方块的方向。
- 速度判断:在顶部碰撞时额外检查
myPlayer.vy > 0(玩家正在向下运动),避免玩家从方块下方穿过时被误判为落地。 - 针对性处理:不同方向的碰撞对应不同的位置修正和速度重置,比如侧面碰撞只修正水平位置和速度,不会触发
onGround状态。
额外建议
- 记得在玩家跳跃或者离开方块时,把
myPlayer.onGround设为false,否则玩家会一直处于“可跳跃”状态。 - 如果你觉得重叠量的方式不够精准,也可以记录玩家碰撞前的位置(比如在更新玩家位置前保存
prevX和prevY),通过比较碰撞前后的位置来判断移动方向,这也是一种常用的碰撞方向判断方法。
内容的提问来源于stack exchange,提问作者Benjamhw
相关产品推荐
相关产品推荐

