我的游戏引擎中的碰撞解决方案遇到了一个小问题。如果两个物体碰撞并且该碰撞导致速度变为零,则物体的边缘将彼此重叠并且它们将被卡住。
有没有办法在这种情况下实施捕获?即,在正确的方向上移动物体,使它们不会卡住。
以下是我检查碰撞和移动物体的方法。在实体上调用update时,它会移动(x,y)。
public static void Update()
{
for (var iterator = 0; iterator < PhysicsEntities.Count; iterator++)
{
for (var index = iterator + 1; index < PhysicsEntities.Count; index++)
{
if (!Collision.ResolveCollision(PhysicsEntities[iterator],
PhysicsEntities[index], Detection)) continue;
PhysicsEntities[iterator].Update();
PhysicsEntities[iterator].Collided = true;
PhysicsEntities[index].Update();
PhysicsEntities[index].Collided = true;
}
}
foreach (var entity in PhysicsEntities)
{
entity.Update(velocity: true);
entity.Collided = false;
}
}
}
以下是实体的更新功能:
public void Update(bool velocity = false)
{
if(!Movable) return;
if (!Collided)
{
var moveX = Velocity.X / Universe.UpdateInterval;
var moveY = Velocity.Y / Universe.UpdateInterval;
Position.Move(moveX, moveY);
BoundingBox.Move(moveX, moveY);
}
if(velocity) UniversalForces();
}
private void UniversalForces()
{
Velocity.Scale(1 - Universe.Friction);
Velocity.Add(Universe.GravityMag, Universe.GravityDir);
}
最后,这是一个模拟对象卡住的图像。正如你所看到的,只是边缘被卡住了:
答案 0 :(得分:1)
快速解决方案是将两个对象移回到前一个tic的位置,并且导致碰撞的任何其他对象也会向后移动。它有效,但它看起来很乱,并且导致一些看起来非常糟糕的行为 - 像直接推到墙上的东西会留下一个空隙,但是朝墙壁倾斜会留下较小的间隙。非常凌乱。
更好的解决方案是沿着负速度矢量将两个物体向后移动足够远,使它们不再接触。通常一些点积数学可以为你提供你需要的东西,虽然向后迭代可以工作(慢)。
长话短说,不要让对象重叠。在它发生之前要小心处理它,避免卡住抖动,不能移动东西等等。
答案 1 :(得分:0)
当一个物体与另一个物体碰撞时,让它回溯它自己的运动矢量,使两个物体的质心之间的距离等于两个半径。如果它是一个圆圈,它就可以工作 - 如果它是一个复杂的多边形,你真的需要进行边缘碰撞检测而不是边界球形检测。如果边界球碰撞,则转移到复杂的边缘检测。最后诀窍是一样的;检查碰撞,然后备份运动矢量,直到找到确切的(或几乎精确的)碰撞点。
答案 2 :(得分:0)
我能够用人们提出的建议来弄明白。我做的一些更改包括每次更新时每个对象仅与任何其他对象碰撞一次,并在碰撞后移动对象直到它不再发生碰撞。这是我过去常用的代码,随时可以在任何项目中使用它,如果您对此有任何疑问,请告诉我。
public static void Update()
{
foreach (var a in PhysicsEntities)
{
foreach (var b in PhysicsEntities)
{
if (a.Equals(b) ||
!Collision.ResolveCollision(a, b, Detection) || b.Collided) continue;
while (Detection == Detection.BoundingBox ?
Collision.BoundingBox(a, b) :
Collision.PixelPerfect(a, b))
{
const float moveBy = .5F;
var moveX = a.Position.X > b.Position.X ? moveBy : -moveBy;
var moveY = a.Position.Y > b.Position.Y ? moveBy : -moveBy;
if (a.Movable)
{
a.Move(moveX, moveY);
a.Velocity.Scale(-1);
}
else if (b.Movable)
{
b.Move(moveX * -1, moveY * -1);
b.Velocity.Scale(-1);
}
}
a.Update();
b.Update();
a.Collided = a.Movable;
}
}
foreach (var entity in PhysicsEntities)
{
entity.Update(velocity: true);
entity.Collided = false;
}
}