我以及如何将输入和游戏对象的关注点分开?


20

在每个游戏中,开发人员都必须以某种方式处理输入,可能是简单的键盘和鼠标事件,触摸事件或加速度计输入。该输入直接间接影响游戏中的对象。有时相同的输入会影响不同的对象。现在,我一直在考虑如何对此建模。我的看法有两种不同的方法。

  • 让游戏对象自己处理它,订阅事件并调用它自己的方法。这具有使游戏对象自己决定哪些输入导致哪个动作的优点。缺点似乎是输入代码与“核心”游戏对象代码混在一起。而且,游戏对象不知道游戏其余部分的状态,并且有时可能不应对输入事件起作用。这似乎不正确。

  • 让一般的输入控制器负责所有输入,并决定谁来处理什么事件。这似乎可以更好地分离关注点,但是紧密地将输入控制器类与游戏对象耦合在一起。它需要以某种方式知道谁想要接收哪个事件和哪个状态。这似乎也不正确。

您正在使用什么策略来解决这个问题?

Answers:


7

我建议将输入事件与游戏对象分开,以便您可以快速更改/升级输入方法,而不必编辑和调试10个对象类。例如,从仅键盘控件切换到鼠标+键盘,或者只是重新分配键。

与其将输入紧密耦合到各个游戏对象上,不如对游戏对象上的每个唯一输入信号仅调用一种方法,并让其确定执行方法。

使用输入控制器来跟踪输入状态:

Up press event   -> dir = up
Down press event -> dir = down

每当输入状态更改时,请评估是否可以修改游戏对象:

set dir  ->  if gamestate != paused && battlemode == false
             ->  character.changeDir(dir);

在游戏对象上实现常规方法,可以根据需要由输入控制器或其他游戏对象调用这些方法:

changeDir (dir)
setSpeed (walk/run)

7

我建议使用MVC方法。在MVC中,游戏对象只需要担心对游戏系统进行建模,并提供诸如move_left的高级界面。然后有一个控制器对象,它担心将输入映射到模型调用。它不仅允许轻松更改控件,而且还为AI提供了一个良好的界面,它们只是另一个控制器。

在第二个选项中,我将输入控制器分为两部分,一个部分处理实际的设备触摸,键盘,加速,无论您要扔给它什么,都要将它们映射到一组通用输入中。然后有第二部分将通用输入映射到游戏特定输入。假设键盘上的箭头映射到input1,然后触摸触摸屏的顶部也映射到input1,现在编写第二部分,将输入1映射为跳转。现在,您可以将任何IO设备以及存储的回放或AI输入映射到此通用输入系统,并具有一个特定于游戏的小部件,可以将input1的含义加载到模型中。


5
在这个网站的其他地方,有很多关于为什么MVC通常不适用于游戏模式的讨论。Stonemetal描述的甚至不是MVC,而仅仅是抽象;“使用MVC”不是答案,因为MVC是对整个体系结构类的描述,而不是分离关注点的特定方法(也不是解决问题的唯一方法)。

2
MVC应该给他A)维基百科上的文章,以供读者阅读; B)关于如何使用已证明有效的解决方案的多种变化; C)我提到了在模型公开高级界面的情况下的设置方法。控制器将低级输入(真实或合成)映射到高级操作,并直接操纵模型而不是某些事件系统。
stonemetal

1

我建议让您的游戏(模型)定义一个可能的输入事件的列表(实现为具有基本接口的枚举或对象)。世事如MovingRightStartedMovingRightStoppedFiredWeapon1Escape,等...

游戏定义了一个数据结构(例如a queue),您的输入代码(Controller)可以用输入事件填充。

然后,您的游戏可以轮询数据结构以获取输入事件。

这样,您可以插入不同种类的控制器来馈送模型:

  • 仅键盘
  • 键盘+鼠标
  • 游戏杆
  • 触摸屏
  • 人工智能

您只需让他们将输入事件推送到模型。


我想我理解您的意思,除了您选择将queueas作为数据类型来存储此内容外。你能解释为什么吗?
罗伯特·马萨

在模型的2个输入事件轮询之间,控制器可能已经推送了多个动作事件,因此保持用户输入的顺序很重要。这就是为什么我选择FIFO数据结构的原因。实际上,您可能还需要指定输入发生的确切时间。
Splo
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.