天天看点

FSM有限状态机

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);
	}
}


        
FSM有限状态机

继续阅读