之前介绍了状态及状态机的概念,并且有个简单的跳转。
下面深入一点,写一个人物的普通状态、寻路状态导致的动作变化(站立状态到移动状态到骑马状态)
1、State类保持不变
using UnityEngine;
using System.Collections;
using System.Collections.Generic;
public class State
{
///
/// 状态名
///
public string name = "";
///
/// 构造
///
public State(string _name)
{
name = _name;
}
public State()
{
}
public delegate void TransitionEventHandler(State _from, State _to);
public delegate void OnActionHandler(State _curState);
///
/// 进入时的事件
///
public TransitionEventHandler onEnter;//System.Action
///
/// 退出时的事件
///
public TransitionEventHandler onExit;
///
/// 在状态机Update()时候调用的更新事件
///
public OnActionHandler onAction;
public virtual void Enter(State _from, State _to)
{
if (onEnter != null)
onEnter(_from, _to);
}
public virtual void Excute(State _curState)
{
if (onAction != null)
onAction(_curState);
}
public virtual void Exit(State _from, State _to)
{
if (onExit != null)
onExit(_from, _to);
}
}
2、Machine小改动了下,添加了能跳转的状态列表
using UnityEngine;
using System.Collections;
public class Machine
{
private State curState = null;
private State lastState = null;
/*Update*/
public void Update ()
{
if (curState != null)
curState.Excute(curState);
}
/*状态改变*/
public void ChangeState (State _newState)
{
if (_newState == null)
{
Debug.LogError ("can't find this state");
return;
}
if (curState != null && !curState.nextStates.Contains(_newState))
{
Debug.LogError("can't change to the state that curState don't contains");
return;
}
//触发退出状态调用Exit方法
curState.Exit(curState, _newState);
//保存上一个状态
lastState = curState;
//设置新状态为当前状态
curState = _newState;
//m_pCurrentState.Target = m_pOwner;
//进入当前状态调用Enter方法
curState.Enter(lastState, curState);
}
public Machine()
{
curState = null;
lastState = null;
}
public Machine(State _curState)
{
curState = _curState;
lastState = new State("init");
curState.Enter(lastState, _curState);
}
public void SetInitState(State _curState)
{
curState = _curState;
lastState = new State("init");
curState.Enter(lastState, _curState);
}
public string GetCurStateName()
{
if (curState != null)
{
return curState.name;
}
return string.Empty;
}
///
/// 重启状态机
///
public void Restart()
{
}
}
3、添加了一个继承MonoBehaviour的基类FSMBase,要用到状态变化就继承这个类
using UnityEngine;
using System.Collections;
public class FSMBase : MonoBehaviour {
protected Machine stateMachine;
void Start () {
stateMachine = new Machine();
InitStateMachine();
}
void Update()
{
if (stateMachine != null)
stateMachine.Update();
}
public virtual void Reset()
{
if (stateMachine != null)
stateMachine.Restart();
}
protected virtual void InitStateMachine() { }
}
4、上篇中的TestMachine改为AnimMachine,并且添加了骑马状态的情况
using UnityEngine;
using System.Collections;
public class AnimMachine : FSMBase {
protected State moveState = null;
protected State idleState = null;
protected State attackState = null;
protected State rideState = null;
protected override void InitStateMachine()
{
base.InitStateMachine();
idleState = new State("idle");
idleState.onEnter = EnterIdle;
idleState.onExit = ExitIdle;
idleState.onAction = ExcuteIdle;
moveState = new State("move");
moveState.onEnter = EnterMove;
moveState.onExit = ExitMove;
moveState.onAction = ExcuteMove;
attackState = new State("attack");
attackState.onEnter = EnterAttack;
attackState.onExit = ExitAttack;
attackState.onAction = ExcuteAttack;
rideState = new State("ride");
rideState.onEnter = EnterRide;
rideState.onExit = ExitRide;
rideState.onAction = ExcuteRide;
idleState.nextStates.Add(moveState);
idleState.nextStates.Add(attackState);
idleState.nextStates.Add(rideState);
moveState.nextStates.Add(idleState);
moveState.nextStates.Add(attackState);
moveState.nextStates.Add(rideState);
attackState.nextStates.Add(idleState);
attackState.nextStates.Add(moveState);
rideState.nextStates.Add(idleState);
stateMachine.SetInitState(idleState);
}
void EnterIdle(State _from, State _to)
{
Debug.Log("EnterIdle _from:" + _from.name);
}
void ExitIdle(State _from, State _to)
{
Debug.Log("ExitIdle _to:" + _to.name);
}
void ExcuteIdle(State _curState)
{
}
void EnterMove(State _from, State _to)
{
Debug.Log("EnterMove _from:" + _from.name);
}
void ExitMove(State _from, State _to)
{
Debug.Log("ExitMove _to:" + _to.name);
}
void ExcuteMove(State _curState)
{
}
void EnterAttack(State _from, State _to)
{
Debug.Log("EnterAttack _from:" + _from.name);
}
void ExitAttack(State _from, State _to)
{
Debug.Log("ExitAttack _to:" + _to.name);
}
void ExcuteAttack(State _curState)
{
}
void EnterRide(State _from, State _to)
{
Debug.Log("EnterRide _from:" + _from.name);
}
void ExitRide(State _from, State _to)
{
Debug.Log("ExitRide _to:" + _to.name);
}
void ExcuteRide(State _curState)
{
}
public void Idle()
{
if (stateMachine != null)
stateMachine.ChangeState(idleState);
}
public void Move()
{
if (stateMachine != null)
stateMachine.ChangeState(moveState);
}
public void Ride()
{
if (stateMachine != null)
stateMachine.ChangeState(rideState);
}
}
5、主玩家类,MainPlayer
using UnityEngine;
using System.Collections;
public class MainPlayer : FSMBase {
protected State normalState = null;
protected State taskPathState = null;//任务寻路
private AnimMachine animMachaine = null;
void Awake()
{
if (animMachaine == null)
{
animMachaine = gameObject.GetComponent
();
}
if (animMachaine == null)
{
animMachaine = gameObject.AddComponent
();
}
}
protected override void InitStateMachine()
{
base.InitStateMachine();
normalState = new State("normal");
normalState.onEnter = EnterNormalState;
normalState.onExit = ExitNormalState;
normalState.onAction = ExcuteNormalState;
taskPathState = new State("taskPathState");
taskPathState.onEnter = EnterTaskPathState;
taskPathState.onExit = ExitTaskPathState;
taskPathState.onAction = ExcuteTaskPathState;
normalState.nextStates.Add(taskPathState);
taskPathState.nextStates.Add(normalState);
stateMachine.SetInitState(normalState);
}
void EnterNormalState(State _from, State _to)
{
Debug.Log("EnterNormalState _from:" + _from.name);
animMachaine.Idle();
}
void ExitNormalState(State _from, State _to)
{
Debug.Log("ExitNormalState _to:" + _to.name);
}
void ExcuteNormalState(State _curState)
{
}
protected float enterTaskPathTime = 0f;
protected bool isRiding = false;
void EnterTaskPathState(State _from, State _to)
{
Debug.Log("EnterTaskPathState _from:" + _from.name);
animMachaine.Move();
enterTaskPathTime = Time.time;
}
void ExitTaskPathState(State _from, State _to)
{
Debug.Log("ExitTaskPathState _to:" + _to.name);
isRiding = false;
}
void ExcuteTaskPathState(State _curState)
{
if (Time.time - enterTaskPathTime > 5f && !isRiding)
{
animMachaine.Ride();
isRiding = true;
}
}
void OnGUI()
{
if (GUILayout.Button("normal"))
{
if (stateMachine != null)
stateMachine.ChangeState(normalState);
}
if (GUILayout.Button("taskPath"))
{
if (stateMachine != null)
stateMachine.ChangeState(taskPathState);
}
GUILayout.Label(stateMachine != null ? stateMachine.GetCurStateName() : "");
}
}