首先我们应该定义一个状态基类FSMBase,里面有一些动画状态的基本行为,比如动画状态的进入,持续,离开等,然后因为人物并不是只有一个状态,所以我们应该建立一个状态管理器来管理状态,里面应该定义一些方法,比如
我们应该定义一些状态的共同逻辑,比如对状态进行存储,添加状态AddState,状态间跳转的方法ChangeState(进入当前的动画状态时,应该离开上一个动画状态,从而保证每一帧处理的都是当前状态的逻辑)。
然后抽象出相应的状态类,即每一个状态都是一个类,如果增添状态,则需要再次定义相应的状态类并继承,每一个状态类都只写与自身相关的逻辑。
档具体的调用时,我们可以通过枚举,将状态添加到状态管理类里,然后如果需要跳转,就应该在状态类里设置一个代理,将需要改变的状态传回至FSMManager管理类的ChangeState方法里,进行跳转,而不是直接进行跳转,这样就大大减少了各个状态之间的耦合性和状态的扩展性。
代码如下:
using System.Collections; using System.Collections.Generic; using UnityEngine; public abstract class FSMBase { public Animator animator; public abstract void OnEnter(); public abstract void OnLeave(); public abstract void UpDate(); } public class FSMManager { FSMBase[] allState; byte curState; short stateIndex; public FSMManager (byte count) { allState = new FSMBase[count]; curState = 0; stateIndex = -1; } /// <summary> /// 添加 /// </summary> /// <param name="tmpBase">Tmp base.</param> public void AddState(FSMBase tmpBase) { if (curState<allState.Length) { allState[curState] = tmpBase; curState++; } } /// <summary> /// 状态跳转 /// </summary> /// <param name="index">Index.</param> public void ChangeState(byte index) { if (stateIndex!=-1) { allState[curState].OnLeave(); } stateIndex = curState; allState[index].OnEnter(); curState = index; } public void Update() { if (stateIndex!=-1) { allState[curState].UpDate(); } } }
using System.Collections; using System.Collections.Generic; using UnityEngine; public enum AnimalState { Idle, Attack, Walk, Jump, Max } public class PlayerController : MonoBehaviour { FSMManager fsmManger; private void Start() { fsmManger = new FSMManager((byte)AnimalState.Max); Animator ani = GetComponent<Animator>(); PlayerIdle tmpIdle = new PlayerIdle(ani); fsmManger.AddState(tmpIdle); PlayerAttack tmpAttack = new PlayerAttack(ani); fsmManger.AddState(tmpAttack); PlayerWalk tmpWalk= new PlayerWalk(ani); fsmManger.AddState(tmpWalk); PlayerJump tmpJump = new PlayerJump(ani); fsmManger.AddState(tmpJump); } private void Update() { if (Input.GetKeyDown(KeyCode.A)) { fsmManger.ChangeState((byte)AnimalState.Walk); } } }
using System; using System.Collections; using System.Collections.Generic; using UnityEngine; public delegate void ChangeDelegate(byte index); public class PlayerIdle : FSMBase { public PlayerIdle(Animator tmpAnimal) { this.animator = tmpAnimal; } public override void OnEnter() { this.animator.SetInteger("StateIndex",1); } public override void OnLeave() { } public override void UpDate() { } } public class PlayerAttack : FSMBase { public PlayerAttack(Animator tmpAnimator) { this.animator = tmpAnimator; } public override void OnEnter() { this.animator.SetInteger("StateIndex", 2); } public override void OnLeave() { } public override void UpDate() { } } public class PlayerWalk : FSMBase { public PlayerWalk(Animator tmpAnimator) { this.animator = tmpAnimator; } public override void OnEnter() { this.animator.SetInteger("StateIndex",3); } public override void OnLeave() { } public override void UpDate() { } }
public class Jump : FSMBase { ChangeDelegate changeIdle; public Skill1(Animator tmpAnimal,ChangeDelegate tmpDlegate) { this.animator = tmpAnimal; changeIdle = tmpDlegate; } float timer = 0; bool isPlayFinish; public override void OnEnter() { this.animator.SetInteger("StateIndex", 4); timer = 0; isPlayFinish = false; } public override void OnLeave() { timer = 0; isPlayFinish = false; } public override void UpDate() { timer += Time.deltaTime; if (timer > 0.28f && !isPlayFinish) { isPlayFinish = true; //do samething } if (timer > 1) { timer = 0; isPlayFinish = false; changeIdle((byte)AnimalStateSkill.Idle); } } }
public void ChangeState(byte index) { fsmManger.ChangeState(index); }