推还是拉?将按键转变为游戏中车辆的速度
我应该在按下按键时将按键按下到车辆上,还是应该从引擎上拉下按下的按键?
我有一个车辆对象,该对象具有位置,速度和加速成员(除其他外)以及一种更新方法,在此过程中,该对象根据其速度更新其位置,并根据其加速度更新其速度。
我有一个包含游戏循环的游戏对象,该循环调用车辆上的update方法。
如果玩家使用箭头键控制车辆,是否应该通过按键设置加速(推)并释放按键来清除速度,还是应该问游戏引擎是否按下了加速键(拉)?我认为按一下将意味着键盘控制模块需要了解车辆,而按一下将意味着车辆需要了解特定的键盘控制。
我认为一个相关的问题应该是这样的:应该让所有对象都知道所有其他对象,还是应该有严格的层次结构,以便对象可以向树上的其他对象询问事物/将事情告诉其他对象(而不是向下)(反之亦然) )?
解决方案
我们应该尝试遵循"订阅/观察者"模式。
我们将所有关键捕获代码放入一个单例InputManager中,然后将每个需要对输入寄存器作出反应的对象与管理器一起放入。
管理器保存已订阅对象的列表,并在按下/按下键时将事件发送给它们。
只是不要忘记在对象被删除或者"失去焦点"时退订。
这避免了轮询问题。
很少有需要轮询解决方案的例外。
没有对游戏引擎如何工作的深入了解,很难回答这个问题。话虽这么说,我会刺中它。 "按下键盘按键"方法对我来说就像是"事件"或者"回调"策略。我们可以在某个地方定义一个类似于def handle_key_event(name_of_key):
的函数,该函数会在发生按键事件时被调用。这样做的好处是,从可读性的角度,我们可以确切地知道关键事件的处理位置。不利的一面是,每次按键都需要视为原子操作。如果我们需要在其他按键的状态上保留许多状态变量来确定每次按下时要做什么,则可能会有些混乱。
另一方面,如果我们按下按键,则会在捕获按键时引入固有的延迟。我们捕获关键事件的速度不会超过滴答率/帧速率。如果游戏运行良好且快速,这很好,但是当帧速率降低时,我们不希望UI变得跳动/缓慢。
我想这只是值得深思的。首先,选择一个策略并坚持下去。例如,如果键盘事件是回调,则不要对鼠标事件使用"拉"方法。在IMO中,一致性比正确性更重要。
IMO,车辆对键盘,鼠标或者游戏手柄一无所知。输入处理代码也不应该对车辆有任何了解。输入处理代码应读取每个玩家的输入,并将其转换为针对其上下文的某种指令。例如,如果玩家正在驾驶汽车,则他的指令可能包括方向盘旋转,加速度和制动值。当玩家驾驶飞机时,可能需要俯仰,偏航等。
通过将游戏手柄的输入(或者其他任何东西)转换为适当的指令类型,可以使输入机制与游戏逻辑脱钩。这种去耦级别可能会发生的一件事就是根据网络输入创建一个" CarInstruction"。
@Joel:我同意车辆不应该了解特定的硬件控制,输入处理代码也不应该对车辆有所了解。应该有一些从钥匙到车辆的中间类。感谢贡献!
我们要轮询:
void UpdateVehicleFromInput() { if (InputSystem()->IsKeyDown(key)) DoSomething(); }
当然,这是"在更新循环中某个适合我们设计的地方"。如果我们想将该特定场所称为"输入系统的一部分"或者"游戏逻辑的一部分"或者其他任何东西,请自行淘汰。
这样,我们就知道为什么要执行某项操作(使键处于按下状态),可以微调条件,知道要执行一次或者完全一次(并且可以不进行调整而更改它,尤其是在车辆没有响应的情况下)。 t存在),并且我们知道自己在做某事(在说之前或者之后,对损害做出响应,对粒子效果进行定位,或者其他人知道什么)。
如果我们确实在进行跨平台开发,则抽象输入系统可能是有效的。对于休闲开发,这是非常不必要的(但是当我们用尽游戏设计构想来实现时,这会带来有趣的技术干扰)。
与非理性的普遍看法相反,民意测验没有任何不利之处。处理器每秒执行> 1B的操作,如果一个帧无关紧要(几乎唯一相关的cpu操作是N ^ 2,其中N> 100,并吹动二级缓存,当然还要忙于等待磁盘访问)。轮询输入为O(1)。