好的,这段代码我需要一些帮助。
前言
下面的代码描述了一个有限状态机(FSM)的实现,由于我使用的是Unity,这让我可以将我的状态/动作和决策创建为资产。
状态
[CreateAssetMenu(menuName = "PluggableAI/States")]public class State : ScriptableObject{ public Action[] actions; public Transition[] transitions; public Color sceneGizmoColor = Color.grey; public EnumProfession Profession; /// <summary> /// 更新当前状态 /// </summary> /// <param name="controller"></param> public void UpdateState(StateController controller) { DoActions(controller); CheckTransitions(controller); } /// <summary> /// 执行每个动作 /// </summary> /// <param name="controller"></param> private void DoActions(StateController controller) { for (int i = 0; i < actions.Length; i++) { actions[i].Act(controller); } } /// <summary> /// 检查需要进入的转换 /// </summary> /// <param name="controller"></param> private void CheckTransitions(StateController controller) { for (int i = 0; i < transitions.Length; i++) { bool decisionSucceeded = transitions[i].decision.Decide(controller); if (decisionSucceeded) { controller.TransitionToState(transitions[i].trueState); } else { controller.TransitionToState(transitions[i].falseState); } } }}
动作
public abstract class Action : ScriptableObject{ public abstract void Act(StateController controller);}
决策
public abstract class Decision : ScriptableObject{ public abstract bool Decide (StateController controller);}
转换
public class Transition{ public Decision decision; public State trueState; public State falseState;}
为了控制状态及其转换,我创建了以下类 StateController
:
public class StateController : MonoBehaviour{ public State CurrentState; public State RemainState; public NpcHuman NpcHuman; /// <summary> /// 游戏开始时 /// </summary> private void Awake() { if (NpcHuman == null) { NpcHuman = GetComponent<NpcHuman>(); } } /// <summary> /// 每帧更新 /// </summary> void Update() { CurrentState.UpdateState(this); } /// <summary> /// 转换到下一个状态 /// </summary> /// <param name="nextState"></param> public void TransitionToState(State nextState) { if (nextState != RemainState) { CurrentState = nextState; onExitState(); } } /// <summary> /// 每次状态退出时调用 /// </summary> private void onExitState() { } public void ForceChangeState(State state) { CurrentState = state; }}
现在,我已经根据它们的类型识别了我游戏中不同类型的AI:
NPC类型
Villager - 人形Soldier - 人形Archer - 人形Catapult (车辆) - 通用Spirits - 通用Animals - 通用
现在,让我们从人形角色开始,为此我创建了以下关系:
如你所见,每个类都派生自 NpcHumanoid
类 编辑 – 图表中的命名有误,抱歉
如果你仔细观察,你会发现这段代码存在一个问题。
我现在主要的问题是引用不同类型的对象。
所以我的问题是,最好的方法是什么?
我应该为状态机创建一个抽象类,然后创建它的子类,这些子类可以保存对它所控制的AI/NPC类型的引用。那样的话,我的状态该如何处理?因为它们都接受一个StateController作为参数,我将不得不一直将statecontroller转换为使用该状态的类型(这看起来很糟糕且混乱)。
也可能有我没有看到的解决方案,我很乐意听取你们的意见。
回答:
Unity使用基于组件的方法来组织游戏逻辑。所以我认为最好的方法是使用组件而不是常规的OOP方法来处理你的NPC 类型。
只需将不同类型的NPC视为带有不同组件的GameObject。例如,
Villager.cs
class Villager: MonoBehaviour{ public float Fatigue; public int Carrying;}
你可以创建一个 NPCFactory
来创建不同的NPC。
class NPCFactory{ public GameObject CreateNPC(NPCType npcType) { GameObject obj = new GameObject(); obj.AddComponent<StateController>(); switch(npcType) { case NPCType.Villager: obj.AddComponent<Villager>(); break; //case .... } return obj; }}
然后你可以通过操作它们上的 StateController
来处理NPC的状态。