实体系统中的多种运动源


9

我对实体系统这个概念还很陌生,已经阅读了很多东西(最有用的是这个很棒的博客这个答案)。

尽管我在理解如何通过不确定数量的源操纵对象的位置这样简单的事情上遇到了一些麻烦。

也就是说,我有我的实体,该实体具有职位组成部分。然后,我在游戏中发生了一些事件,告诉该实体在给定时间内移动给定距离。

这些事件可以随时发生,并且具有不同的位置和时间值。结果是将它们混合在一起。

在传统的OO解决方案中,我会有某种MoveBy类,其中包含距离/时间,以及在我的游戏对象类内部的数组。每帧,我都要遍历所有MoveBy,然后将其应用于该位置。如果a MoveBy已达到结束时间,请从阵列中将其删除。

对于实体系统,我对如何复制这种行为感到有些困惑。

如果一次只有一个,而不是能够将它们复合在一起,那将是相当简单的(我相信),并且看起来像这样:

PositionComponent 包含 x, y

MoveByComponent 包含 x, y, time

Entity同时具有a PositionComponent和aMoveByComponent

MoveBySystem查找具有这两个组成部分的实体,并将的值添加MoveByComponent到中PositionComponent。当time到达,它会从该实体的组件。

我对于在很多情况下如何做同样的事情有些困惑。

我最初的想法是我会:

PositionComponentMoveByComponent与上述相同

MoveByCollectionComponent其中包含MoveByComponents 的数组

MoveByCollectionSystem查找具有PositionComponent和的实体,并在MoveByCollectionComponent其中的MoveByComponents中进行迭代,并根据需要应用/删除。

我猜这是一个更普遍的问题,具有许多相同的组件,并且希望有一个相应的系统对每个组件起作用。我的实体将其组件包含在组件类型->组件的哈希中,因此每个实体严格只有一种特定类型的组件。

  1. 这是看待这个问题的正确方法吗?

  2. 实体是否应该始终始终只有一种给定类型的组件?


1
听起来有点像MoveBy功能只是一种速度?听起来您在正确的轨道上。对于第二个问题,实体/组件系统有很多不同的实现。在您链接的我的答案中描述的内容只有一个给定类型的内容。
MichaelHouse

有点,但区别在于该速度仅一次有效,另一次有效,并且许多速度可以一次组合在一起。我想我只需要放心,过去我对自己的游戏一直严格(肛门,几乎)面向对象的游戏-几年后,在同一项目上,这降低了我们的生产速度-这真是个陌生的领域;) 。顺便说一句,另一个帖子的答案很好,这有助于清理一些内容
Sticky

我这样做是这样的:我有PlayerInputComponent和AIInputComponent(或系统),它们会告诉MobileBehaviorComponent在键盘上单击或在AI上认为移动设备应移动到某个位置,MobileBehaviorComponent将存储它应移动到某个位置(它内部有FSM用于移动操作)某些系统会移动它。您的粒度太高了,使用诸如Transform,Model,Light,Mob之类的更高级别的组件,所有功能也都可以正常工作。同样,我也不需要删除组件-我认为它们更像是描述游戏对象的东西,因此它不能消失。
Kikaimaru 2012年

这个特定的MoveBy示例只是一个示例。问题更多是关于如何将这些东西复合在一起。如果我需要专门说“在5秒钟内移动x = 5和y = 6”“在10秒钟内移动x = 10 y = 2”,这是我的做法吗?
粘性

“复合在一起”是什么意思?喜欢增加速度吗?因此,如果您复利move x by 10 in 2 seconds并且move x by -10 in 2 seconds实体将完全静止不动?
Tom Dalling 2012年

Answers:


6

对于您的方案,我们通常向游戏对象添加三个组件:

  1. TransformComponent(位置,方向,比例)
  2. VelocityComponent(速度,方向)
  3. 控制器组件

当游戏对象需要某种类型的AI功能(例如沿您描述的路径移动)时,我们将AIController分配给它的组件列表。AIController实际上只不过是一步步包装行为树的包装器而已。行为树是我们设计要让游戏对象执行的实际功能的地方,例如:

BehaviorTree* tree(new SequentialNode());
tree->addChild(new MoveToNode(x,y,z));
tree->addChild(new WaitNode(30));
tree->addChild(new MoveToNode(a,b,c));
tree->addChild(new WaitNode(30));
gameObject->addComponent(new AIController(tree));

AI子系统管理AIController,以便子系统在控制器上打钩,从而依次控制“行为树”。MoveToNode()查看当前位置/方向,根据其构造函数参数计算要移动到的方向向量和速​​度,并在速度分量上设置值。运动系统负责读取具有值的运动分量并应用物理原理,从而相应地更新位置/方向。

上面的代码只是将游戏对象从生成位置移动到世界空间中的x,y,z,然后等待至少30秒,然后将游戏对象移动到位置a,b,c,然后再等待30秒。等待结束后,行为序列已完成,因此从头开始重复。

这使您可以轻松定义AI子系统中需要的所有AI功能,而对Entity子系统的影响最小。它还可以使您的实体系统组件列表保持精简,而又没有太多的粒度。


1

一种选择是将控制器添加到您的设计中。实体拥有代表位置的数据(在我的引擎中,它们也具有记住先前位置的数据,因此我可以知道速度矢量以及它们是否被移动或传送),但是它们对物理学一无所知AI。控制器移动实体,您可以有许多影响同一实体的控制器,也可以有一个影响各种实体的控制器。

例如:使用run()方法创建一个基本的Controller类,或者如果您不喜欢该名称,则调用它think(),update()或tick()。然后从中继承并创建一个MoveController,NPCController,PlayerInputController(用于播放器实体),PhysicController;然后实现run()方法。我会将您的MoveByComponent放在MoveController中,而不是在Entity中。

如果每个Controller拥有特定于实体的数据,则可以由每个实体实例化。它们可以销毁或重置,以备后用。您也可以使用控制器移动一组实体,例如在RTE游戏中,如果您需要将多个单位作为一个组移动,则每个单位都有一个控制器可能会损害游戏性能,那么您只需分配所有单位即可移至GroupController或LegionController,然后将其作为有组织的组的一部分移动。战斗时,如果游戏允许单个单位的行为,并且可能大多数游戏都这样做,则您必须切换到UnitController,但最好只在需要时才这样做,而不是从一开始就这样做。

在我正在开发的游戏中,我有一个MoveController可以沿着路径移动实体,每个NPC和玩家角色都有一个MoveController。有时会为玩家可以推动的盒子或石头创建一个盒子。PhysicController,只有一个实例,它将检查分配给它的所有实体的位置,如果某个实体与另一个分配的实体发生碰撞,则将计算两个实体的最终位置(实际上,它的作用还不止于此,但您可以理解)。NPCController是AI,每个NPC一个实例。它检查NPC的情况并确定要移动到的位置,然后将路径推到MoveController,该控制器实际上将NPC移动。控制器具有优先级,因此我可以提前确定其顺序,PhysicController是最后执行的控制器。

我主张使用控制器,但不是唯一的“正确”选项。例如,我记得Cafu引擎中的一个Entity接口,它在Entity本身中具有think()方法,该类的用户必须从Entity继承并实现think(),我还记得一个名为CompanyBot的派生类(示例随附)游戏)在该方法中进行碰撞检查,这就是所谓的“思考”,我们可以假设AI代码也应该存在。当NeoAxis引擎(我上次研究它)时,将AI和物理与实体分开。

我已经听过一个Controller模式。也许您应该搜索它,这可能与我在这里所说的不完全相同,但是听起来也不错。


这基本上就是我们现在已经拥有的OO设计。一个拥有衍生品(角色,怪物)等的实体,我一直带领我们的团队全职致力于这款游戏将近2年,并且每个人都随心所欲地改变事物,这变得非常可怕,可怕代码库-并且开始花费很长时间才能获得新功能。实体系统的想法似乎正是我要寻找的,因此,尽管您的答案不太相关,但是您应该自己阅读问题顶部的链接,看看它们是否可以帮助您:)
粘性

@Sticky我必须承认,由节点组成的节点系统加实体是一种巧妙的方式来表示所需的不同系统,这比我建议的控制器方法(这是一种不太发达的版本)更好。毕竟,您真的不需要我的回答。
Hatoru Hansou 2012年

别担心。面向对象的方法确实有其优势,但是事情变得丑陋,快速
粘性
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.