如何在基于组件的游戏中正确处理碰撞?


11

在围绕组件设计的游戏中,尝试绕过正确处理碰撞的方法。

我看到许多示例PhysicsComponent在实体的组件列表中添加了某种示例,但实际的实现使我感到困惑。

为了PhysicsComponent使它起作用,需要访问周围的环境。这对我来说没有直觉。组件不应该不仅意识到其容器(实体),还没有意识到其容器的容器(世界)吗?

对我来说,听起来好像关卡或场景应该维护这些实体的列表,并且每次游戏更新都会遍历这些实体以确定哪个碰撞。

我的问题是,首先,这是否是好的设计,其次,如何确定哪些实体会发生冲突。我想实体实体可以实现一个空的IRigidBody接口,以便该级别可以确定列表中的哪些实体支持冲突。但这会破坏组件设计吗?

相反,它们应该包含一个空的RigidBody成分吗?实际上,这可能会更好,因为它可能并不总是空的,而且这种方法更适合未来。唯一的问题是复杂性。场景不仅必须遍历每个实体,还必须遍历每个实体的组件,以确定它是否具有此RigidBody组件。

第三,当它们确实发生碰撞时,应该以某种方式告知两个实体,我也不确定如何做到这一点。

假设两个实体都包含一个HealthComponent,并且当它们碰撞时,两个实体的健康状况都会降低一些任意值5。我想当场景中检测到两个实体之间发生碰撞时,要负责处理此问题?

但是,现场是否要承担太多责任?当场景负责实体不应该访问的许多事物时,我可以看到这种情况可能会变得一发不可收拾并且变得笨拙。

编辑:问题已更新,具有更多详细信息。



安德鲁(Andrew)的链接答案,詹姆斯(James)的答案和尼克·威吉尔(Nick Wiggill)的答案均应+1。将组件更多地视为数据,而不是具有数据和方法的典型类(不是它们没有方法,但不应赋予他们太多责任)。查看Artemis组件系统(piemaster.net/2011/07/entity-component-artemis),了解一个好的组件框架的示例。
michael.bartnett

Answers:


5

老实说,从组件设计的角度来看,除非有必要,否则我的组件彼此之间并不了解(这非常少见)。即使那样,我通常还是希望组件与所述组件的某个管理系统对话,而不是直接与组件对话。(脚本接口看起来像它的对象到对象,但是它不在实际的引擎中,呵呵)。

为此,我将支持您最初所说的内容,并使用存在于需要测试对象碰撞的位置的物理组件。现在,很明显,这些对象可能必须在解决冲突时通知其他组件自己,但是,如上所述,在这里,我更喜欢事件本身只是通过另一个接口(通过管理器或事件消息传递系统,通过另一个接口)发送给这些对象。您有其中之一)。

我认为您处在正确的轨道上,只是需要更多的“是的,听起来很正确”所以。.是的,这听起来很正确。

希望这可以帮助!


3

通常,游戏引擎使用第三方库来检测实体之间的碰撞。在这种情况下,可以将具有PhysicsComponent的实体创建或注册到“物理”世界中。并且每当它检测到两个实体(A和B)之间发生冲突时,通常都会调用对实体A的回调,以通知其已与实体B发生冲突,对于实体B则相同,从而通知其已与实体A发生冲突。

对于2D,Box2D是一个著名的免费物理学库。同样值得一看的花栗鼠。对于3D,Bullet是免费的(可能是您找到的最好的免费软件)。Havok和PhysX因在许多三重A游戏中使用而闻名。


2

您遇到的问题是看到碰撞检测(这是您需要一个具有物理成分的实体引用另一个实体的唯一原因)通常是在游戏循环中直接完成,或者是通过一个可以完成此任务的辅助函数/类。几周前,对某人的回答基于相似的理由谈论实体移除,并牢记如果碰撞导致您的一个实体被破坏,那么在给定的背景下,相同的答案将与您非常相关,因为“更高的力量”仍然需要管理尸体的清理……可以这么说。

通常,仅在实体之间进行任何上述操作都是不可行的。在坚实的体系结构中,几乎总是存在此类事情的代理,无论是通过直接管理(例如冲突检测)还是通过事件分派(例如)。一个播放器消息传递系统,客户端消息传递管理器在其中侦听从播放器分发的消息,然后将其发送到服务器,以重新广播给所有人。


2

我现在在一个项目中面临与您完全相同的问题。我决定解决这个问题的方法是拥有一个“ ColliderComponent”,它可以从物理引擎中固定身体。实体在外部定义(在运行时加载的形状定义),然后添加到物理世界它们所属的游戏实体中。

我正在使用Box2D,您可以在其中附加“碰撞侦听器”,该碰撞侦听器会通知您。由于我在主体用户数据中添加了指向我的“ ColliderComponent”的指针,因此我可以获得两个碰撞的ColliderComponents。

因此,发生碰撞时发生的事情如下:碰撞的一部分ColliderComponents将向其所有者对象(游戏实体)发送一条消息,该所有者对象又将该消息广播到其所有组件。

然后,每个组件都可以对该消息做出反应,因此您的“健康组件”可以从健康中删除5点,依此类推。


+1:我使用的是非常相似的方法。您如何根据碰撞的实体类型确定造成的损害程度?

@Den我根据发生的冲突发送不同的消息(或消息数据)。这对我来说很好,因为我没有很多不同的情况要处理。
bummzack,2011年

0

创建一个知道碰撞“世界”的碰撞系统。然后,在您的碰撞组件中,告诉碰撞系统将射线从点A投射到点B,并响应它是否碰撞。

祝好运。我发现碰撞系统是游戏引擎中较为繁琐的部分之一。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.