基于组件的设计中的输入处理


12

我知道这个问题已经问过几次了,但是我仍然不确定如何在基于组件的引擎中实现输入处理。

我使用的基于组件的设计基于T = Machine的博客系列以及Artemis(其中实体只是id)。

实现输入处理时,我有三个主要想法:

  1. 输入组件将保存其感兴趣的事件。输入系统会将键和鼠标事件转换为游戏事件,并使用输入组件在实体之间循环,如果它们对事件感兴趣,则输入系统将采取适当的措施。该动作将被硬编码到输入系统。
  2. 没有输入组件。您可以将具有特定事件的实体注册到输入系统。输入系统然后将消息(具有实体ID和事件类型)发送给其他系统,以便它们可以采取适当的措施。或与第一种情况一样,这些动作将被硬编码到输入系统中。
  3. 与第一种方法类似,该组件将包含事件到函数(即std::map<std::function>)的映射,而不是对输入系统的动作进行硬编码,输入将调用该函数。这具有能够将同一事件耦合到不同动作的附加效果。

您会建议上述任何一种方法,还是对我实现灵活的输入处理系统有任何建议?另外,我还不熟悉多线程,但是也欢迎任何使实现线程友好的建议。

注意:我希望实现能够满足的另一个要求是,我能够将相同的输入传递给许多实体,例如,同时移动相机实体和播放器。


2
通常(当摄像机跟随播放器时),您不想在摄像机中接收输入,而是让摄像机检查播放器的位置并跟随它。
路加B.13年

1
摄像机是跟随玩家还是“自己”,从概念上讲并不重要。但是,我不确定在不违反设计原则的情况下如何在基于组件的设计中实现您的建议。
Grieverheart

1
@Luke B .:经过深思熟虑,我发现您也可以将相机作为一个单独的类,将指针指向要遵循的实体。
Grieverheart

Answers:


8

我认为,就像我对组件系统中材料的回答一样,您遇到了一个问题,您试图将所有内容都推入“组件”中。您不需要这样做,这样做可能是通过尝试将一堆方形钉插入圆孔中来创建一个非常麻烦的界面。

听起来您已经有了一个处理从播放器获取输入的系统。我选择一种方法,然后将该输入转换为动作(“向前移动”或“向后移动”)或事件,然后将其分配给感兴趣的各方。过去,我不允许组件为这些事件注册自己,而是选择一种方法,在这种方法中,更高级别的系统明确选择了“受控实体”。但是,如果您愿意,也可以通过其他方式工作,特别是如果您要重复使用相同的消息来执行输入未直接刺激的操作时。

不过,我不一定建议通过让相机实体和玩家实体都响应“向前移动”(等等)消息来实现相机跟随行为。这在两个物体之间建立了极其僵化的连接,这可能会使玩家感觉不佳,并且还使得处理诸如当玩家向左或向右旋转时使相机绕着玩家旋转的事情变得有些棘手:您拥有一个实体假设“从左旋转”已从属玩家,从而做出响应,但这意味着如果没有从动,它将无法正确响应...除非您引入该概念作为可以检查的状态。而且,如果要执行此操作,则还可以实施一个适当的系统来将两个物理对象捆绑在一起,并带有适当的弹性可调整项,等等。

关于多线程,我真的没有必要在这里使用它,因为它可能导致比其价值更大的复杂性,并且您正在处理一个固有的串行问题,因此您只需要涉及很多线程即可。同步原语。


我对问题提出了一些想法,并准备自己回答。我还得出这样的结论:我应该最好将输入处理与EC系统解耦,因此很高兴看到这一点。我如何做到这一点是通过使用信号以及将多个实体与事件类型相关联的能力。我也决定取消相机的耦合,尽管这实际上不是必需的,并且将其作为一个实体同样可行。我认为,当仍然是EC的新手时,您真的必须考虑将某个组件或实体制成的好处。
Grieverheart

4

我的经验可能带有偏见,但在多平台项目中,输入设备不会直接暴露给实体系统。

输入设备由较低级别的系统处理,该系统从按键,按钮,轴,鼠标,触摸表面,加速度计接收事件。

然后,这些事件通过上下文相关意图生成器层发送。

每个生成器都会注册其功能相关的组件,实体和系统的状态更改。

然后,这些生成器将消息/意图发送到路由到意图系统(在该意图系统中实体具有组件)或直接路由到正确的组件。

这样,您可以简单地依靠“始终”具有相同的输入,即JUMP_INTENT(1),JUMP_INTENT(0),AIM_INTENT(1)...

并且所有“脏”平台相关的输入工作都将保留在您的实体系统之外。


关于相机,如果要在播放器中移动相机,可以注册自己的意图组件并听取要发送的意图。

否则,如果跟随玩家,则永远不要听目的地为玩家的输入。它应该收听播放器发出的状态更改(ENTITY_MOVED(transform))...并相应地移动。如果您使用物理系统,甚至可以使用各种关节之一将相机连接到播放器。


土狼,谢谢您的回答。我也在这里阅读了您的其他文章。我最大的担心不是如何抽象输入。我已经有一个较低级别的构造来处理按键之类的操作,并且再增加一个间接级别并不难。我的问题是处理例如您的意图系统生成的事件。如果我理解正确,则您的方法中根本没有输入组件。您如何知道哪些实体需要输入以及如何处理?您能否举一些更具体的例子?
Grieverheart

2

InputComponent有什么好处?当然,决定执行操作的实体是输入命令的特权。最经典的例子就是让玩家跳起来。为什么不让每个跳转实体查找标记为“玩家”的实体并执行必要的逻辑呢?

Action jump = () =>
{
    entities["player"].Transform.Velocity.Y += 5;
};

来自OP的另一个示例:

Action moveRight = () =>
{
    foreach (var entity in entities.Tagged("player", "camera"))
        entity.Transform.Position.X += 5;
};
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.