开启辅助访问
 找回密码
 注册帐号

扫一扫,访问微社区

教程分享

关注:648

当前位置:游戏蛮牛 技术专区 教程分享

查看: 667|回复: 2

[基础知识] Unity3D架构系列之- FSM有限状态机设计四至六

[复制链接]  [移动端链接]
7日久生情
4285/5000
排名
2170
昨日变化
1

1646

主题

1657

帖子

4285

积分

Rank: 7Rank: 7Rank: 7Rank: 7

UID
132510
好友
17
蛮牛币
57209
威望
0
注册时间
2015-12-24
在线时间
352 小时
最后登录
2017-6-20
发表于 2016-7-6 11:52:43 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。

您需要 登录 才可以下载或查看,没有帐号?注册帐号

x
  接下来,我们继续我们的FSM有限状态机的设计,在设计三中我们实现了FSState这个类,我们继续实现FSEvent事件处理类。在FSEvent类里面我们声明了FiniteStateMachine里面定义的委托函数。代码如下:

  protected FiniteStateMachine.EnterState mEnterDelegate;

  protected FiniteStateMachine.PushState mPushDelegate;

  protected FiniteStateMachine.PopState mPopDelegate;

  同时我们定义了一个枚举用于处理有限状态机的状态,使用了System里面自带的封装的一个具有三个参数并返回TResult参数制定的雷兴志的方法。

  public Func<object,object,object,bool>        mAction = null;

  这个FSEvent事件类也是独立的,不继承Mono。它的核心功能主要是处理FSState的Enter,Push,Pop。代码如下:

  public FSState Enter(string stateName) {

  mTargetState = stateName;

  eType = EventType.ENTER;

  return mStateOwner;

  }

  public FSState Push(string stateName) {

  mTargetState = stateName;

  eType = EventType.PUSH;

  return mStateOwner;

  }

  public void Pop() {

  eType = EventType.POP;

  }

  public void Execute(object o1,object o2,object o3) {

  if (eType == EventType.POP) {

  mPopDelegate();

  }

  else if (eType == EventType.PUSH) {

  mPushDelegate(mTargetState, mOwner.CurrentState.StateName);

  }

  else if (eType == EventType.ENTER) {

  mEnterDelegate(mTargetState);

  }

  else if (mAction != null) {

  mAction(o1, o2, o3);

  }

  }

  总的来说,FSEvent是通过调用Enter,Push,Pop,Execute执行状态的切换。下面把整个代码给大家展现一下:

  [C#] 纯文本查看 复制代码

  ?

  01

  02

  03

  04

  05

  06

  07

  08

  09

  10

  11

  12

  13

  14

  15

  16

  17

  18

  19

  20

  21

  22

  23

  24

  25

  26

  27

  28

  29

  30

  31

  32

  33

  34

  35

  36

  37

  38

  39

  40

  41

  42

  43

  44

  45

  46

  47

  48

  49

  50

  51

  52

  53

  54

  55

  56

  57

  using

  System;

  public

  class

  FSEvent {

  protected

  FiniteStateMachine.EnterState mEnterDelegate;

  protected

  FiniteStateMachine.PushState mPushDelegate;

  protected

  FiniteStateMachine.PopState mPopDelegate;

  protected

  enum

  EventType { NONE, ENTER, PUSH, POP };

  protected

  string

  mEventName;

  protected

  FSState mStateOwner;

  protected

  string

  mTargetState;

  protected

  FiniteStateMachine mOwner;

  protected

  EventType eType;

  public

  Func<object,object,object,bool>

  mAction = null;

  public

  FSEvent(string

  name, string

  target, FSState state, FiniteStateMachine owner, FiniteStateMachine.EnterState e, FiniteStateMachine.PushState pu, FiniteStateMachine.PopState po) {

  mStateOwner

  = state;

  mEventName

  = name;

  mTargetState

  = target;

  mOwner

  = owner;

  eType

  = EventType.NONE;

  mEnterDelegate

  = e;

  mPushDelegate

  = pu;

  mPopDelegate

  = po;

  }

  public

  FSState Enter(string

  stateName) {

  mTargetState

  = stateName;

  eType

  = EventType.ENTER;

  return

  mStateOwner;

  }

  public

  FSState Push(string

  stateName) {

  mTargetState

  = stateName;

  eType

  = EventType.PUSH;

  return

  mStateOwner;

  }

  public

  void

  Pop() {

  eType

  = EventType.POP;

  }

  public

  void

  Execute(object

  o1,object

  o2,object

  o3) {

  if

  (eType == EventType.POP) {

  mPopDelegate();

  }

  else

  if

  (eType == EventType.PUSH) {

  mPushDelegate(mTargetState,

  mOwner.CurrentState.StateName);

  }

  else

  if

  (eType == EventType.ENTER) {

  mEnterDelegate(mTargetState);

  }

  else

  if

  (mAction != null)

  {

  mAction(o1,

  o2, o3);

  }

  }

  }

  设计四把FSM常用的类已经封装好了,接下来我们会在设计五中去封装一个EventSystem类。用于处理事件的注册,分发等功能。

  架构系列之- FSM有限状态机设计五

  在设计五中,我们把事件系统EventSystem实现一下。这个EventSystem类主要实现的是事件的注册,触发,以及分发Event消息的作用。提供接口对外使用的。在这里面为了功能扩展方便用了好多模板函数,方便大家调用。

  分发消息的时候,我们采用的是队列的方式,就是先进先出原则。

  首先要把消息事件注册一下,就是将其放到我们预先定义的表里面。函数代码如下所示:



  <font

  face="微软雅黑"><font

  size="3"><font

  color="#000000">

  int

  Register(string

  eventName, Func<object,object,object,bool>

  action) {

  int

  listenID = ++mNextListenID;

  Listen

  listen = (mFreeListen.Count == 0) ? new

  Listen() : mFreeListen.Pop();

  listen.mID

  = listenID;

  listen.mAction

  = action;

  mRegistered.Add(listenID,

  listen);

  List<int>

  eventList;

  if(!mRegisteredEvents.TryGetValue(eventName,

  out

  eventList))

  eventList

  = mRegisteredEvents[eventName] = new

  List<int>();

  eventList.Add(listenID);

  return

  listenID;

  }</font></font></font>

  接下来就是 消息事件的触发代码如下:

  public void Trigger(string eventName) {

  Call(eventName, null, null, null);

  }

  void Call(string eventName, object arg1, object arg2, object arg3) {

  List<int> listenerList;

  if(mRegisteredEvents.TryGetValue(eventName, out listenerList)) {

  for(int i = listenerList.Count - 1; i >= 0; --i) {

  Listen listener;

  if(mRegistered.TryGetValue(listenerList, out listener)) {

  if(!listener.mAction(arg1, arg2, arg3)) {

  mRegistered.Remove(listenerList);

  mFreeListen.Push(listener);

  listenerList.RemoveAt(i);

  }

  }

  else {

  listenerList.RemoveAt(i);

  }

  }

  if(listenerList.Count == 0) {

  mRegisteredEvents.Remove(eventName);

  }

  }

  }

  遍历查找消息列表是否在mRegistererdEvents这个字典里面,mRegisteredEvents的定义如下:

  Dictionary<string,List<int>>  mRegisteredEvents = new Dictionary<string, List<int>>();

  Listen的定义如下:

  class Listen {

  public int        mID;

  public Func<object,object,object,bool> mAction;

  }

  接下来就是最核心的功能了,状态机的切换功能代码:

  [C#] 纯文本查看 复制代码

  ?

  01

  02

  03

  04

  05

  06

  07

  08

  09

  10

  11

  12

  13

  14

  15

  16

  17

  18

  19

  20

  <i><i>public

  int

  On<T1,T2>(string

  eventName, Func<T1,T2,bool>

  action) {

  return

  Register(eventName, delegate(object

  arg1, object

  arg2, object

  arg3) {

  T1

  param1;

  T2

  param2;

  try

  { param1 = (T1)arg1; } catch

  { param1 = default(T1);

  }

  try

  { param2 = (T2)arg2; } catch

  { param2 = default(T2);

  }

  return(action(param1,

  param2));

  });

  }

  public

  int

  On<T1,T2>(string

  eventName, Action<T1,T2> action) {

  return

  Register(eventName, delegate(object

  arg1, object

  arg2, object

  arg3) {

  T1

  param1;

  T2

  param2;

  try

  { param1 = (T1)arg1; } catch

  { param1 = default(T1);

  }

  try

  { param2 = (T2)arg2; } catch

  { param2 = default(T2);

  }

  action(param1,

  param2);

  return

  true;

  });

  }</i></i>

  整个的EventSystem事件系统的代码如下所示:


  <i><i>using

  System;

  using

  System.Collections;

  using

  System.Collections.Generic;

  namespace

  EventSystem {

  public

  class

  Dispatcher {

  public

  void

  Trigger(string

  eventName) {

  Call(eventName,

  null,

  null,

  null);

  }

  public

  void

  Dispatch(string

  eventName) {

  Dispatched

  d = (mFreeDispatch.Count == 0) ? new

  Dispatched() : mFreeDispatch.Pop();

  mDispatched.Enqueue(d.Set(eventName));

  }

  public

  int

  On(string

  eventName, Func<bool>

  action) {

  return

  Register(eventName, delegate(object

  arg1, object

  arg2, object

  arg3) {

  return(action());

  });

  }

  public

  int

  On(string

  eventName, Action action) {

  return

  Register(eventName, delegate(object

  arg1, object

  arg2, object

  arg3) {

  action();

  return(true);

  });

  }

  public

  void

  Trigger(string

  eventName, object

  param1) {

  Call(eventName,

  param1, null,

  null);

  }

  public

  void

  Dispatch(string

  eventName, object

  param1) {

  Dispatched

  d = (mFreeDispatch.Count == 0) ? new

  Dispatched() : mFreeDispatch.Pop();

  mDispatched.Enqueue(d.Set(eventName,

  param1));

  }

  public

  int

  On<T>(string

  eventName, Func<T,bool>

  action) {

  return

  Register(eventName, delegate(object

  arg1, object

  arg2, object

  arg3) {

  T

  param1;

  try

  { param1 = (T)arg1; } catch

  { param1 = default(T);

  }

  return(action(param1));

  });

  }

  public

  int

  On<T>(string

  eventName, Action<T> action) {

  return

  Register(eventName, delegate(object

  arg1, object

  arg2, object

  arg3) {

  T

  param1;

  try

  { param1 = (T)arg1; } catch

  { param1 = default(T);

  }

  action(param1);

  return

  true;

  });

  }

  public

  void

  Trigger(string

  eventName, object

  param1, object

  param2) {

  Call(eventName,

  param1, param2, null);

  }

  public

  void

  Dispatch(string

  eventName, object

  param1, object

  param2) {

  Dispatched

  d = (mFreeDispatch.Count == 0) ? new

  Dispatched() : mFreeDispatch.Pop();

  mDispatched.Enqueue(d.Set(eventName,

  param1, param2));

  }

  public

  int

  On<T1,T2>(string

  eventName, Func<T1,T2,bool>

  action) {

  return

  Register(eventName, delegate(object

  arg1, object

  arg2, object

  arg3) {

  T1

  param1;

  T2

  param2;

  try

  { param1 = (T1)arg1; } catch

  { param1 = default(T1);

  }

  try

  { param2 = (T2)arg2; } catch

  { param2 = default(T2);

  }

  return(action(param1,

  param2));

  });

  }

  public

  int

  On<T1,T2>(string

  eventName, Action<T1,T2> action) {

  return

  Register(eventName, delegate(object

  arg1, object

  arg2, object

  arg3) {

  T1

  param1;

  T2

  param2;

  try

  { param1 = (T1)arg1; } catch

  { param1 = default(T1);

  }

  try

  { param2 = (T2)arg2; } catch

  { param2 = default(T2);

  }

  action(param1,

  param2);

  return

  true;

  });

  }

  public

  void

  Trigger(string

  eventName, object

  param1, object

  param2, object

  param3) {

  Call(eventName,

  param1, param2, param3);

  }

  public

  void

  Dispatch(string

  eventName, object

  param1, object

  param2, object

  param3){

  Dispatched

  d = (mFreeDispatch.Count == 0) ? new

  Dispatched() : mFreeDispatch.Pop();

  mDispatched.Enqueue(d.Set(eventName,

  param1, param2, param3));

  }

  public

  int

  On<T1,T2,T3>(string

  eventName, Func<T1,T2,T3,bool>

  action) {

  return

  Register(eventName, delegate(object

  arg1, object

  arg2, object

  arg3) {

  T1

  param1;

  T2

  param2;

  T3

  param3;

  try

  { param1 = (T1)arg1; } catch

  { param1 = default(T1);

  }

  try

  { param2 = (T2)arg2; } catch

  { param2 = default(T2);

  }

  try

  { param3 = (T3)arg3; } catch

  { param3 = default(T3);

  }

  return(action(param1,

  param2, param3));

  });

  }

  public

  int

  On<T1,T2,T3>(string

  eventName, Action<T1,T2,T3> action) {

  return

  Register(eventName, delegate(object

  arg1, object

  arg2, object

  arg3) {

  T1

  param1;

  T2

  param2;

  T3

  param3;

  try

  { param1 = (T1)arg1; } catch

  { param1 = default(T1);

  }

  try

  { param2 = (T2)arg2; } catch

  { param2 = default(T2);

  }

  try

  { param3 = (T3)arg3; } catch

  { param3 = default(T3);

  }

  action(param1,

  param2, param3);

  return

  true;

  });

  }

  public

  bool

  Cancel(int

  listenerID) {

  return

  mRegistered.Remove(listenerID);

  }

  public

  void

  DispatchPending() {

  while(mDispatched.Count

  > 0) {

  Dispatched

  d = mDispatched.Dequeue();

  Call(d.mEventName,

  d.mArg1, d.mArg2, d.mArg3);

  mFreeDispatch.Push(d);

  }

  }

  int

  Register(string

  eventName, Func<object,object,object,bool>

  action) {

  int

  listenID = ++mNextListenID;

  Listen

  listen = (mFreeListen.Count == 0) ? new

  Listen() : mFreeListen.Pop();

  listen.mID

  = listenID;

  listen.mAction

  = action;

  mRegistered.Add(listenID,

  listen);

  List<int>

  eventList;

  if(!mRegisteredEvents.TryGetValue(eventName,

  out

  eventList))

  eventList

  = mRegisteredEvents[eventName] = new

  List<int>();

  eventList.Add(listenID);

  return

  listenID;

  }

  void

  Call(string

  eventName, object

  arg1, object

  arg2, object

  arg3) {

  List<int>

  listenerList;

  if(mRegisteredEvents.TryGetValue(eventName,

  out

  listenerList)) {

  for(int

  i = listenerList.Count - 1; i >= 0; --i) {

  Listen

  listener;

  if(mRegistered.TryGetValue(listenerList[i],

  out

  listener)) {

  if(!listener.mAction(arg1,

  arg2, arg3)) {

  mRegistered.Remove(listenerList[i]);

  mFreeListen.Push(listener);

  listenerList.RemoveAt(i);

  }

  }

  else

  {

  listenerList.RemoveAt(i);

  }

  }

  if(listenerList.Count

  == 0) {

  mRegisteredEvents.Remove(eventName);

  }

  }

  }

  class

  Listen {

  public

  int

  mID;

  public

  Func<object,object,object,bool>

  mAction;

  }

  class

  Dispatched {

  public

  Dispatched Set(string

  eventName, object

  arg1=null,

  object

  arg2=null,

  object

  arg3=null)

  {

  mEventName

  = eventName;

  mArg1

  = arg1;

  mArg2

  = arg2;

  mArg3

  = arg3;

  return

  this;

  }

  public

  string

  mEventName;

  public

  object

  mArg1, mArg2, mArg3;

  }

  Dictionary<string,List<int>>

  mRegisteredEvents = new

  Dictionary<string,

  List<int>>();

  Dictionary<int,Listen>

  mRegistered = new

  Dictionary<int,

  Listen>();

  Stack<Listen>

  mFreeListen = new

  Stack<Listen>();

  Stack<Dispatched>

  mFreeDispatch = new

  Stack<Dispatched>();

  Queue<Dispatched>

  mDispatched = new

  Queue<Dispatched>();

  int

  mNextListenID = 4711;

  }

  }</i></i>

  接下来我会在最后一讲也就是设计六中,给大家说一下如何去使用。

  Unity3D架构系列之- FSM有限状态机设计六

  由于最近一直赶项目进度,没时间写,昨晚终于项目终于完成了,空闲下来,做一个总结。在这一篇中主要是把前五章一起总结一下,以及通过举例演示如何使用?有限状态机在游戏中使用的地方非常多,比如我们界面之间的切换,角色的状态切换等等。所以非常值得大家去学习一下,接下来我们主要实现的功能,为了表达清楚,我通过图例给大家说明一下:

  给大家解析一下,程序运行首先进入主菜单,里面有三个按钮,开始游戏,音量,退出游戏。先从第一个说起,如果是开始游戏,它会进入到下一个界面游戏界面,游戏界面有个返回主菜单功能。二者可以互相切换。接下来是音量按钮,整个按钮是调节音量的,调节好了后,点确认和取消都是返回主菜单。二者之间互相切换,最后一个是退出游戏,会进入是否退出界面,如果否,返回主界面,如果是真正的关闭游戏。我们就把这个简单的功能用我们的有限状态机实现一下:

  首先我们声明两个对象:

  public static EventSystem.Dispatcher Events = new EventSystem.Dispatcher();

  public FiniteStateMachine FSM = new FiniteStateMachine();

  events主要是创建一个全局的事件系统用于我们指定的UI。

  FSM是作为一个状态机被驱动。

  接下来我们注册几个状态用我们的状态机:

  FSM.Register("MainMenu", new MainMenuUI());

  FSM.Register("AudioMenu", new AudioMenuUI());

  FSM.Register("MainGame", new MainGame(FSM));

  FSM.Register("QuitGame", new QuitGameUI());

  我们用EntryPoint告诉玩家我们第一个界面是主界面:

  FSM.EntryPoint("MainMenu");

  我们为主界面定义几个actions,OPEN_AUDIO,PLAY_GAME, QUIT_GAME.其中OPEN_AUDIO和QUIT_GAME用于取代顶部栈的状态。PLAY_GAME用于增加状态栈新的item。代码如下:

  FSM.State("MainMenu").On("OPEN_AUDIO").Enter("AudioMenu")

  .On("PLAY_GAME").Push("MainGame")

  .On("QUIT_GAME").Enter("QuitGame");

  退出菜单响应PROCESS_QUIT action。代码如下:

  FSM.State("QuitGame").On("PROCESS_QUIT", delegate(bool sure) {

  if (sure) {

  gameObject.GetComponent<TestUIState>().enabled = false;

  Camera.main.backgroundColor = Color.black;

  } else { FSM.Enter("MainMenu"); }

  });

  上述代码主要实现的功能:如果确认游戏结束,否则返回主菜单。

  游戏类是负责对于主菜单弹出栈顶元素的。

  <font

  face="微软雅黑"><font

  size="3"><font

  color="#000000">using

  UnityEngine;

  using

  System.Collections;

  class

  MainGame : MenuUI, IState {

  protected

  FiniteStateMachine FSM;

  protected

  float

  Score = 0;

  public

  MainGame(FiniteStateMachine parentMachine) {

  FSM

  = parentMachine;

  }

  public

  void

  OnEnter(string

  prevState) {

  Score

  = 0;

  }

  public

  void

  OnExit(string

  nextState) {

  }

  public

  void

  OnUpdate() {

  }

  public

  override

  void

  DoGUI() {

  if

  (GUILayout.Button("Quit

  / Back To Menu",

  GUILayout.Width(Screen.width))) {

  FSM.Pop();

  }

  GUILayout.Space(25);

  GUILayout.Label("The

  waiting game!");

  GUILayout.Space(25);

  GUILayout.Label("CurrentScore:

  "

  + System.Convert.ToInt32(Score));

  Score

  += Time.deltaTime;

  }

  }</font></font></font>

  声音菜单保留它自己的状态,处理音量逻辑。代码如下:

  SM.State("AudioMenu").On("BACK_TO_MENU").Enter("MainMenu");

  最后将每一个事件系统挂到状态机的actions里面,代码如下:

  Events.On("OpenMainGame", delegate() { FSM.CurrentState.Trigger("PLAY_GAME"); });

  Events.On("OpenAudioMenu", delegate() { FSM.CurrentState.Trigger("OPEN_AUDIO"); });

  Events.On("QuitGame", delegate() { FSM.CurrentState.Trigger("QUIT_GAME"); });

  Events.On("ConfirmQuit", delegate() { FSM.CurrentState.Trigger("PROCESS_QUIT", true); });

  Events.On("CancelQuit", delegate() { FSM.CurrentState.Trigger("PROCESS_QUIT", false); });

  Events.On("BackToMenu", delegate() { FSM.CurrentState.Trigger("BACK_TO_MENU", false); });

  大家可能会问,状态机是如何切换的,我们将在Update里面实现,代码很简单:

  public void Update() {

  FSM.Update();

  }

  这样就可以每一帧都可以进行检测push还是top状态机了。

  为了响应主界面我们定义了一个OnGUI函数:

  void OnGUI() {

  if (FSM.CurrentState == null)

  return;

  MenuUI ui = (MenuUI)FSM.CurrentState.StateObject;

  ui.DoGUI();

  }

  最后因为我们涉及到主界面各个操作,所以它们都有自己的类。

  我将它们都拿出来给大家分享:

  主菜单中声音菜单的逻辑代码如下:

  using UnityEngine;

  using System.Collections;

  class AudioMenuUI : MenuUI, IState {

  float volume = 0.5f;

  float backupVolume = 0.0f;

  public void OnEnter(string prevState) {

  backupVolume = volume;

  }

  public void OnExit(string nextState) {

  }

  public void OnUpdate() {

  }

  public override void DoGUI() {

  GUILayout.Space(25.0f);

  volume = GUILayout.HorizontalSlider(volume, 0.0f, 1.0f, GUILayout.Width(Screen.width));

  GUILayout.BeginHorizontal();

  GUILayout.FlexibleSpace();

  GUILayout.Label("Volume: " + System.Convert.ToInt32(volume * 100.0f) + " %");

  GUILayout.FlexibleSpace();

  GUILayout.EndHorizontal();

  GUILayout.BeginHorizontal();

  if (GUILayout.Button("Cancel", GUILayout.Height(75.0f))) {

  volume = backupVolume;

  TestUIState.Events.Trigger("BackToMenu");

  }

  if (GUILayout.Button("Confirm", GUILayout.Height(75.0f))) {

  TestUIState.Events.Trigger("BackToMenu");

  }

  GUILayout.EndHorizontal();

  }

  }

  主菜单类逻辑代码如下:

  using UnityEngine;

  using System.Collections;

  public class MainMenuUI : MenuUI, IState {

  public void OnEnter(string prevState) {

  }

  public void OnExit(string nextState) {

  }

  public void OnUpdate() {

  }

  public override void DoGUI() {

  if (GUILayout.Button("Play Game", GUILayout.Width(Screen.width), GUILayout.Height(Screen.height / 3))) {

  TestUIState.Events.Trigger("OpenMainGame");

  }

  if (GUILayout.Button("Audio Menu", GUILayout.Width(Screen.width), GUILayout.Height(Screen.height / 3))) {

  TestUIState.Events.Trigger("OpenAudioMenu");

  }

  if (GUILayout.Button("Quit Game", GUILayout.Width(Screen.width), GUILayout.Height(Screen.height / 3))) {

  TestUIState.Events.Trigger("QuitGame");

  }

  }

  }

  我们定义了一个菜单操作的抽象类用于继承:

  using UnityEngine;

  using System.Collections;

  public class MenuUI {

  public virtual void DoGUI() {

  }

  }

  游戏退出类代码如下:

  using UnityEngine;

  using System.Collections;

  class QuitGameUI : MenuUI, IState {

  public void OnEnter(string prevState) {

  }

  public void OnExit(string nextState) {

  }

  public void OnUpdate() {

  }

  public override void DoGUI() {

  GUILayout.BeginHorizontal();

  if (GUILayout.Button("Confirm", GUILayout.Width(Screen.width / 2), GUILayout.Height(Screen.height))) {

  TestUIState.Events.Trigger("ConfirmQuit");

  }

  if (GUILayout.Button("Cancel", GUILayout.Width(Screen.width / 2), GUILayout.Height(Screen.height))) {

  TestUIState.Events.Trigger("CancelQuit");

  }

  GUILayout.EndHorizontal();

  }

  }

  最后只要将下面的脚本挂到对象上就可以了:

  using UnityEngine;

  using System.Collections;

  public class TestUIState : MonoBehaviour {

  public static EventSystem.Dispatcher Events = new EventSystem.Dispatcher();

  public FiniteStateMachine FSM = new FiniteStateMachine();

  public void Awake() {

  FSM.Register("MainMenu", new MainMenuUI());

  FSM.Register("AudioMenu", new AudioMenuUI());

  FSM.Register("MainGame", new MainGame(FSM));

  FSM.Register("QuitGame", new QuitGameUI());

  FSM.EntryPoint("MainMenu");

  FSM.State("MainMenu").On("OPEN_AUDIO").Enter("AudioMenu")

  .On("PLAY_GAME").Push("MainGame")

  .On("QUIT_GAME").Enter("QuitGame");

  FSM.State("QuitGame").On("PROCESS_QUIT", delegate(bool sure) {

  if (sure) {

  gameObject.GetComponent<TestUIState>().enabled = false;

  Camera.main.backgroundColor = Color.black;

  } else { FSM.Enter("MainMenu"); }

  });

  FSM.State("AudioMenu").On("BACK_TO_MENU").Enter("MainMenu");

  Events.On("OpenMainGame", delegate() { FSM.CurrentState.Trigger("PLAY_GAME"); });

  Events.On("OpenAudioMenu", delegate() { FSM.CurrentState.Trigger("OPEN_AUDIO"); });

  Events.On("QuitGame", delegate() { FSM.CurrentState.Trigger("QUIT_GAME"); });

  Events.On("ConfirmQuit", delegate() { FSM.CurrentState.Trigger("PROCESS_QUIT", true); });

  Events.On("CancelQuit", delegate() { FSM.CurrentState.Trigger("PROCESS_QUIT", false); });

  Events.On("BackToMenu", delegate() { FSM.CurrentState.Trigger("BACK_TO_MENU", false); });

  }

  public void Update() {

  FSM.Update();

  }

  void OnGUI() {

  if (FSM.CurrentState == null)

  return;

  MenuUI ui = (MenuUI)FSM.CurrentState.StateObject;

  ui.DoGUI();

  }

  }

  测试用的代码一共有AudioMenUI.cs    MainGame.cs  MainMenuUI.cs MenuUI.cs  QuitGameUI.cs  TestUIState.cs.大家只要将TestUIStat.cs挂到对象上就可以运行了。在使用的过程中可以先调试一下,前五章是给大家封装的,可以直接将其运用到项目中。这里的类只是跟大家分享一下如何去运用。

  有限状态机到这里就全部结束了。有什么问题欢迎一起讨论。接下来我会给大家分享其他技术点。。。。。

[发帖际遇]: BobbyKim 发帖时在路边捡到 1 蛮牛币,偷偷放进了口袋. 幸运榜 / 衰神榜

回复

使用道具 举报

6蛮牛粉丝
1429/1500
排名
953
昨日变化

4

主题

145

帖子

1429

积分

Rank: 6Rank: 6Rank: 6

UID
48056
好友
2
蛮牛币
3920
威望
0
注册时间
2014-10-9
在线时间
419 小时
最后登录
2017-3-29
发表于 2016-9-19 20:32:17 | 显示全部楼层
直接复制别人的啊

回复 支持 反对

使用道具 举报

7日久生情
1620/5000
排名
807
昨日变化
3

0

主题

152

帖子

1620

积分

Rank: 7Rank: 7Rank: 7Rank: 7

UID
122176
好友
9
蛮牛币
2470
威望
0
注册时间
2015-9-11
在线时间
528 小时
最后登录
2017-7-22
发表于 2017-6-12 11:21:45 | 显示全部楼层
一直都在做很简单浅显的项目,都用不到这些东西,但是自己很想学,怎么办

回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 注册帐号

本版积分规则

快速回复 返回顶部 返回列表