首先我们应该定义一个状态基类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);
}