2D平台冲突处理
我正在尝试创建一个2D Platform(马里奥类型)游戏,我在正确处理碰撞方面有一些问题。我用C++编写这个游戏,使用SDL进行输入、图像加载、字体加载等。我还通过FreeGLUT库和SDL一起使用OpenGL来显示图形。
我的碰撞检测方法是AABB(轴对齐边界框),这是我真正需要开始的全部内容。我需要的是一种简单的方法,既能检测碰撞发生在哪一边,又能正确处理碰撞。因此,基本上,如果球员与平台顶部相撞,则将他重新定位到平台顶部;如果球员与两侧发生碰撞,则将球员重新定位到物体一侧;如果球员与平台底部发生碰撞,则将球员重新定位到平台下方。
我尝试了许多不同的方法,例如尝试找到穿透深度,并根据穿透深度将玩家向后定位。遗憾的是,我的尝试似乎都不能正常工作。球员的移动最终会出现故障,当我不想让球员移动的时候,他们会重新调整位置。部分原因可能是因为我觉得这件事很简单,但我想太多了。
如果任何人认为他们可以提供帮助,请查看下面的代码,并在可能的情况下帮助我改进这一点。如果可能的话,我不想使用库来处理这件事(因为我想自己学习)或SAT(分离轴定理)之类的东西。提前感谢您的帮助!
void world1Level1CollisionDetection()
{
for(int i; i < blocks; i++)
{
if (de2dCheckCollision(ball,block[i],0.0f,0.0f)==true)
{
de2dObj ballPrev;
ballPrev.coords[0] = ball.coords[0];
ballPrev.coords[1] = ball.coords[1];
ballPrev.coords[2] = ball.coords[2];
ballPrev.coords[3] = ball.coords[3];
ballPrev.coords[0] -= ball.xspeed;
ballPrev.coords[1] -= ball.yspeed;
ballPrev.coords[2] -= ball.xspeed;
ballPrev.coords[3] -= ball.yspeed;
int up = 0;
int left = 0;
int right = 0;
int down = 0;
if (ballPrev.coords[0] < block[i].coords[0] && ballPrev.coords[2] < block[i].coords[0] && (((ball.coords[1] < block[i].coords[1]) || (ball.coords[3] < ball.coords[1])) || ((ball.coords[1] < block[i].coords[3]) || ball.coords[3] < block[i].coords[3])))
{
left = 1;
}
if (ballPrev.coords[0] > block[i].coords[2] && ballPrev.coords[2] > block[i].coords[2] && (((ball.coords[1] < block[i].coords[1]) || (ball.coords[3] < ball.coords[1])) || ((ball.coords[1] < block[i].coords[3]) || (ball.coords[3] < block[i].coords[3]))))
{
right = 1;
}
if(ballPrev.coords[1] < block[i].coords[1] && block[i].coords[1] < ballPrev.coords[3] && ballPrev.coords[3] < block[i].coords[3])
{
up = 1;
}
if(block[i].coords[1] < ballPrev.coords[1] && ballPrev.coords[1] < block[i].coords[3] && block[i].coords[3] < ballPrev.coords[3])
{
down = 1;
}
cout << left << ", " << right << ", " << up << ", " << down << ", " << endl;
if (left == 1)
{
ball.coords[0] = block[i].coords[0] - 18.0f;
ball.coords[2] = block[i].coords[0] - 2.0f;
}
else if (right == 1)
{
ball.coords[0] = block[i].coords[2] + 2.0f;
ball.coords[2] = block[i].coords[2] + 18.0f;
}
else if (down == 1)
{
ball.coords[1] = block[i].coords[3] + 4.0f;
ball.coords[3] = block[i].coords[3] + 20.0f;
}
else if (up == 1)
{
ball.yspeed = 0.0f;
ball.gravity = 0.0f;
ball.coords[1] = block[i].coords[1] - 17.0f;
ball.coords[3] = block[i].coords[1] - 1.0f;
}
}
if (de2dCheckCollision(ball,block[i],0.0f,0.0f)==false)
{
ball.gravity = -0.5f;
}
}
}
要解释其中一些代码的含义:
BLOCKS变量基本上是一个存储块或平台数量的整数。我正在使用for循环检查所有块,该循环当前所在的数字由整数i表示。 坐标系可能看起来有点奇怪,所以这是值得解释的。 坐标[0]表示对象的x位置(左)(对象在x轴上的起点)。 COCORS[1]表示对象的y位置(顶部)(对象在y轴上的起点)。 坐标[2]表示对象的宽度加上坐标[0](右)。 坐标[3]表示对象的高度加上坐标[1](底部)。 De2dCheckCollision执行AABB冲突检测。 和大多数游戏一样,up代表负y,down代表正y。希望我已经为某人提供了足够的信息来成功地帮助我。如果我遗漏了什么可能很重要的东西,请让我知道,我会提供必要的信息。最后,对于任何可以提供帮助的人来说,提供代码将是非常有帮助的,并且非常感激。
再次感谢您的帮助!
编辑2:我已经使用新的算法更新了我的代码,该算法可以检查球在碰撞之前的位置。角箱现在可以在单个平台上正常工作,当我有一堵对象墙时,我可以正确地滑动到它上面。唯一剩下的问题是,当我在地面上时,会发生一种微小的抖动效应,球不断地上下移动,就像是被重力拉着一样,然后球又落回物体里。
编辑:以下是一个图像的URL,该图像试图显示我遇到的各种问题: http://img8.imageshack.us/img8/4603/collisionproblem.png
以防图片中的解释不太有意义,除非我跳过球,否则球不能向左移动越过物体的角落。但是,球可以向右移动,但在移动时会重新定位到对象的右侧,这是不需要的。这基本上创造了一个跳跃运动,当我向右移动时,它看起来像是球跳过了物体的一半左右。如果这不合理,请询问我,我将尝试澄清更多内容。
解决方案
代码的一个问题是您只检测到这样的情况:
如果圆恰好完全位于块内,则根本不需要重新定位。这是一个问题。
您试图将模拟看作是连续的,但请记住,它是离散的。一般来说,如果您只查看球的当前状态,您确实无法知道它撞到了哪一边。看看这两种可能性:
想到的第一个解决方案是也查看球的最后位置;更准确地说,查看增量向量。查看增量向量是否与墙相交。如果是,则在轴对齐的方向上朝着与增量向量相交的墙重新定位。
编辑:当我说"增量向量"时,我忘记了您移动的是一个正方形,而不是一个点。所以,如果你只看左上角的增量向量,这是不够的,因为它可能没有检测到球的一部分进入了一个拦网。相反,您可以查看所有4个角的增量向量。
相关文章