Javascript碰撞检测系统不会忽略阻塞的碰撞

我在使用EaselJS和我的碰撞检测系统进行小游戏开发时遇到了问题,我需要别人的帮助。 当英雄(圆形位图)碰撞一个物体并且第一个物体后面有其他物体时,即使第二次碰撞被阻挡,英雄也会与两个物体发生碰撞。 这是一个图像说明:

问题的原因非常简单,即使问题本身不是:

该碰撞检测系统基于圆的未来位置(而不是其实际位置),然后如果圆的下一个位置与矩形相交,则它将反弹。 问题在于,如果未来位置与两个矩形相交,则圆圈将在两个矩形中反弹 – 即使实际的圆周运动被另一个矩形阻挡,也无法到达第二个矩形。

更新:请注意,只有在由于rect创建顺序而保持向上箭头时才会出现此问题。


这是相关的JavaScript代码:

rects.forEach(function (rect) { // Affect all rects // Collision detection: // (This MUST BE after every change in xvel/yvel) // Next circle position calculation: var nextposx = circle.x + event.delta / 1000 * xvel * 20, nextposy = circle.y + event.delta / 1000 * yvel * 20; // Collision between objects (Rect and Circle): if (nextposy + height(circle) > rect.y && nextposx + width(circle) > rect.x && nextposx < rect.x + rect.width && nextposy < rect.y + rect.height) { if (circle.y + height(circle) < rect.y) { cls("top"); } if (circle.x + width(circle)  rect.x + rect.width) { cls("right"); } if (circle.y > rect.y + rect.height) { cls("bottom"); } } // Stage collision: if (nextposy < 0) { // Collided with TOP of stage. Trust me. cls("bottom"); // Inverted collision side is proposital! } if (nextposx  stage.canvas.width) { cls("left"); } if (nextposy + height(circle) > stage.canvas.height) { cls("top"); } }); 

的jsfiddle

您必须独立处理水平和垂直碰撞。

我对你的JS小提琴做了一些小改动: http : //jsfiddle.net/Kf6cv/1/它现在应该可以工作了,我做的是把你的一张支票分成两部分:

 if (nextposy + height(circle) > rect.y && circle.x + width(circle) > rect.x && circle.x < rect.x + rect.width && nextposy < rect.y + rect.height) { if (circle.y + height(circle) < rect.y) { cls("top"); } if (circle.y > rect.y + rect.height) { cls("bottom"); } } if (nextposx + width(circle) > rect.x && nextposx < rect.x + rect.width && circle.y + height(circle) > rect.y && circle.y < rect.y + rect.height) { if (circle.x + width(circle) < rect.x) { cls("left"); } if (circle.x > rect.x + rect.width) { cls("right"); } } 

这样做的原因是,如果同时检查两个方向,它将阻止两个方向的移动(或使其反弹)(如图中的红色图形) – 即使它可能移动到一个方向。 检查水平/垂直的顺序通常无关紧要,通常只有当你的“英雄”100%边对边接近另一个对象时才会这样。 但你可以先用更高的速度检查方向,所以如果| velX | > | velY | 然后你首先检查水平碰撞。

另外我会说在检查后直接应用新位置是明智的,现在它会进行两次独立检查然后应用两个方向的运动 – 我不确定它但我可以想象这可能会导致以后有些问题。

我已经找到了这个问题的解决方案,而不会影响边缘到边缘的碰撞!

首先,我将两个forEach s中的forEach循环分开:第一个处理左右碰撞,第二个处理边对边碰撞,因为这种方式首先将对侧反应应用于所有对象,然后它检查剩余的边缘到边缘的碰撞。 然后我改变了碰撞检测的核心方式,使用当前和最后帧位置之间的比较(而不是使用估计的当前和未来)。

这是最终的相关代码:

 function colhndlr(obj1, obj2array){ var sidecollided = false; // Side-to-side collision handler: obj2array.forEach(function(obj2){ // Top side: if(obj1.ypast + obj1.height < obj2.y && obj1.y + obj1.height >= obj2.y && // Checks if past position X was correct: obj1.xpast + obj1.width >= obj2.x && obj1.xpast <= obj2.x + obj2.width){ // Collided with top } // Left side: if(obj2.clsdir > 2 && // Checks if object is side-collideable obj1.xpast + obj1.width < obj2.x && obj1.x + obj1.width >= obj2.x && // Checks if past position Y was correct: obj1.ypast + obj1.height >= obj2.y && obj1.ypast <= obj2.y + obj2.height){ // Collided with left } // Right side: if(obj2.clsdir > 2 && // Checks if object is side-collideable obj1.xpast > obj2.x + obj2.width && obj1.x <= obj2.x + obj2.width && // Checks if past position Y was correct: obj1.ypast + obj1.height >= obj2.y && obj1.ypast <= obj2.y + obj2.height){ // Collided with right } // Bottom side: if(obj2.clsdir == 4 && // Checks if object is bottom-collideable obj1.ypast > obj2.y + obj2.height && obj1.y <= obj2.y + obj2.height && // Checks if past position X was correct: obj1.xpast + obj1.width >= obj2.x && obj1.xpast <= obj2.x + obj2.width){ // Collided with bottom } }); /* Now that every side-to-side collision change was made, the edge-to-edge collision handler will not detect blocked collisions. */ if(!sidecollided){ // Edge-to-edge collision handler: obj2array.forEach(function(obj2){ if(obj2.clsdir != 1){ // If it's 1 then there's no need for edge collisions // Top left edge: if(obj1.ypast + obj1.height < obj2.y && obj1.xpast + obj1.width < obj2.x && obj1.y + obj1.height >= obj2.y && obj1.x + obj1.width >= obj2.x){ // Collided with top left edge } // Top right edge: if(obj1.ypast + obj1.height < obj2.y && obj1.xpast > obj2.x + obj2.width && obj1.y + obj1.height >= obj2.y && obj1.x <= obj2.x + obj2.width){ // Collided with top right edge } // Bottom right edge: if(obj2.clsdir == 4 && // Checks if object is bottom collideable obj1.ypast > obj2.y + obj2.height && obj1.xpast > obj2.x + obj2.width && obj1.y <= obj2.y + obj2.height && obj1.x <= obj2.x + obj2.width){ // Collided with bottom right edge } // Bottom left edge: if(obj2.clsdir == 4 && // Checks if object is bottom collideable obj1.ypast > obj2.y + obj2.height && obj1.xpast + obj1.width < obj2.x && obj1.y <= obj2.y + obj2.height && obj1.x + obj1.width >= obj2.x){ // Collided with bottom left edge } } }); } } 

的jsfiddle