FSM有限状态机,它是一种设计模式,它是一种设计思想.
解决的问题,有多个状态组成的,有限多个状态之间的切换,切换状态的时候有清晰的逻辑.
描述一个人物的行为:可以是一个idle状态,跑步状态,攻击的状态,死亡的状态
链接:http://pan.baidu.com/s/1slbNli1 密码:5vih 工程源码,需要把ui拖到画布下面
控制小球拖拽的脚本
using UnityEngine;
using System.Collections;
using UnityEngine.EventSystems;
public class UIJoysticksWin : MonoBehaviour
{
public static UIJoysticksWin Instance;
void Awake ()
{
Instance = this;
}
// 声明一个委托类型
// 拖拽
public delegate void JoysticksDragDelegate (Vector3 coor);
public JoysticksDragDelegate JoysticksDrag;
// 抬手
public delegate void JoysticksUpDelegate ();
public JoysticksUpDelegate JoysticksUp;
// 1.小球初始点
Vector3 startPoint;
// 2.半径
float r;
public Transform m_border;
void Start ()
{
startPoint = transform.position;
r = Vector3.Distance (transform.position, m_border.position);
}
// 拖拽方法
public void OnPointDragAction (BaseEventData bd)
{
// 如果在半径内
if (Vector3.Distance (Input.mousePosition, startPoint) < r) {
transform.position = Input.mousePosition;
} else {
Vector3 dir = Input.mousePosition - startPoint;
transform.position = startPoint + dir.normalized * r;
}
}
// 抬起鼠标
public void OnPointUpAction (BaseEventData bd)
{
if (JoysticksUp != null) {
JoysticksUp ();
}
transform.position = startPoint;
}
void Update ()
{
if (JoysticksDrag != null) {
if (Vector3.Distance (transform.position, startPoint) > 0.1f) {
Vector3 newDir = (transform.position - startPoint).normalized;
JoysticksDrag (newDir);
}
}
}
}
button点击事件,控制人物的技能点击按钮的脚本
using UnityEngine;
using System.Collections;
using UnityEngine.UI;
// 传参类
public class MyEventArgs
{
public int id;
public GameObject obj;
}
public class UICtrlWinScript : MonoBehaviour
{
public static UICtrlWinScript Instance;
void Awake ()
{
Instance = this;
}
// 定义button委托
public delegate void SkillButtonDeleget (MyEventArgs buttonArgs);
public SkillButtonDeleget SkillButtonAction;
// 数组
Button[] buttons;
void Start ()
{
buttons = GetComponentsInChildren<Button> ();
for (int i = 0; i < buttons.Length; i++) {
MyEventArgs args = new MyEventArgs ();
args.id = i + 1;
args.obj = buttons [i].gameObject;
buttons [i].onClick.AddListener (
() => OnButtonClick (args)
);
}
}
public void OnButtonClick (MyEventArgs args)
{
if (SkillButtonAction != null) {
SkillButtonAction (args);
}
}
}
定义的基类,控制状态之间的切换
using UnityEngine;
using System.Collections;
public abstract class StateBase
{
/// <summary>
/// 控制的对象
/// </summary>
public Transform transform = null;
/// <summary>
/// 构造方法
/// </summary>
/// <param name="transform">Transform.</param>
public StateBase (Transform transform)
{
this.transform = transform;
}
/// <summary>
/// 状态进入的回调
/// </summary>
public abstract void OnEnter ();
/// <summary>
/// Update方法
/// </summary>
public abstract void OnStay ();
/// <summary>
/// 状态离开的回调
/// </summary>
public abstract void OnExit ();
}
状态管理类,里面存放所有的人物状态
using UnityEngine;
using System.Collections;
using System.Collections.Generic;
using System;
public class StateMgr
{
// 状态列表
private List<StateBase> mStates = new List<StateBase> ();
// 当前状态
public StateBase mCurrentState = null;
public void AddState (StateBase state)
{
mStates.Add (state);
if (mStates.Count == 1) {
mCurrentState = state;
}
}
public void RemoveState (StateBase state)
{
mStates.Remove (state);
state = null;
}
public void Update ()
{
mCurrentState.OnStay ();
}
public void ChangeState (Type state = null)
{
//判断状态是否存在
foreach (StateBase s in mStates) {
if (s.GetType () == state) {
//状态离开
if (mCurrentState != null)
mCurrentState.OnExit ();
//切换状态
mCurrentState = s;
//新状态进入
mCurrentState.OnEnter ();
}
}
}
}
人物控制脚本
using UnityEngine;
using System.Collections;
public class MageMaleCtrl : MonoBehaviour
{
// 水平位移
float hor, ver;
// 状态机
public StateMgr m_stateMgr;
void Start ()
{
// 注册摇杆委托
UIJoysticksWin.Instance.JoysticksDrag = OnJoysticksDrag;
UIJoysticksWin.Instance.JoysticksUp = OnJoysticksUp;
// 注册技能Button委托
UICtrlWinScript.Instance.SkillButtonAction = OnSkillButtonAction;
// 向有限状态机注册状态.
// 这中有限状态机的写法与课上所讲不同,
// 游戏时, 可能经常在不同的状态下来回切换,
// 课上的FSM会每次都创建一个新的状态对象. 这会大大增加负担.
// 这种FSM的写法将每种状态保存到List容器中, 不会
m_stateMgr = new StateMgr ();
Run run = new Run (transform);
m_stateMgr.AddState (run);
Idle idle = new Idle (transform);
m_stateMgr.AddState (idle);
// 以下4中技能, 应该从Model中获取.
// 利用反射动态生成技能节点状态.
// 这样的话, 就能够通过Model的配置动态的为人物修改技能了.
Attack1 attack1 = new Attack1 (transform);
m_stateMgr.AddState (attack1);
Attack2 attack2 = new Attack2 (transform);
m_stateMgr.AddState (attack2);
Attack3 attack3 = new Attack3 (transform);
m_stateMgr.AddState (attack3);
Attack4 attack4 = new Attack4 (transform);
m_stateMgr.AddState (attack4);
m_stateMgr.ChangeState (typeof(Idle));
}
// 驱动状态机的Update事件
void Update ()
{
if (m_stateMgr.mCurrentState != null) {
m_stateMgr.Update ();
}
}
// 摇杆移动
public void OnJoysticksDrag (Vector3 coor)
{
// 这段代码表示, 只有在Idle状态和Run状态,
// 才会响应摇杆数据
// 在播放攻击动画时, 不会响应摇杆. 只有动画播放完成后, 才会响应摇杆.
if (!(m_stateMgr.mCurrentState.GetType () == typeof(Idle) ||
m_stateMgr.mCurrentState.GetType () == typeof(Run))) {
return;
}
// 摇杆拖动, 进入跑步状态,
Vector3 dir = new Vector3 (coor.x, 0, coor.y);
Quaternion q = Quaternion.LookRotation (dir);
transform.rotation = Quaternion.Lerp (transform.rotation, q, Time.deltaTime * 3f);
// 切换到跑步状态
m_stateMgr.ChangeState (typeof(Run));
}
// 摇杆抬起
public void OnJoysticksUp ()
{
// 摇杆抬起, 进入Idle状态
m_stateMgr.ChangeState (typeof(Idle));
}
// 按钮按下
public void OnSkillButtonAction (MyEventArgs args)
{
// 这段代码表示, 只有在idle状态和Run状态,
// 才会响应技能Button
// 在播放攻击动画时,不能移动也不能播放其他动画
if (!(m_stateMgr.mCurrentState.GetType () == typeof(Idle) ||
m_stateMgr.mCurrentState.GetType () == typeof(Run))) {
return;
}
// 这里的映射也需要从Model中获取配置.暂时写死.
switch (args.id) {
case 1:
{
m_stateMgr.ChangeState (typeof(Attack1));
break;
}
case 2:
{
m_stateMgr.ChangeState (typeof(Attack2));
break;
}
case 3:
{
m_stateMgr.ChangeState (typeof(Attack3));
break;
}
case 4:
{
m_stateMgr.ChangeState (typeof(Attack4));
break;
}
default:
{
break;
}
}
}
}
技能1脚本
using UnityEngine;
using System.Collections;
public class Attack1 : StateBase
{
// 继承父类的构造方法
public Attack1 (Transform transform) : base (transform)
{
}
Animator m_ant;
public override void OnEnter ()
{
m_ant = transform.GetComponent<Animator> ();
m_ant.SetBool ("Attack1", true);
}
public override void OnStay ()
{
AnimatorStateInfo info = m_ant.GetCurrentAnimatorStateInfo (0);
if (info.IsName ("Attack1")) {
if (info.normalizedTime > 1) {
transform.GetComponent<MageMaleCtrl> ().m_stateMgr.ChangeState (typeof(Idle));
}
}
}
public override void OnExit ()
{
m_ant.SetBool ("Attack1", false);
}
}
技能2脚本
using UnityEngine;
using System.Collections;
public class Attack2 : StateBase
{
// 继承父类的构造方法
public Attack2 (Transform transform) : base (transform)
{
}
Animator m_ant;
public override void OnEnter ()
{
m_ant = transform.GetComponent<Animator> ();
m_ant.SetBool ("Attack2", true);
}
public override void OnStay ()
{
AnimatorStateInfo info = m_ant.GetCurrentAnimatorStateInfo (0);
if (info.IsName ("Attack2")) {
if (info.normalizedTime > 1) {
transform.GetComponent<MageMaleCtrl> ().m_stateMgr.ChangeState (typeof(Idle));
}
}
}
public override void OnExit ()
{
m_ant.SetBool ("Attack2", false);
}
}
技能3脚本
using UnityEngine;
using System.Collections;
public class Attack3 : StateBase
{
// 继承父类的构造方法
public Attack3 (Transform transform) : base (transform)
{
}
Animator m_ant;
public override void OnEnter ()
{
m_ant = transform.GetComponent<Animator> ();
m_ant.SetBool ("Attack3", true);
}
public override void OnStay ()
{
AnimatorStateInfo info = m_ant.GetCurrentAnimatorStateInfo (0);
if (info.IsName ("Attack3")) {
if (info.normalizedTime > 1) {
transform.GetComponent<MageMaleCtrl> ().m_stateMgr.ChangeState (typeof(Idle));
}
}
}
public override void OnExit ()
{
m_ant.SetBool ("Attack3", false);
}
}
技能4脚本
using UnityEngine;
using System.Collections;
public class Attack4 : StateBase
{
// 继承父类的构造方法
public Attack4 (Transform transform) : base (transform)
{
}
Animator m_ant;
public override void OnEnter ()
{
m_ant = transform.GetComponent<Animator> ();
m_ant.SetBool ("Attack4", true);
}
public override void OnStay ()
{
AnimatorStateInfo info = m_ant.GetCurrentAnimatorStateInfo (0);
if (info.IsName ("Attack4")) {
if (info.normalizedTime > 1) {
transform.GetComponent<MageMaleCtrl> ().m_stateMgr.ChangeState (typeof(Idle));
}
}
}
public override void OnExit ()
{
m_ant.SetBool ("Attack4", false);
}
}
人物默认状态Idel
using UnityEngine;
using System.Collections;
public class Idle : StateBase
{
// 继承父类的构造方法
public Idle (Transform transform) : base (transform)
{
}
public override void OnEnter ()
{
this.transform.GetComponent<Animator> ().SetBool ("Idle", true);
}
public override void OnStay ()
{
}
public override void OnExit ()
{
this.transform.GetComponent<Animator> ().SetBool ("Idle", false);
}
}
人物跑的脚本
using UnityEngine;
using System.Collections;
public class Run : StateBase
{
// 继承父类的构造方法
public Run (Transform transform) : base (transform)
{
}
public override void OnEnter ()
{
this.transform.GetComponent<Animator> ().SetBool ("Run", true);
}
public override void OnStay ()
{
transform.position += transform.forward * Time.deltaTime * 3f;
}
public override void OnExit ()
{
this.transform.GetComponent<Animator> ().SetBool ("Run", false);
}
}