C# FSM for multiple NPC types

好的,这段代码我需要一些帮助。

前言

下面的代码描述了一个有限状态机(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 - 通用

现在,让我们从人形角色开始,为此我创建了以下关系:

enter image description here

如你所见,每个类都派生自 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的状态。

Related Posts

Keras Dense层输入未被展平

这是我的测试代码: from keras import…

无法将分类变量输入随机森林

我有10个分类变量和3个数值变量。我在分割后直接将它们…

如何在Keras中对每个输出应用Sigmoid函数?

这是我代码的一部分。 model = Sequenti…

如何选择类概率的最佳阈值?

我的神经网络输出是一个用于多标签分类的预测类概率表: …

在Keras中使用深度学习得到不同的结果

我按照一个教程使用Keras中的深度神经网络进行文本分…

‘MatMul’操作的输入’b’类型为float32,与参数’a’的类型float64不匹配

我写了一个简单的TensorFlow代码,但不断遇到T…

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注