【发布时间】:2011-07-06 04:38:23
【问题描述】:
我正在尝试创建一个 2D 平台游戏(Mario 类型),但在正确处理碰撞时遇到了一些问题。我正在用 C++ 编写这个游戏,使用 SDL 进行输入、图像加载、字体加载等。我还通过 FreeGLUT 库结合 SDL 使用 OpenGL 来显示图形。
我的碰撞检测方法是 AABB(Axis-Aligned Bounding Box),这是我真正需要开始的全部。我需要一种简单的方法来检测碰撞发生在哪一侧并正确处理碰撞。因此,基本上,如果玩家与平台顶部发生碰撞,则将他重新定位到顶部;如果两侧发生碰撞,请将玩家重新定位到物体的一侧;如果底部发生碰撞,请将播放器重新定位到平台下方。
我已经尝试了许多不同的方法来做到这一点,例如尝试找到穿透深度并将玩家向后重新定位穿透深度。可悲的是,我尝试过的任何方法似乎都无法正常工作。玩家的移动最终会变得非常有问题,并在我不想要的时候重新定位玩家。部分原因可能是因为我觉得这很简单,但我想多了。
如果有人认为他们可以提供帮助,请查看下面的代码,如果可以的话,请帮助我尝试改进。如果可能的话,我想避免使用库来处理这个问题(因为我想自己学习)或者像 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 表示。 坐标系可能看起来有点奇怪,所以值得解释一下。 coords[0] 表示对象的 x 位置(左侧)(从 x 轴开始的位置)。 coords[1] 表示对象的 y 位置(顶部)(从 y 轴开始的位置)。 coords[2] 表示对象的宽度加上 coords[0](右)。 coords[3] 表示对象的高度加上 coords[1](底部)。 de2dCheckCollision 执行 AABB 碰撞检测。 在大多数游戏中,向上是负 y,向下是正 y。
希望我已经提供了足够的信息来帮助我成功。如果我遗漏了一些可能很重要的内容,请告诉我,我会提供必要的信息。最后,对于任何可以提供帮助的人,提供代码将非常有帮助,非常感谢。
再次感谢您的帮助!
编辑 2:我用一种新算法更新了我的代码,该算法可以检查球在碰撞之前的位置。角落案例现在可以在那个单一平台上正常工作,当我有一堵墙时,我现在可以正确地靠着它滑动。唯一剩下的问题是,当我在地面上时,会发生一个小的抖动效应,球不断地上下移动,就好像它被重力拉着一样,然后球又落回物体中。
编辑:这是一个图像的 URL,试图显示我遇到的各种问题: http://img8.imageshack.us/img8/4603/collisionproblem.png
如果图片中的解释没有太多意义,除非我跳过它,否则球不能向左移动超过对象的角。然而,球可以向右移动,但它会在移动时重新定位到对象的右侧,这是不需要的。这实质上会产生一个跳跃运动,当我向右移动时,它会出现在球跳过物体的一半左右时。如果这没有意义,请问我,我会尽力澄清更多。
【问题讨论】:
-
这个问题可能更适合gamedev.stackexchange.com,但是......那里的人口似乎在各个方面都缺乏。毕竟在这里可能会更好。
-
不管怎样,平台游戏中的移动代码确实包含很多手动调整和故障。甚至有一群人对它们进行逆向工程以制作“工具辅助的快速运行”。
-
我以前听说过“工具辅助快速运行”。感谢您对平台游戏移动代码的提醒。看来我需要进行 lot 的手动调整才能使其正常工作。希望有人对我如何解决这个问题有一些想法。
标签: c++ opengl 2d sdl collision-detection