首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >多NPC类型的C#有限状态机

多NPC类型的C#有限状态机
EN

Stack Overflow用户
提问于 2018-03-05 00:19:28
回答 1查看 769关注 0票数 3

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

前言

下面的代码描述了FSM的一个实现,因为我现在使用的是统一,这允许我在我的州/行动和决策之外创建资产。

国家

代码语言:javascript
运行
复制
[CreateAssetMenu(menuName = "PluggableAI/States")]
public class State : ScriptableObject
{
    public Action[] actions;
    public Transition[] transitions;
    public Color sceneGizmoColor = Color.grey;
    public EnumProfession Profession;

    /// <summary>
    /// Updates current state
    /// </summary>
    /// <param name="controller"></param>
    public void UpdateState(StateController controller)
    {
        DoActions(controller);
        CheckTransitions(controller);
    }

    /// <summary>
    /// Does each action
    /// </summary>
    /// <param name="controller"></param>
    private void DoActions(StateController controller)
    {
        for (int i = 0; i < actions.Length; i++)
        {
            actions[i].Act(controller);
        }
    }

    /// <summary>
    /// Check which transition we have to ggo in
    /// </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);
            }
        }
    }
}

Action

代码语言:javascript
运行
复制
    public abstract class Action : ScriptableObject
{
    public abstract void Act(StateController controller);
}

决策

代码语言:javascript
运行
复制
public abstract class Decision : ScriptableObject
{
    public abstract bool Decide (StateController controller);
}  

跃迁

代码语言:javascript
运行
复制
public class Transition
{
    public Decision decision;
    public State trueState;
    public State falseState;
}

为了控制状态及其转换,我创建了以下类StateController

代码语言:javascript
运行
复制
    public class StateController : MonoBehaviour
{
    public State CurrentState;
    public State RemainState;
    public NpcHuman NpcHuman;

    /// <summary>
    /// When the game starts
    /// </summary>
    private void Awake()
    {
        if (NpcHuman == null)
        {
            NpcHuman = GetComponent<NpcHuman>();
        }
    }

    /// <summary>
    /// Updates every frame
    /// </summary>
    void Update()
    {
        CurrentState.UpdateState(this);
    }

    /// <summary>
    /// Transitions to next state
    /// </summary>
    /// <param name="nextState"></param>
    public void TransitionToState(State nextState)
    {
        if (nextState != RemainState)
        {
            CurrentState = nextState;
            onExitState();
        }
    }

    /// <summary>
    /// Is Called everytime a state exits
    /// </summary>
    private void onExitState()
    {
    }

    public void ForceChangeState(State state)
    {
        CurrentState = state;
    }
}

现在我所做的是,我已经确定了不同类型的人工智能在我的游戏中,取决于他们的类型:

鼻咽癌的

代码语言:javascript
运行
复制
Villager  - Humanoid

Soldier  - Humanoid

Archer - Humanoid

Catapult (vehicles)  - Generic

Spirits - Generic

Animals - Generic

现在让我们从人形字符开始,我已经创建了以下关系:

现在,您可以看到,每个类人形类都是从类NpcHumanoid编辑派生出来的--在图表中我的命名出现了一个错误,对不起。

如果您一直密切关注,您就会发现此代码存在问题。

我现在的主要问题是引用不同类型的对象。

,所以我的问题是什么是最好的方法?

我是否应该为状态机创建一个抽象类,然后创建该类的子类,然后为其控制AI/NPC类型的引用。那对我的州又有什么用呢?考虑到他们都以一个StateController作为参数,我必须不断地将状态控制器cast转换为使用状态的类型(这看起来像是游说和意大利面一样)。

此外,可能有一个解决方案,我没有看到我会想要从你们的意见。

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2018-03-05 01:04:09

统一使用基于组件的方法来组织游戏逻辑。因此,我认为最好的方法是对NPC类型使用组件而不是常规的OOP方法。

只需将不同类型的NPC视为具有不同组件的GameObject。例如,

Villager.cs

代码语言:javascript
运行
复制
class Villager: MonoBehaviour
{
    public float Fatigue;
    public int Carrying;
}

您可以创建一个NPCFactory来创建不同的NPC。

代码语言:javascript
运行
复制
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的状态。

票数 3
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/49101923

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档