使用AABB的碰撞检测问题

我使用AABB在我的主要游戏精灵和各种平台之间实现了一个简单的碰撞检测例程(请参阅下面的代码)。 它的效果很好,但是现在我正在引入重力让我的角色掉下来,并且在我的CD例程中出现了一些问题。

我认为问题的关键在于我的CD例程将精灵沿着其中已经穿透less量的轴移回到另一个精灵。 所以,如果它在Y轴上多于X,那么它将沿着X轴移回。

然而,现在我的(英雄)精灵正在以每帧30像素的速度下降(这是一个1504高的屏幕 – 我需要它快速下降,因为我想试图模拟“正常”的重力,任何慢一点看起来怪异)我得到这些问题。 我会试着用几张图片来展示正在发生的事情(以及我认为是什么造成的 – 虽然我不确定):(代码如下图)。

我将不胜感激关于如何解决这个问题的一些建议。

在这里输入图像描述

为了澄清,在上面的图片中,当我说这个位置被“错误地”纠正了,这可能有点误导。 代码本身是如何正确工作的,或者换言之,algorithm本身如果performance得如何我期望它,但我需要改变它的行为来阻止这个问题的发生,希望澄清我的意见在图片。

在这里输入图像描述

我的代码

public boolean heroWithPlatforms(){ //Set Hero center for this frame heroCenterX = hero.xScreen+(hero.quadWidth/2); heroCenterY = hero.yScreen+(hero.quadHeight/2); //Iterate through all platforms to check for collisions for(x=0;x<platformCoords.length;x+=2){ //Set platform Center for this iteration platformCenterX = platformCoords[x]+(platforms.quadWidth/2); platformCenterY = platformCoords[x+1]+(platforms.quadHeight/2); // the Dif variables are the difference (absolute value) // of the center of the two sprites being compared (one for X axis difference //and on for the Y axis difference) difX = Math.abs(heroCenterX-platformCenterX); difY = Math.abs(heroCenterY-platformCenterY); //If 1 //Check the difference between the 2 centers and compare it to the vector (the sum of //the two sprite's widths/2. If it is smaller, then the sprites are pverlapping along //the X axis and we can now proceed to check the Y axis if (difX<vecXPlatform){ //If 2 //Same as above but for the Y axis, if this is also true, then we have a collision if(difY<vecYPlatform){ //we now know sprites are colliding, so we now need to know exactly by how much //penX will hold the value equal to the amount one sprite (hero, in this case) //has overlapped with the other sprite (the platform) penX = vecXPlatform-difX; penY = vecYPlatform-difY; //One sprite has penetrated into the other, mostly in the Y axis, so move sprite //back on the X Axis if (penX < penY){hero.xScreen-=penX*(heroCenterX-platformCenterX>=0 ? -1 : 1);} //Sprite has penetrated into the other, mostly in the X asis, so move sprite //back on the Y Axis else if (penY < penX) {hero.yScreen-=penY*(heroCenterY-platformCenterY>=0 ? -1 : 1);} return true; }//Close 'If' 2 } //Close 'If' 1 } //Otherwise, no collision return false; } 

Solutions Collecting From Web of "使用AABB的碰撞检测问题"

在我对HTML5 canvas和AABB的实验中,我发现了你正在经历的事情。 当我试图从相邻的32×32像素的盒子制作平台时,就发生了这种情况。

我按个人喜好命令尝试的解决scheme

1 – 按轴分割运动

我目前的一个,我想我会继续我的游戏。 但是一定要检查一下我所说的Phantom AABB,如果你需要一个快速的解决scheme,而不必修改很多你目前的devise。

我的游戏世界有非常简单的物理。 没有力量(尚)的概念,只有stream离失所。 重力是一个不断的下降。 没有加速(还)。

位移由轴应用。 在这包括这第一个解决scheme。

每个游戏框架:

 player.moves.y += gravity; player.moves.x += move_x; 

move_x是根据input处理设置的,如果没有按下箭头键,那么move_x = 0。低于零的值意味着剩下,否则向右。

处理所有其他移动的精灵,并确定他们的“移动”组件的值,他们也有“移动”组件。

注意:在碰撞检测和响应之后,移动部件必须设置为零,x和y属性,因为下一个滴答重力将再次被添加。 如果你没有重置,你将以两倍所需重力的moves.y结束,在下一个勾号将是三次。

然后input位移应用和碰撞检测代码。

移动组件不是精灵的当前位置。 即使moves.x或y改变,精灵还没有移动。 “移动”组件是一种可以将位移应用到游戏循环正确部分的精灵位置的方法。

首先处理y轴(moves.y)。 将moves.y应用于sprite.position.y。 然后应用AABB方法来查看正在处理的移动精灵是否与平台AABB重叠(您已经了解如何执行此操作)。 如果重叠,则通过应用penetration.y将精灵重新移回y轴。 是的,与我的其他答案相反,现在这个移动演变的方法忽略了这个过程的渗透。 而且我们使用penetration.y,即使它大于penetration.x,我们甚至不检查它。

然后处理x轴(moves.x)。 将moves.x应用于sprite.position.x。 和以前相反。 这次你只能通过应用penetration.x来移动精灵。 和以前一样,你不会在意penetration.x是小于还是大于penetration.y。

这里的概念是,如果精灵不移动,并且最初没有碰撞,那么它将保持在下一帧(sprite.moves.x和y为零)。 另一个游戏对象神奇地传送到一个与精灵重叠的位置开始处理的特殊情况是我稍后将要处理的。

当一个精灵开始移动。 如果它只在x轴上移动,那么我们只是感兴趣,如果它渗透了左边或右边的东西。 由于精灵没有向下移动,我们知道这是因为移动部件的y属性为零,所以我们甚至不检查穿透的计算值。我们只能在penetration.x上看到。 如果渗透存在于运动轴线上,我们应用修正,否则我们只是让精灵移动。

对角线位移怎么样,不一定是45度角?

建议的系统可以处理它。 您只需要分别处理每个轴。 在你的模拟。 不同的力量被应用于精灵。 即使你的引擎还不了解力量。 这些力转化为二维平面上的任意位移,这个位移是任何方向和任何长度的二维vector。 从这个向量你可以提取y轴和x轴。

如果位移vector太大怎么办?

你不想要这个:

 | | | | | | | |_ _ _ _ _ _ _ _ _ 

由于我们的新动作是先应用逻辑处理一个轴,然后处理另一个轴,那么大的位移可能会像碰到一个大的L一样被碰撞代码看到,这将无法正确检测到与位移vector相交的物体的碰撞。

解决的办法是以较小的步幅分割大的位移,理想的是你的精灵宽度或高度,或者一半的精灵宽度或高度。 要获得像这样的东西:

 |_ |_ |_ |_ |_ |_ |_ |_ 

怎么样传送精灵?

如果将传送表示为大位移,则使用与正常移动相同的移动组件,则没有问题。 如果你不这样做,那么你必须考虑一种方法来标记由冲突代码处理的传送精灵(添加到专门用于这个目的的列表?),在响应代码中,您可以直接replace出现在传送发生的方式。

2 – 幻影AABB

对于受到重力影响的每个精灵(从精灵底部开始),具有相同的精灵AABB宽度和1个像素高度,都有一个辅助AABB。

这里的想法是这个幻影AABB总是与精灵下面的平台相碰撞。 只有当幻像AABB不重叠时,才允许重力应用于精灵。

您不需要计算幻影AABB和平台的穿透vector。 你只对一个简单的碰撞testing感兴趣,如果它与一个平台重叠,重力不能被应用。 你的精灵可以有一个布尔属性,告诉它是否在平台上或在空中。 当您的幻像AABB不与播放器下方的平台碰撞时,您处于空中。

这个:

 player.position.y += gravity; 

成为这样的事情:

 if (player.onGround == false) player.position.y += gravity; 

非常简单可靠。

你离开你的AABB实施。

幻影AABB可能有一个专门的循环处理它们,只检查简单的碰撞,不要浪费时间计算穿透向量。 这个循环必须在正常的碰撞和响应代码之前。 你可以在这个循环中施加重力,因为这些空气中的精灵会施加重力。 如果幻像AABB本身就是一个类或结构,它可能会引用它所属的精灵。

这与其他建议的解决scheme非常相似,您可以检查您的播放器是否正在跳跃。 我给出了一种可能的方法来检测玩家是否有脚踏平台。

我会将平台拼贴组合成一个平台实体。

例如,假设您从图片中取出3个图块并将它们合并为一个实体,那么您的实体将具有以下冲突框:

 Left = box1.left Right = box3.right Top = box1.top Bottom = box1.bottom 

使用碰撞会使y在整个平台的大部分平台中穿透力最小,同时仍然允许在平台内安装特定的瓷砖。

像这样的问题在新的碰撞检测方法中很常见。

我不太了解你当前的碰撞设置,但是这是应该如何去做的:

首先,让这些variables:

  1. 做一个X和Y速度
  2. 重力
  3. 做一个跳跃速度
  4. 做一个isJumping

其次,制定计时器来计算影响物体速度的增量。

第三,这样做:

  1. 检查玩家是否正在按下跳跃button而不是跳跃,如果是,则将jumpSpeed添加到Y速度。
  2. 从每次更新的Y速度减去重力以模拟重力
  3. 如果玩家的y +高度小于或等于平台y,则将Y速度设置为0,并将玩家的Yjoin平台的y +玩家的身高。

如果你这样做,不应该有任何问题。 希望这可以帮助!