unity3d中使用状态机
2016-07-28 14:35
429 查看
使用状态机的目的就是对角色复杂的行为逻辑代码进行解耦。在同一个act根据状态id不同,调用不同的类执行代码。
以一个士兵,有查找敌人、移动、攻击、胜利、自身死亡,这五种状态为例。
FMS_State_ShiBing.cs是状态机的父类。主要完成定义状态枚举和构建状态字段
以一个士兵,有查找敌人、移动、攻击、胜利、自身死亡,这五种状态为例。
FMS_State_ShiBing.cs是状态机的父类。主要完成定义状态枚举和构建状态字段
using UnityEngine; using System.Collections; using System.Collections.Generic; public enum Translate_ShiBing //如果进入一个新的状态,需要一些触发,比如NPC看到了Player,由巡逻状态进入跟踪状态 { Unknow, ShiBing_FindObject, ShiBing_MoveToObjct, ShiBing_ActObject, ShiBing_Victory, ShiBing_Death } public enum StateID_ShiBing //每个状态都应该有一个ID,作为识别改状态的标志 { Unknow, ShiBing_FindObject, ShiBing_MoveToObjct, ShiBing_ActObject, ShiBing_Victory, ShiBing_Death } public abstract class FMS_State_ShiBing { private StateID_ShiBing id; //定一个状态ID作为变量来标识 public StateID_ShiBing ID { set { id = value; } get { return id; } } private Dictionary<Translate_ShiBing, StateID_ShiBing> map = new Dictionary<Translate_ShiBing, StateID_ShiBing>(); //在某一状态下,事件引起了触发进入另一个状态 // 于是我们定义了一个字典,存储的便是触发的类型,以及对应要进入的状态 public void addDictionary(Translate_ShiBing tr, StateID_ShiBing id1) //向字典里添加 { if (tr == Translate_ShiBing.Unknow) { Debug.LogError("Null Trans is not allower to adding into"); return; } if (ID == StateID_ShiBing.Unknow) { Debug.LogError("Null State id not ~~~"); return; } if (map.ContainsKey(tr)) //NPC 任何时候都只能出于一种状态,所以一旦定义了一个触发的枚举类型,对应的只能是接下来的一种状态 { Debug.LogError(id1.ToString() + "is already added to"); return; } map.Add(tr, id1); } public void deleateDictionary(Translate_ShiBing tr) //删除字典里存储的一个状态 { if (tr == Translate_ShiBing.Unknow) { Debug.LogError("TransNull is not allowed to delate"); return; } if (map.ContainsKey(tr)) { map.Remove(tr); return; } Debug.LogError(tr.ToString() + "are not exist"); } public StateID_ShiBing GetOutState(Translate_ShiBing tr) //由状态的触发枚举类型返回一个对应的状态类型 { if (map.ContainsKey(tr)) { // Debug.Log("Translate " + tr + "State" + map); return map ; } return StateID_ShiBing.Unknow; } public virtual void DoBeforeEnter() { } //虚方法 public virtual void DoBeforeMoveing() { } // public abstract void Reason(); // 抽象方法 public abstract void Act(); }
FMS_Machine_Manage_ShiBing.cs 这个类主要是实例化状态机,默认为第一个添加的状态。并且声明了当前状态允许跳转的状态清单using UnityEngine; using System.Collections; using System.Collections.Generic; public class FMS_Machine_Manage_ShiBing : MonoBehaviour { private List<FMS_State_ShiBing> states;//存储所有状态的的List private FMS_State_ShiBing currentState; //当前状态 private StateID_ShiBing currentStateID;//当前状态ID public FMS_State_ShiBing CurrentState { set { currentState = value; } get { return currentState; } } public StateID_ShiBing CurrentStateID { set { currentStateID = value; } get { return currentStateID; } } public GameObject player; public GameObject[] path; public GameObject NPC; public FMS_Machine_Manage_ShiBing() { states = new List<FMS_State_ShiBing>(); //初始化 } public void UpdateFunction() { // CurrentState.Reason(); CurrentState.Act(); } public void Revert() { } void Awake() { } public void MakeFMSMachine(GameObject MySelf) { FindObject_State_ShiBing FindObject = new FindObject_State_ShiBing(MySelf,this); FindObject.addDictionary(Translate_ShiBing.ShiBing_MoveToObjct, StateID_ShiBing.ShiBing_MoveToObjct);//放的是下个状态的,并且一次只能跳转到一个状态,但是好像也可以是多个 FindObject.addDictionary(Translate_ShiBing.ShiBing_Victory, StateID_ShiBing.ShiBing_Victory); AddFmsState(FindObject); MoveToObject_State_ShiBing MoveToObject = new MoveToObject_State_ShiBing(MySelf,this); MoveToObject.addDictionary(Translate_ShiBing.ShiBing_ActObject, StateID_ShiBing.ShiBing_ActObject); MoveToObject.addDictionary(Translate_ShiBing.ShiBing_FindObject, StateID_ShiBing.ShiBing_FindObject); AddFmsState(MoveToObject); ActTarget_State_ShiBing ActTarget = new ActTarget_State_ShiBing(MySelf,this); ActTarget.addDictionary(Translate_ShiBing.ShiBing_FindObject, StateID_ShiBing.ShiBing_FindObject); AddFmsState(ActTarget); Victory_State_ShiBing VictoryState = new Victory_State_ShiBing(MySelf, this); VictoryState.addDictionary(Translate_ShiBing.ShiBing_FindObject, StateID_ShiBing.ShiBing_FindObject); AddFmsState(VictoryState); } public void AddFmsState(FMS_State_ShiBing s)//注册所有状态 { if (s == null) { Debug.LogError(" Null reference is not allowed"); } if (states.Count == 0) { states.Add(s); //设置默认状态(important); currentState = s; currentStateID = s.ID; return; } foreach (FMS_State_ShiBing state in states) { if (state == s) { Debug.LogError(s.ID.ToString() + "has already been added"); return; } } states.Add(s); } public void delateFmsState(StateID_ShiBing id) { if (id == StateID_ShiBing.Unknow) { Debug.LogError("NullStateID is not allowed for a real state"); return; } foreach (FMS_State_ShiBing state in states) { if (state.ID == id) { states.Remove(state); return; } } } public void changeState(Translate_ShiBing tr) //更改状态 { if (tr == Translate_ShiBing.Unknow) { Debug.LogError("NullTransition is not allowed for a real transition"); return; } //if (currentState.GetOutState(tr) == StateID.NullState) //{ // Debug.Log("translate" + " " + tr + " " + currentState.GetOutState(tr)+" "+CurrentStateID); // Debug.LogError("1234"); // return; //} StateID_ShiBing id = CurrentState.GetOutState(tr); //当前状态会进入的新的状态 currentStateID = id; // Debug.Log("Prives" + Prives.ID); foreach (FMS_State_ShiBing state in states) //通过注册的所有状态,进行搜索来获取要进入的状态实例 { if (currentStateID == state.ID) { CurrentState.DoBeforeMoveing(); //退出状态前,留下点什么,比如挥舞下手臂 currentState = state; CurrentState.DoBeforeEnter(); //进入状态 break; } } } }
NPC_Control_ShiBing.cs这个类是用来挂在实际pre士兵身上的,其中UpDate实现了动作的心跳执行。
using UnityEngine;
using System.Collections;
public class NPC_Control_ShiBing : MonoBehaviour {
//要攻击的目标
public GameObject TargetObject;
//自己
public GameObject MySelfObject;
public float Speed;//速度
public float TurnSpeed;//旋转速度
public float ActRange;//火力范围
public int damage;//攻击力
public int HP;
private bool IsDestroy = false;
private FMS_Machine_Manage_ShiBing _FMS_Machine_Manage_ShiBing;
// Use this for initialization
void Start () {
Speed = 50f;
HP = 100;
TurnSpeed = 0.3f;
ActRange = 3.0f;
damage = 25;
_FMS_Machine_Manage_ShiBing = new FMS_Machine_Manage_ShiBing();
_FMS_Machine_Manage_ShiBing.MakeFMSMachine(MySelfObject);
}
// Update is called once per frame
void Update () {
_FMS_Machine_Manage_ShiBing.UpdateFunction();
}
public bool GetDestroy()
{
return IsDestroy;
}
public void DestroySetTrue()
{
IsDestroy = true;
Destroy(gameObject, 1.01f);//1.01秒后销毁炸弹
}
}
FindObject_State_ShiBing.cs是具体实现功能的类,查找目标。找到后移动,找不到说明没有敌人了,进入胜利状态。找到目标后进入攻击状态
using UnityEngine;
using System.Collections;
public class FindObject_State_ShiBing : FMS_State_ShiBing//查找目标
{
public GameObject[] aEnemy;//所有的敌人
private GameObject _MySelf;//自己
private NPC_Control_ShiBing _NPC_Control_ShiBing;//自己的其他属性
private FMS_Machine_Manage_ShiBing _FMS_Machine_Manage_ShiBing;
public FindObject_State_ShiBing(GameObject MySelf, FMS_Machine_Manage_ShiBing __FMS_Machine_Manage_ShiBing)
{
_FMS_Machine_Manage_ShiBing = __FMS_Machine_Manage_ShiBing;
ID = StateID_ShiBing.ShiBing_FindObject;
_MySelf = MySelf;//自己
_NPC_Control_ShiBing = _MySelf.GetComponent("NPC_Control_ShiBing") as NPC_Control_ShiBing;//自己的属性
}
public override void Act() //在该状态下改做点什么呢
{
//所有的敌人
aEnemy = GameObject.FindGameObjectsWithTag("Enemy");
//没有敌人就是胜利了
//if (aJianZhu.Length == 0)
//{
// _FMS_Machine_Manage_ShiBing.changeState(Translate_ShiBing.ShiBing_Victory);
// return;
//}
//最近的敌人
GameObject NearlyObject = null;
float TempDistance = 999999.0f;
bool AnyJianZhu = false;
foreach (GameObject enemy_GameObject in aEnemy)
{
NPC_Control_Enemy _NPC_Control_Enemy = enemy_GameObject.GetComponent("NPC_Control_Enemy") as NPC_Control_Enemy;
//如果被销毁,不计算当前敌人
if (_NPC_Control_Enemy.GetDestroy())
{
continue;
}
//还有敌人
AnyJianZhu = true;
//计算最小距离,这里最好的做法是在对象初始化的时候得到一个减去值,然后每次得到Y的初始位置
// JianZhu_GameObject.transform.position
//_MySelf.transform.position
float _distance = Vector3.Distance(enemy_GameObject.transform.position, _MySelf.transform.position);
if (_distance < TempDistance)
{
TempDistance = _distance;
NearlyObject = enemy_GameObject;
}
}
if (AnyJianZhu)
{
_NPC_Control_ShiBing.TargetObject = NearlyObject;
//找到目标后转向
_FMS_Machine_Manage_ShiBing.changeState(Translate_ShiBing.ShiBing_MoveToObjct);
}
else
{
_FMS_Machine_Manage_ShiBing.changeState(Translate_ShiBing.ShiBing_Victory);
}
}
public override void DoBeforeMoveing()
{
}
public override void DoBeforeEnter()
{
}
}
ActTarget_State_ShiBing.cs攻击状态,持续对敌人造成伤害。如果敌人死亡,进入查找敌人状态
using UnityEngine;
using System.Collections;
public class ActTarget_State_ShiBing : FMS_State_ShiBing
{
private GameObject _MySelf;//自己
private NPC_Control_ShiBing _NPC_Control_ShiBing;//自己的其他属性
private FMS_Machine_Manage_ShiBing _FMS_Machine_Manage_ShiBing;
private GameObject _target;//目标敌人
private NPC_Control_Enemy _NPC_Control_Enemy;//目标敌人的脚本
private float m_fireTimer = 0.0f;
public ActTarget_State_ShiBing(GameObject MySelf, FMS_Machine_Manage_ShiBing __FMS_Machine_Manage_ShiBing)
{
ID = StateID_ShiBing.ShiBing_ActObject;
_FMS_Machine_Manage_ShiBing = __FMS_Machine_Manage_ShiBing;
_MySelf = MySelf;//自己
_NPC_Control_ShiBing = _MySelf.GetComponent("NPC_Control_ShiBing") as NPC_Control_ShiBing;//自己的属性
}
public override void Act() //在该状态下改做点什么呢
{
// if (_target == null)
// {
_target = _NPC_Control_ShiBing.TargetObject;
// 获取一个对象上的脚本
_NPC_Control_Enemy = _target.GetComponent("NPC_Control_Enemy") as NPC_Control_Enemy;
//TargetHP = JianZhuObject.HP;
// }
if (_NPC_Control_Enemy.GetDestroy())
{
_FMS_Machine_Manage_ShiBing.changeState(Translate_ShiBing.ShiBing_FindObject);
}
else
{
//每两秒开一次火
m_fireTimer -= Time.deltaTime;
if (m_fireTimer <= 0)
{
// JianZhuObject.Jian_BeiGongJiFX();//如果士兵死了要调用一下
m_fireTimer = 2;
_NPC_Control_Enemy.HP = _NPC_Control_Enemy.HP - _NPC_Control_ShiBing.damage;
//如果敌人没血了,设置一个建筑的标志为摧毁,如果当前目标摧毁了,进入寻找状态
if (_NPC_Control_Enemy.HP <= 0)
{
_NPC_Control_Enemy.DestroySetTrue();
}
}
}
}
public override void DoBeforeMoveing()
{
}
public override void DoBeforeEnter()
{
}
}
其他的都同理我就不一一列出了。奉上源代码 http://pan.baidu.com/s/1i5wdVyX
博客不让上传附件太蛋疼了相关文章推荐
- Kinect结合Unity3D引擎开发体感游戏(一)
- Unity3D中脚本的执行顺序和编译顺序
- Unity3D动态对象优化代码分享
- Unity3D获取当前键盘按键及Unity3D鼠标、键盘的基本操作
- Unity3d获取系统时间
- unity3d发布apk在android虚拟机中运行的详细步骤(unity3d导出android apk)
- Unity3D游戏引擎实现在Android中打开WebView的实例
- javascript与有限状态机详解
- unity3d调用手机或电脑摄像头
- Unity3d发布IOS9应用时出现中文乱码的解决方法
- 分享一个开源的网络游戏服务器架构—HouHai
- Unity3D插件详细评测及教学下载
- Unity3D上路_01-2D太空射击游戏
- Unity3D上路_02-第一视角射击游戏
- Unity3D上路_03-塔防游戏
- Unity3D上路_04-基础资源介绍
- Unity3D上路_05-网络相关