using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine; /**
有限状态机系统基于Eric Dybsand的《游戏编程精粹》(Game Programming Gems)第3.1章 如何使用:
1. 在状态转化机中的相应枚举类中,声明 transitions 和 states 的label. 2. 写新的类集成 FSMState, 对于写的每一个类都要写上“转换条件” pairs (transition-state).
这些转换条件表明 represent the state S2 the FSMSystem should be if while being on state S1, a
transition T is fired and state S1 has a transition from it to S2. 切记这是确定的FSM.
不能有 transition 导致两种 states. “Reason” 方法用来决定transition 是否应该 fired.
如果你感觉爽,可以把这个方法留空,在别的地方写代码用来 fire transitions. “Act” 用来写代码表现NPC在当前状态的 the actions.
如果你感觉爽,可以把这个方法留空,在别的地方写代码用来 code for the actions. 3. 创建 FSMSystem 类的实例,然后给他增加 states. 4. 在你的 UPdate或 FixedUpdate 方法中调用 Reason 和 Act (或者其他你用来 firing transitions 和 making the NPCs
behave 的方法). Asynchronous transitions from Unity Engine, 例如 OnTriggerEnter, SendMessage, 依然可用,
只需要调用你的 PerformTransition 方法 from your FSMSystem 实例 with the correct Transition
when the event occurs. */ /// <summary>
/// 在这个枚举类中声明 Transitions 的labels.
/// 不要改变第一个 label ( NullTransition ) 因为 FSMSystem 类将会使用它.
/// </summary>
public enum Transition
{
NullTransition = 0, // 使用这个 transition 用来在你的系统中表示一个不存在的 transition
SawPlayer,
LostPlayer
} /// <summary>
/// 在这个枚举类中声明 States 的labels.
/// 不要改变第一个 label( NullTransition ) 因为 FSMSystem 类将会使用它.
/// </summary>
public enum StateID
{
NullStateID = 0, // 使用这个 ID 用来在你的系统中表示一个不存在的 State
ChasingPlayer,
FollowingPath
} /// <summary>
/// 这个类表示有限状态机中的 States.
/// 每个状态有一个 Dictionary with pairs (transition-state) showing
/// which state the FSM should be if a transition is fired while this state
/// is the current state.
/// Reason 方法用来判断 transition 是否可行.
/// Act 方法用来表现NPC的动作.
/// </summary>
public abstract class FSMState
{
protected Dictionary<Transition, StateID> map = new Dictionary<Transition, StateID>();
protected StateID stateID;
public StateID ID { get { return stateID; } } public void AddTransition(Transition trans, StateID id)
{
// 检查trans和id是否为空
if (trans == Transition.NullTransition)
{
Debug.LogError("FSMState ERROR: NullTransition is not allowed for a real transition");
return;
} if (id == StateID.NullStateID)
{
Debug.LogError("FSMState ERROR: NullStateID is not allowed for a real ID");
return;
} // 因为这是一个确定的 FSM,
// 检查当前的 transition 是否已经在 the map
if (map.ContainsKey(trans))
{
Debug.LogError("FSMState ERROR: State " + stateID.ToString() + " already has transition " + trans.ToString() +
"Impossible to assign to another state");
return;
} map.Add(trans, id);
} /// <summary>
/// 这个方法用来用state's map中删除 transition-state对.
/// 如果 transition 不在 state's map但中,打印一个错误信息.
/// </summary>
public void DeleteTransition(Transition trans)
{
// 检查trans是否为空
if (trans == Transition.NullTransition)
{
Debug.LogError("FSMState ERROR: NullTransition is not allowed");
return;
} //删除钱检查 pair i是否在map当中
if (map.ContainsKey(trans))
{
map.Remove(trans);
return;
}
Debug.LogError("FSMState ERROR: Transition " + trans.ToString() + " passed to " + stateID.ToString() +
" was not on the state's transition list");
} /// <summary>
/// 这个方法用来返回 new state the FSM should be if
/// this state receives a transition and
/// </summary>
public StateID GetOutputState(Transition trans)
{
//检查 map 是否含有 transition
if (map.ContainsKey(trans))
{
return map[trans];
}
return StateID.NullStateID;
} /// <summary>
/// 这个函数用来设置 the State condition before entering it.
/// 在进入这个状态之前 FSMSystem 自动调用这个方法.
/// </summary>
public virtual void DoBeforeEntering() { } /// <summary>
/// 这个方法用来做必须的工作,在状态转化之前例如重新设置变量
/// 在进入到新状态之前 FSMSystem 会自动调用这个方法.
/// </summary>
public virtual void DoBeforeLeaving() { } /// <summary>
/// This method decides if the state should transition to another on its list
/// NPC is a reference to the object that is controlled by this class
/// </summary>
public abstract void Reason(GameObject player, GameObject npc); /// <summary>
/// This method controls the behavior of the NPC in the game World.
/// Every action, movement or communication the NPC does should be placed here
/// NPC is a reference to the object that is controlled by this class
/// </summary>
public abstract void Act(GameObject player, GameObject npc); } // class FSMState /// <summary>
/// FSMSystem class represents the Finite State Machine class.
/// It has a List with the States the NPC has and methods to add,
/// delete a state, and to change the current state the Machine is on.
/// </summary>
public class FSMSystem
{
private List<FSMState> states; // The only way one can change the state of the FSM is by performing a transition
// Don't change the CurrentState directly
private StateID currentStateID;
public StateID CurrentStateID { get { return currentStateID; } }
private FSMState currentState;
public FSMState CurrentState { get { return currentState; } } public FSMSystem()
{
states = new List<FSMState>();
} /// <summary>
/// This method places new states inside the FSM,
/// or prints an ERROR message if the state was already inside the List.
/// First state added is also the initial state.
/// </summary>
public void AddState(FSMState s)
{
// Check for Null reference before deleting
if (s == null)
{
Debug.LogError("FSM ERROR: Null reference is not allowed");
} // First State inserted is also the Initial state,
// the state the machine is in when the simulation begins
if (states.Count == 0)
{
states.Add(s);
currentState = s;
currentStateID = s.ID;
return;
} // Add the state to the List if it's not inside it
foreach (FSMState state in states)
{
if (state.ID == s.ID)
{
Debug.LogError("FSM ERROR: Impossible to add state " + s.ID.ToString() +
" because state has already been added");
return;
}
}
states.Add(s);
} /// <summary>
/// This method delete a state from the FSM List if it exists,
/// or prints an ERROR message if the state was not on the List.
/// </summary>
public void DeleteState(StateID id)
{
// Check for NullState before deleting
if (id == StateID.NullStateID)
{
Debug.LogError("FSM ERROR: NullStateID is not allowed for a real state");
return;
} // Search the List and delete the state if it's inside it
foreach (FSMState state in states)
{
if (state.ID == id)
{
states.Remove(state);
return;
}
}
Debug.LogError("FSM ERROR: Impossible to delete state " + id.ToString() +
". It was not on the list of states");
} /// <summary>
/// This method tries to change the state the FSM is in based on
/// the current state and the transition passed. If current state
/// doesn't have a target state for the transition passed,
/// an ERROR message is printed.
/// </summary>
public void PerformTransition(Transition trans)
{
// Check for NullTransition before changing the current state
if (trans == Transition.NullTransition)
{
Debug.LogError("FSM ERROR: NullTransition is not allowed for a real transition");
return;
} // Check if the currentState has the transition passed as argument
StateID id = currentState.GetOutputState(trans);
if (id == StateID.NullStateID)
{
Debug.LogError("FSM ERROR: State " + currentStateID.ToString() + " does not have a target state " +
" for transition " + trans.ToString());
return;
} // Update the currentStateID and currentState
currentStateID = id;
foreach (FSMState state in states)
{
if (state.ID == currentStateID)
{
// Do the post processing of the state before setting the new one
currentState.DoBeforeLeaving(); currentState = state; // Reset the state to its desired condition before it can reason or act
currentState.DoBeforeEntering();
break;
}
} } // PerformTransition() } //class FSMSystem

NPC 身上挂在的脚本

using System;
using System.Collections.Generic;
using System.Text;
using UnityEngine; [RequireComponent(typeof(Rigidbody))]
public class NPCControl : MonoBehaviour
{
public GameObject player;
public Transform[] path; private FSMSystem fsm; public void SetTransition(Transition t) { fsm.PerformTransition(t); } public void Start()
{
MakeFSM();
} // The NPC 有两个状态 FollowPath 和 ChasePlayer
private void MakeFSM()
{
FollowPathState follow = new FollowPathState(path);
follow.AddTransition(Transition.SawPlayer, StateID.ChasingPlayer); ChasePlayerState chase = new ChasePlayerState();
chase.AddTransition(Transition.LostPlayer, StateID.FollowingPath); fsm = new FSMSystem();
fsm.AddState(follow);
fsm.AddState(chase);
} public void FixedUpdate()
{
fsm.CurrentState.Reason(player, gameObject);
fsm.CurrentState.Act(player, gameObject);
} } //跟随固定路径状态定义
public class FollowPathState : FSMState
{
private int currentWayPoint;
private Transform[] waypoints; //初始化
public FollowPathState(Transform[] wp)
{
waypoints = wp;
currentWayPoint = 0;
stateID = StateID.FollowingPath;
} public override void Reason(GameObject player, GameObject npc)
{
// 如果 Player 距离NPC小于2米
float distance = (player.transform.position-npc.transform.position).magnitude;
Debug.Log(distance);
if (distance<2)
{
//转换条件
npc.GetComponent<NPCControl>().SetTransition(Transition.SawPlayer);
}
} public override void Act(GameObject player, GameObject npc)
{
// Follow the path of waypoints
// Find the direction of the current way point Vector3 vel = npc.GetComponent<Rigidbody>().velocity;
Vector3 moveDir = waypoints[currentWayPoint].position - npc.transform.position; if (moveDir.magnitude < 1)
{
currentWayPoint++;
if (currentWayPoint >= waypoints.Length)
{
currentWayPoint = 0;
}
}
else
{
vel = moveDir.normalized * 3;
} // 应用速度
npc.GetComponent<Rigidbody>().velocity = vel;
} } //追逐英雄状态 public class ChasePlayerState : FSMState
{
//初始化函数
public ChasePlayerState()
{
stateID = StateID.ChasingPlayer;
} public override void Reason(GameObject player, GameObject npc)
{
// player已经距离 NPC超过30米, fire LostPlayer transition
if (Vector3.Distance(npc.transform.position, player.transform.position) >= 30)
npc.GetComponent<NPCControl>().SetTransition(Transition.LostPlayer);
} public override void Act(GameObject player, GameObject npc)
{
// Follow the path of waypoints
//找到玩家 player 的方向
Vector3 vel = npc.GetComponent<Rigidbody>().velocity;
Vector3 moveDir = player.transform.position - npc.transform.position; // Rotate towards the waypoint
vel = moveDir.normalized * 1; // 使用速度
npc.GetComponent<Rigidbody>().velocity = vel;
} }

Unity 状态转化机器的更多相关文章

  1. REST --- Representational State Transfer --- 表现层状态转化

    引用:阮一峰的网络日志 如果一个架构符合REST原则,就称它为RESTful架构. 要理解RESTful架构,最好的方法就是去理解Representational State Transfer这个词组 ...

  2. REST 表现层状态转化

    1.REST是什么? 1) REST:即 Representational State Transfer.(资源)表现层状态转化.是目前最流行的一种互联网软件架构.它结构清晰.符合标准.易于理解.扩展 ...

  3. TCP状态转化图 TIME_WAIT解析

    先上转换图: 重点研究TIME_WAIT状态,根据UNIX网络编程中的思路,TIME_WAIT状态有两个存在的理由: 理由1. 客户端执行主动关闭,假设最终的ACK丢失,服务器将重新发送它的最后那个F ...

  4. 魔板 Magic Squares(广搜,状态转化)

    题目背景 在成功地发明了魔方之后,鲁比克先生发明了它的二维版本,称作魔板.这是一张有8个大小相同的格子的魔板: 1 2 3 4 8 7 6 5 题目描述 我们知道魔板的每一个方格都有一种颜色.这8种颜 ...

  5. Java:线程的六种状态及转化

    目录 Java:线程的六种状态及转化 一.新建状态(NEW) 二.运行状态(RUNNABLE) 就绪状态(READY) 运行状态(RUNNING) 三.阻塞状态(BLOCKED) 四.等待状态(WAI ...

  6. Java中线程的状态及其转化

    线程状态转化图: 说明: 线程总共包括以下5种状态. 1.新状态New:该状态也叫新建状态,当线程对象被创建后,线程就进入了新建状态.例如:Thread thread = new Thread();. ...

  7. Asp.net 面向接口可扩展框架之类型转化基础服务

    新框架正在逐步完善,可喜可贺的是基础服务部分初具模样了,给大家分享一下 由于基础服务涉及面太广,也没开发完,这篇只介绍其中的类型转化部分,命名为类型转化基础服务,其实就是基础服务模块的类型转化子模块 ...

  8. 【Hibernate框架】对象的三种持久化状态

    一.综述 hibernate中的对象有三种状态,分别是TransientObjects(瞬时对象).PersistentObjects(持久化对象)和DetachedObjects(托管对象也叫做离线 ...

  9. TCP/IP详解--连接状态变迁图CLOSE_WAIT

    终止一个连接要经过4次握手.这由TCP的半关闭(half-close)造成的.既然一个TCP连接是全双工(即数据在两个方向上能同时传递,可理解为两个方向相反的独立通道),因此每个方向必须单独地进行关闭 ...

随机推荐

  1. timestamp 类型的索引

    由这条语句datetime.strftime('2014/12/05','%Y/%m/%d')转换出来的索引 是pandas内置类型相同,如果使用datetime.strftime('2014/12/ ...

  2. JNDI 和JDBC的区别

    1.JNDI 和JDBC的区别和联系.两者都是API,是一个标准.并不是什么产品或方法.JDBC 全称:Java Database Connectivity 以一种统一的方式来对各种各样的数据库进行存 ...

  3. STL_advance distance prev next

    template<class InputIterator> typename iterator_traits<InputIterator>::difference_type d ...

  4. NYOJ之猴子吃桃问题

    aaarticlea/png;base64,iVBORw0KGgoAAAANSUhEUgAAAskAAAIMCAIAAACIcqa9AAAgAElEQVR4nO3dO3Li3BaG4TMJcgbi1A

  5. 使用HttpWebRequest发送自定义POST请求

    平时用浏览器看网页的时候,点击一下submit按钮的时候其实就是给服务器发送了一个POST请求.但是如何在自己的C#程序里面实现类似的功能呢?本文给出了一个简单的范例,可以实现类似的和web serv ...

  6. SVN 搭建

    http://www.blogjava.net/jasmine214--love/archive/2010/09/26/332989.html http://hunan.iteye.com/blog/ ...

  7. 【JAVA网络流之URL】

    一.URL URL对象可以认为是URLConnection对象+Socket对象. Java.lang.Object |-Java.net.URL 常用构造方法: URL(String spec)   ...

  8. HTML5_Canvas_属性、定义及方法

    一.简单图形,整套的属性和方法专门用于绘制矩形:1.fillStyle可以设置为CSS颜色.一个图案或一种颜色渐变.fillStyle默认是纯黑色,你可以设置成你喜欢的任意颜色.只要页面打开着,每个绘 ...

  9. slf4i + logback 配置

    一.所需jar包: slf4j-api-1.6.1.jar logback-classic-0.9.24.jar logback-core-0.9.24.jar 二.logback.xml配置示例: ...

  10. 在Virtulbox上装Ubuntu

    做个程序员,会用Linux,这应该是最基本的要求吧.可惜本人经常用Windows,只是偶尔去服务器上做些操作的时候才接触到linux.so,我要学Linux.刚学所以还是先装个虚拟机吧,等在虚拟机上用 ...