如何处理复杂逻辑 – 有限状态机 (FSM)
您可能已经跟随一些初学者教程,并决定基于您学到的游戏机制创建自己的项目。但是,一旦您添加了更复杂的动作,很快就会迷失在相互嵌套的条件中,这导致了很难找到的错误。最终,您可能放弃了这个项目。
您在互联网上找到的大多数教程(与游戏引擎无关)通常只是尝试展示一种实现特定教程目标的方式,尽可能少地分散注意力。不幸的是,这通常导致的代码不关心可扩展性。
这个教程将向您展示如何以一种结构化的方式组织您的项目,以封装您的玩家(敌人或其他动态对象)的逻辑。
什么是状态机?
状态机将对象的逻辑分为一组固定的明确定义的状态,这些状态彼此独立地运行。每个状态只包含适用于其自身的逻辑。例如,当玩家处于“下落”状态时,您不必检查左右移动按钮,也不必检查跳跃按钮,因为您的脚下没有地面。当满足特定条件时,玩家状态会转换为另一个状态。
所以想象一下,玩家处于“下落”状态。在空中时,它不应该能执行任何操作。它只是被重力 passively 往下拉。为了转变成另一种状态,必须满足某些条件。在“下落”状态下,此条件将是“与地面碰撞”。当这种情况发生时,游戏将把状态从“下落”改变为“空闲”。现在,在“空闲”状态下,游戏会不断检查是否按下移动按钮,这将导致玩家状态从“空闲”转换为“行走”。在“行走”状态下,玩家会持续移动,直到发生其他事件(例如释放移动按钮)。您明白了吗?
入门
让我们从“ 下载资产开始。切换到事件编辑器(“main”场景)并创建这些外部事件“playerstateinit”,“playerstatefalling”,“playerstateidle”,“playerstatewalking”,“playerstatejumping”。在主场景的事件中,从右侧的下拉菜单中创建一个新的事件组。将其命名为“Player logic”。现在添加一个“在场景开始时”条件。添加一个子事件到条件,并通过“添加”/“其他”按钮链接外部事件表“playerstateinit”。对所有其他玩家状态执行相同操作。
注意:
相比于动画,我们可以在这里创建一个专门的场景变量“state”来控制玩家状态。这更加高级,但可以提供更好的灵活性。然而,这里介绍的方法有利于将逻辑与相应的动画捆绑在一起,使事件表中更加清晰简单。此外,您可以访问当前动画/状态的帧,并在动画的某个帧内触发一些逻辑。
调试信息
为了在玩游戏时了解玩家当前处于哪种状态,创建一个文本对象并将其命名为“debug_state”。将其添加到主场景中,并按照以下操作创建动作(带有一个空条件),以便在玩家头顶正上方显示当前玩家状态。每当某些功能不按预期工作时,我们将知道我们必须调查哪个状态以找到错误。
我们的第一个状态 “init”
打开外部状态“playerstateinit”。此状态用于在游戏启动时初始化我们的玩家对象。在“编辑事件时应如同事件在场景中被包含”字段中选择“main”场景。
由于我们已经在主场景事件表中设置了关于何时执行初始化状态代码的条件,因此我们可以在这里省略条件,只需添加动作。
首先,我们需要禁用平台器行为的默认控件,因为这些控件在使用状态机时会妨碍。接下来,将玩家精灵的动画设置为“下落”。因此,在游戏循环的下一次迭代中,将执行“下落”状态的事件。我们选择这里的下落状态,因为玩家被放在空中,最终会掉到地面,在那里我们可以转换为“空闲”状态。
您也可以使用此状态来(重新)设置玩家的生命值、弹药或其他东西。如果决定重新开始级别,可以始终返回“init”状态以重置玩家属性。
“下落” 状态
下落是所有状态中最普遍的状态。每当您不确定要转换为哪种状态时,“下落”状态通常是一个不错的选择,因为它最终将导致当玩家与物体碰撞时转换为另一种合理的状态。在下落时,玩家无法执行任何主动动作。他只会被他进入下落状态之前施加在他身上的力量被动影响。例如,如果在执行跳跃后进入下落状态,您仍会被 passively 移动到您跳跃的方向,但您不能再调整方向。(请参阅本教程底部的练习部分,以更改此行为)。因此,我们在此状态中所做的全部工作就是检查玩家是否与地板碰撞。如果是,则将玩家转换为“空闲”状态。# "空闲"状态
当面前的人不做任何操作时,就会触发空闲状态。换句话说,没有按键按下,玩家对象只是静止不动。就像“下落”状态一样,没有任何活动动作需要执行。我们只是检查让我们离开“空闲”状态的条件。首先,我们检查玩家是否在地板上。如果不是,则转换为下落状态。接下来,我们检查玩家是否按下左或右箭头键。如果是,我们转换为行走状态。最后但同样重要的是检查上箭头键,如果按下,则将玩家切换到跳跃状态。听起来合乎逻辑吧?
"行走"状态
在行走状态中,我们最终可以整合一些玩家执行的活动动作。由于我们只使用一个状态来向左行走和向右行走,因此我们首先必须确定玩家需要移动的方向。因此,我们再次检查按下的键,并在进入行走状态时将玩家的方向变量设置为相应方向。之后,只要玩家处于行走状态,我们会使玩家朝着那个方向移动。
现在玩家可以行走了,我们将再次遇到使他离开当前状态的条件。当我们正在行走时会发生什么?最明显的事情就是放开行走键。在这种情况下,我们将转换为“空闲”状态。如果我们走到当前平台的边缘,我们会转换为“下落”状态。如果按下跳跃键,则切换到跳跃状态。
"跳跃"状态
如您所料,我们进入状态后首先要执行的是触发跳跃动作。力量会被 passively 应用,因此一旦执行了跳跃,我们就不必再担心它了。像往常一样,我们需要做的最后一件事就是找到使我们转换到另一个状态的条件。在这种情况下,我们将检查玩家是不是在跳跃或下落。如果是这样,玩家将转换到“下落”状态。
这就是全部内容。
结论
我们现在将玩家逻辑分为五种不同的状态,每种状态只处理适用于它们的逻辑,而不多余。如果您希望玩家获得额外的能力,如飞行、潜水、死亡或被撞到墙上,只需创建一个新状态并在那里处理逻辑。
您可以在此处下载整个项目。
练习
- 您可能已经注意到,玩家在空中时的行为与激活的默认控件有点不同。这是因为我们目前在“下落”状态下没有主动输入。因此,您的任务是使玩家在下落状态时能够移动。检查是否按下移动键,并向玩家施加通常移动力的一半。