2D游戏中的表面检测?

时间:2010-06-04 11:18:02

标签: xna 2d collision

我正在开发2D平台游戏,我想知道实现Surface(碰撞)检测的最佳(性能方面)方法。

到目前为止,我正在考虑构建一个由行列表构成的关卡对象列表,并沿着这些线绘制切片。

alt text http://img375.imageshack.us/img375/1704/lines.png

我认为每个物体都拥有他走过的表面的ID,以便在上/下坡时轻松操纵他的y位置。

这样的事情:

//Player/MovableObject class
MoveLeft()
{
    this.Position.Y = Helper.GetSurfaceById(this.SurfaceId).GetYWhenXIs(this.Position.X)
}

所以我用来检测“在表面上摔跤/走路”的逻辑是一个简单的点(玩家的小腿) - 接触线(表面)检查 (有一些安全近似值 - 让我们说在线上1-2个像素。)

这种做法好吗? 我一直难以找到解决这个问题的阅读材料,所以请随意删除链接/建议。

8 个答案:

答案 0 :(得分:3)

长期使用基于多边形的2D平台游戏,让我给你一些建议:

制作基于图块的平台游戏。

现在,直接回答有关碰撞检测的问题:

你需要让你的世界几何体“坚固”(你可以让你的玩家对象成为一个点,但让它更坚固更好)。我的意思是“坚实” - 您需要检测玩家对象是否相交您的世界几何体。

我已经尝试过“玩家是否越过了这个世界几何体的边缘”并且在实践中不起作用(即使它似乎在纸上工作 - 浮点精度问题不会是你唯一的问题)。

网上有很多关于如何在各种形状之间进行交叉测试的说明。如果您刚刚开始我建议使用轴对齐边界框(AABB)。

非常多,很多很多比使用任意几何体更容易制作基于图块的平台游戏。所以从瓦片开始,检测与AABB的交叉点,然后一旦你开始工作,你可以添加其他形状(如斜坡)。

检测到交叉路口后,您必须执行碰撞响应。同样,基于磁贴的平台游戏最容易 - 只需将玩家移动到碰撞的磁贴外面(你移动到它上面,还是移到侧面? - 它将取决于碰撞 - 我将离开如何做到这一点是一个运动)。

(PS:你可以用方形瓷砖获得极好的结果 - 例如,看看Knytt Stories。)

答案 1 :(得分:1)

查看XNA的Platformer Starter Kit项目是如何完成的。基本上,瓷砖有枚举用于确定瓷砖是否可通过,无法通过等,然后在您的水平上GetBounds瓷砖,然后检查与玩家的交叉点并确定要做什么。

答案 2 :(得分:1)

我在处理2D碰撞检测方面度过了愉快的时光。如果你事先没有计划好,看起来像一个简单的问题很容易成为一场噩梦。

在OO意义上执行此操作的最佳方法是制作通用对象,例如classMapObject。这有一个位置坐标和斜率。从这里,你可以扩展它以包括其他形状等。

由此,让我们处理与Solid对象的碰撞。假设只是一个区块,比如32x32,,您可以从左侧,右侧,顶部和底部点击。或者,根据您的编码方式,同时从顶部和左侧点击它。那么你如何确定角色的走向?例如,如果角色从顶部撞击块,站立,编码不正确,则可能会无意中将角色推到一边。

那么,你应该怎么做?我为2D游戏做了什么,在决定如何对碰撞做出反应之前,我查看了此人的先前定位。如果角色的Y位置+高度在块上方并向西移动,那么我将首先检查顶部碰撞然后检查左碰撞。但是,如果角色的Y位置+高度低于块的顶部,我会检查左碰撞。

现在假设您有一个倾斜的区块。该块宽32像素,在x = 32时高32像素,在x = 0时高0像素。 有了这个,你必须假设角色只能从顶部撞到并碰撞这个块。使用这个块,你可以返回一个FALSE碰撞,如果它是左/右/底碰撞,但如果它是从顶部发生的碰撞,你可以说明如果角色处于X = 0,则返回碰撞点Y = 0。如果X = 16,Y = 16等。

当然,这都是相对的。您将检查多个块,因此您应该做的是将所有可能的更改存储到角色的方向上的临时变量中。因此,如果角色在X方向上与块重叠5,则从该变量中减去5。累计X和Y方向的所有可能变化,将它们应用于角色的当前位置,并将它们重置为0以用于下一帧。

祝你好运。我可以在以后提供更多样本,但我在我的Mac上(我的代码在WinPC上)这是经典Mega Man游戏IIRC中使用的相同类型的碰撞检测。以下是有关此内容的视频:http://www.youtube.com/watch?v=uKQM8vCNUTM

答案 3 :(得分:0)

您可以尝试使用物理引擎之一,例如Box2DChipmunk。他们拥有先进的碰撞检测系统和许多不同的奖金。当然,它们不会加速你的游戏,但它们适用于任何现代设备上的大多数游戏

答案 4 :(得分:0)

创建自己的碰撞检测算法并不容易。困难的一个简单例子是:如果你的角色以足够高的速度移动,在两帧之间,它将从一条线的一侧移动到另一条线,该怎么办?那么你的算法将没有时间在其间运行,并且永远不会检测到碰撞。

我同意Tiendil:使用图书馆!

答案 5 :(得分:0)

我建议Farseer Physics。它是一个伟大而强大的物理引擎,应该能够照顾你需要的任何东西!

答案 6 :(得分:0)

我会这样做:

  1. 严格没有碰撞线。只有实心形状(盒子和三角形,可能是球体)
  2. 2D BSP,用于存储所有级别形状的2D分区,或“扫描和修剪”算法。每个都将是非常强大的。扫描和修剪,结合插入排序,可以轻松地成千上万的潜在碰撞对象(如果不是数十万),并且2D空间分区将允许根据需要快速获得所有附近可能碰撞的形状。

使对象在曲面上行走的最简单方法是使每帧落下几个像素,然后获取对象碰撞的曲面列表,并将对象移动到曲面法线方向。在2d它是垂直的。这种方法会导致物体在非水平表面上向下滑动,但您可以通过略微改变法线来解决这个问题。 此外,您必须每帧运行几次碰撞检测和“推送对象”例程,而不是一次。这是为了处理对象在堆中的情况,或者它们是否接触多个表面。

答案 7 :(得分:0)

我使用了一种有限的碰撞检测方法,这种方法在不同的基础上工作,所以我会把它扔到这里以防它有用:

黑白的次要图像。不通的像素是白色的。构造一个字符的掩码,它只是当前设置的任何像素。为了评估预期的移动,从次级图像中读取该掩模的像素,看看是否有白色的像素返回。

要检测与其他对象的碰撞,请使用相同的方法,但使用足够的深度来覆盖所有可能的对象,而不是布尔值。将每个对象完全以其对象编号的“颜色”绘制到辅助对象。当您通过蒙版读取并获得非零像素时,“颜色”是您点击的对象编号。

这解决了O(n)时间内所有可能的碰撞,而不是计算相互作用的O(n ^ 2)。