Unity中使用有限状态机FSM进行游戏开发

    总的来说,有限状态机系统,是指在不同阶段会呈现出不同的运行状态的系统,这些状态是有限的、不重叠的。这样的系统在某一时刻一定会处于其所有状态中的一个状态,此时它接收一部分允许的输入,产生一部分可能的响应,并且迁移到一部分可能的状态。
     五个要素:状态,事件,条件,动作,迁移

CS 角色FSM图


这里写图片描述

    使用switch (){case….}实现简单的有限状态机。

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class SimleFSM : MonoBehaviour {
    public enum State
    {
        Idle,
        Patrol,
        Chase,
        Attack
    }
    private State state = State.Idle;
    void Update () {
        switch (state)
        {
            case State.Idle:
                ProcessStateIdle();
                break;
            case State.Patrol:
                ProcessStatePatrol();
                break;
            case State.Chase:
                ProcessStateChase();
                break;
            case State.Attack:
                ProcessStateAttack();
                break;
            default:
                break;
        }
    }

    void ProcessStateIdle()
    {
    }
    void ProcessStatePatrol()
    {
    }
    void ProcessStateChase()
    {
    }
    void ProcessStateAttack()
    {
    }
}

    Unity中FSM有限状态机系统的构成和功能的简单实现:


这里写图片描述


using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class FSMSystem  {
    private Dictionary<StateID, FSMState> states = new Dictionary<StateID, FSMState>();

    private StateID currentStateID;
    private FSMState currentState;

    public void Update(GameObject npc)
    {
        currentState.Act(npc);
        currentState.Reason(npc);
    }

    public void AddState(FSMState s)
    {
        if (s == null)
        {
            Debug.LogError("FSMState不能为空");return;
        }
        if (currentState == null)
        {
            currentState = s;
            currentStateID = s.ID;
        }
        if (states.ContainsKey(s.ID))
        {
            Debug.LogError("状态" + s.ID + "已经存在,无法重复添加");return;
        }
        states.Add(s.ID, s);
    }
    public void DeleteState(StateID id)
    {
        if (id == StateID.NullStateID)
        {
            Debug.LogError("无法删除空状态");return;
        }
        if (states.ContainsKey(id) == false)
        {
            Debug.LogError("无法删除不存在的状态:" + id);return;
        }
        states.Remove(id);
    }

    public void PerformTransition(Transition trans)
    {
        if (trans == Transition.NullTransition)
        {
            Debug.LogError("无法执行空的转换条件");return;
        }
        StateID id= currentState.GetOutputState(trans);
        if (id == StateID.NullStateID)
        {
            Debug.LogWarning("当前状态" + currentStateID + "无法根据转换条件" + trans + "发生转换");return;
        }
        if (states.ContainsKey(id) == false)
        {
            Debug.LogError("在状态机里面不存在状态" + id + ",无法进行状态转换!");return;
        }
        FSMState state = states[id];
        currentState.DoAfterLeaving();
        currentState = state;
        currentStateID = id;
        currentState.DoBeforeEntering();
    }
} 
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public enum Transition
{
    NullTransition=0,
    SeePlayer,
    LostPlayer
}
public enum StateID
{
    NullStateID=0,
    Patrol,
    Chase
}


public abstract class FSMState{

    protected StateID stateID;
    public StateID ID { get { return stateID; } }
    protected Dictionary<Transition, StateID> map = new Dictionary<Transition, StateID>();
    protected FSMSystem fsm;

    public FSMState(FSMSystem fsm)
    {
        this.fsm = fsm;
    }


    public void AddTransition(Transition trans,StateID id)
    {
        if (trans == Transition.NullTransition)
        {
            Debug.LogError("不允许NullTransition");return;
        }
        if (id == StateID.NullStateID)
        {
            Debug.LogError("不允许NullStateID"); return;
        }
        if (map.ContainsKey(trans))
        {
            Debug.LogError("添加转换条件的时候," + trans + "已经存在于map中");return;
        }
        map.Add(trans, id);
    }
    public void DeleteTransition(Transition trans)
    {
        if (trans == Transition.NullTransition)
        {
            Debug.LogError("不允许NullTransition"); return;
        }
        if (map.ContainsKey(trans)==false)
        {
            Debug.LogError("删除转换条件的时候," + trans + "不存在于map中"); return;
        }
        map.Remove(trans);
    }
    public StateID GetOutputState(Transition trans)
    {
        if (map.ContainsKey(trans))
        {
            return map[trans];
        }
        return StateID.NullStateID;
    }

    public virtual void DoBeforeEntering() { }
    public virtual void DoAfterLeaving() { }
    public abstract void Act(GameObject npc);
    public abstract void Reason(GameObject npc);
}
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Enemy : MonoBehaviour {

    private FSMSystem fsm;

    void Start () {
        InitFSM();
    }

    void InitFSM()
    {
        fsm = new FSMSystem();

        FSMState patrolState = new PatrolState(fsm);
        patrolState.AddTransition(Transition.SeePlayer, StateID.Chase);

        FSMState chaseState = new ChaseState(fsm);
        chaseState.AddTransition(Transition.LostPlayer, StateID.Patrol);

        fsm.AddState(patrolState);
        fsm.AddState(chaseState);
    }

    void Update () {
        fsm.Update(this.gameObject);
    }
}
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class PatrolState : FSMState
{
    private List<Transform> path = new List<Transform>();
    private int index = 0;
    private Transform playerTransform;

    public PatrolState(FSMSystem fsm) : base(fsm)
    {
        stateID = StateID.Patrol;
        Transform pathTransform = GameObject.Find("Path").transform;
        Transform[] children= pathTransform.GetComponentsInChildren<Transform>();
        foreach(Transform child in children)
        {
            if (child != pathTransform)
            {
                path.Add(child);
            }
        }
        playerTransform = GameObject.Find("Player").transform;
    }

    public override void Act(GameObject npc)
    {
        npc.transform.LookAt(path[index].position);
        npc.transform.Translate(Vector3.forward * Time.deltaTime * 3);
        if (Vector3.Distance(npc.transform.position, path[index].position) < 1)
        {
            index++;
            index %= path.Count;
        }
    }

    public override void Reason(GameObject npc)
    {
        if (Vector3.Distance(playerTransform.position, npc.transform.position) < 3)
        {
            fsm.PerformTransition(Transition.SeePlayer);
        }
    }
}
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class ChaseState : FSMState
{
    private Transform playerTransform;
    public ChaseState(FSMSystem fsm) : base(fsm)
    {
        stateID = StateID.Chase;
        playerTransform = GameObject.Find("Player").transform;
    }

    public override void Act(GameObject npc)
    {
        npc.transform.LookAt(playerTransform.position);
        npc.transform.Translate(Vector3.forward * 2 * Time.deltaTime);
    }
    public override void Reason(GameObject npc)
    {
        if (Vector3.Distance(playerTransform.position, npc.transform.position) > 6)
        {
            fsm.PerformTransition(Transition.LostPlayer);
        }
    }
}
阅读更多
想对作者说点什么? 我来说一句

没有更多推荐了,返回首页