高级状态机创建

首先知道简单状态机

这种方法中我们把状态和条件判断都集中在一个类里面,代码量冗多,不方便管理,很容易搞混

高级状态机则是通过把状态,状态引用,角色引用分离,是代码看起来十分清晰;


首先先定义一个抽象状态基类(FSMState),枚举切换状态的条件,状态若干;新建一个字典《看见什么条件,切换为什么状态》;添加字典是必须判断输入是否规范,增加程序的 健壮性。比如说条件是否为空,状态是否为空,条件是否已经存在。再定义一个类通过传条件获取当前的状态。接着定义虚方法进入状态之前和状态之后,定义抽象方法状态进行时和条件判断,最后引用一个状态机类(FSMSystem),在构造函数赋值;

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; } }                    //返回stateID
    public Dictionary<Transition, StateID> map = new Dictionary<Transition, StateID>();
    protected FSMSystem fsm;                                        //引用的FSMSystem

    public FSMState(FSMSystem fsm)                                  //先调用构造函数更新引用的FSMSystem;
    {
        this.fsm = fsm;
    }



    public void AddTransition(Transition tran,StateID id)         //添加转化条件(构造)
    {
        if (tran==Transition.NullTransition)
        {
            Debug.LogError("不允许条件为空");return;
        }
        if (id == StateID.NullStateId)
        {
            Debug.LogError("不允许状态为空"); return;
        }
        if (map.ContainsKey(tran))
        {
            Debug.LogError("条件已经存在"); return;
        }
        map.Add(tran,id);
    }


    public void DeleteTransition(Transition tran,StateID id)
    {
        if (tran == Transition.NullTransition)
        {
            Debug.LogError("不允许条件为空"); return;
        }
        if (map.ContainsKey(tran)==false)
        {
            Debug.LogError("条件不存在"); return;
        }
        map.Remove(tran);
    }

    public StateID GetState(Transition tran)
    {
        if (map.ContainsKey(tran))
        {
            return map[tran];
        }
        return StateID.NullStateId;
    }

    public virtual void BeforeEnter() { }
    public virtual void AfterExit() { }
    public abstract void Act(GameObject npc);                 //进入状态之时(抽象类每个子类不同必须重写)
    public abstract void Reason(GameObject npc);              //判断转换条件,条件机



    // Use this for initialization
    void Start () {
		
	}
	
	// Update is called once per frame
	void Update () {
		
	}
}


定义一个状态机类(FSMSystem),为不用遍历采用字典《状态,状态抽象类》,变量有,当前状态和当前 抽象状态基类

函数一:通过传抽象状态基类为字典赋值

函数二:执行条件(如果条件没报错的话),赋值当前状态和当前 抽象状态基类。

函数三:传值gameobject给update;时刻调用状态进行时和条件判断

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 AddState(FSMState s)
    {
        if (s==null)
        {
            Debug.LogError("FSM不能为空");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 DeleState(StateID id)
    {
        if (id==StateID.NullStateId)
        {
            Debug.LogError("无法删除空状态");return;
        }
        if (states.ContainsKey(id)==false)
        {
            Debug.LogError("无法删除不存在的状态"+id);
        }
        states.Remove(id);
    }

    public void PerformTransition(Transition tran)              //传进来一个条件,执行条件
    {
        if (tran==Transition.NullTransition)
        {
            Debug.LogError("无法执行空的转换条件");return;
        }
        StateID id= currentState.GetState(tran);                //通过条件获取ID
        if (id==StateID.NullStateId)
        {
            Debug.LogError("该条件没有对应的状态");return;
        }
        if (states.ContainsKey(id)==false)                      //当前状态机字典里是否有这个状态
        {
            Debug.LogError("状态机不存在这个状态"); return;
        }
        FSMState state = states[id];                            //把状态和条件赋值给 局部变量
        currentState.AfterExit();                               //播放状态离开部分
        currentState = state;                                   //赋值给当前条件和状态
        currentStateID = id;                                    //赋值给当前状态
        currentState.BeforeEnter();                             //播放状态进入之前
    }

	// Use this for initialization
	void Start () {
		
	}
	
	// Update is called once per frame
	public void Update (GameObject npc) {
        currentState.Act(npc);                                  //调用当前状态的ACT
        currentState.Reason(npc);
	}
}


定义巡逻类,追寻类;重写构造方法,状态进行时和条件判断

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

public class PatrolState :  FSMState{

    public List<Transform> path=new List<Transform>() ;
    public int index = 0;
    public Transform player;
    public PatrolState(FSMSystem fsm) : base(fsm)                               //那么子类也要传一个FSM用于更新父类fsm
    {
        player = GameObject.Find("Play").transform;
        stateID = StateID.Patrol;                                              //继承并修改父类参数
        Transform Path1 = GameObject.Find("Path").transform;
        Transform[] children = Path1.GetComponentsInChildren<Transform>();    //这个位置组包含Path的位置
        foreach (Transform child in children)
        {
            if (child!=Path1)
            {
                path.Add(child);
            }
        }                
    }

    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(player.position,npc.transform.position)<3)
        {
            fsm.PerformTransition(Transition.SeePlayer);
        }
        //throw new NotImplementedException();
    }

    // Use this for initialization
    void Start () {
		
	}
	
	// Update is called once per frame
	void Update () {
		
	}
}
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Chase : FSMState {

    private Transform player;
    public Chase(FSMSystem fsm) : base(fsm)
    {
        stateID = StateID.Chase;
        player = GameObject.Find("Play").transform;
    }

    public override void Act(GameObject npc)
    {
        npc.transform.LookAt(player.position);
        npc.transform.Translate(Vector3.forward*Time.deltaTime*2);
    }

    public override void Reason(GameObject npc)
    {
        if (Vector3.Distance(player.position, npc.transform.position) > 6)
        {
            fsm.PerformTransition(Transition.LostPlayer);
        }
        //throw new NotImplementedException();
    }

    // Use this for initialization
    void Start () {
		
	}
	
	// Update is called once per frame
	void Update () {
		
	}
}



定义敌人类

  1. new一个状态机,初始化,新建一个状态机,见一个巡逻类,赋值状态机给构造函数往字典《看见什么条件,切换为什么状态》加“看见敌人条件”,“追寻状态”。调用状态机添加巡逻状态的函数。
  2. 新建一个状态机,见一个追寻类,赋值状态机给构造函数往字典《看见什么条件,切换为什么状态》加“丢失敌人条件”,“巡逻状态”。调用状态机添加追寻状态的函数。
  3. update给状态机update添加this.gameobject'

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

public class enemy : MonoBehaviour {

    public FSMSystem fsm;

	// Use this for initialization
	void Start () {
        InitFSM();
	}
    void InitFSM()
    {
        fsm = new FSMSystem();

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

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

        fsm.AddState(ChaseState);


    }

    // Update is called once per frame
    void Update () {
        fsm.Update(this.gameObject);
	}
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值