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

扫一扫,访问微社区

教程分享

关注:620

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

查看: 851|回复: 1

[基础知识] 基于unity3d(C#)的有限状态机设计(二)

[复制链接]  [移动端链接]
抢楼 抢楼 本帖为抢楼帖,欢迎抢楼! 
8常驻蛮牛
9843/10000
排名
386
昨日变化
3

3421

主题

3691

帖子

9843

积分

Rank: 8Rank: 8

UID
1235
好友
168
蛮牛币
174741
威望
110
注册时间
2013-7-29
在线时间
432 小时
最后登录
2016-10-9

社区QQ达人游戏蛮牛QQ群会员蛮牛妹

发表于 2015-11-15 11:00:00 | 显示全部楼层 |阅读模式

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

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

x
  我们一般游戏中都是这样使用状态机的

[AppleScript] 纯文本查看 复制代码
  [csharp] view plaincopy

  enum State_Type

  {

  GameMenu,

  GameLoading,

  GameLogic,

  GameOver,

  }

  void Update()

  {

  switch(currentstate)

  {

  case State_Type. GameMenu:

  if( 按了开始按钮 )

  {

  currentstate=State_Type. GameLoading;

  }

  if( 按了成就 )

  {

  currentstate=State_Type……..;

  }

  if(按了高分榜)

  {

  currentstate=State_Type……..;

  }

  break;

  case State_Type. GameLoading:

  if( 加载游戏完成 )

  {

  currentstate=State_Type. GameLogic;

  }

  break;

  case State_Type. GameLogic:

  if( 死了 )

  {

  currentstate=State_Type. GameOver;

  }

  break;

  case State_Type. GameOver:

  currentstate=State_Type. GameMenu;

  break;

  }

  }


  这样写没有什么问题。不过当状态多的时候确实很头疼。

  有一种方法可以解决这样的问题(有限状态机FSM)

  下面是一个例子

  两个实体

  ActorOne

  ActorTwo

  第一个实体ActorOne

[AppleScript] 纯文本查看 复制代码
  [csharp] view plaincopy

  using UnityEngine;

  using System.Collections;

  public class ActorOne  : BaseGameEntity {

  //有限状态机

  StateMachine<ActorOne> m_pStateMachine;

  void Start () {

  //设置实体的id必须唯一

  SetID((int)EntityID.m_ActorOne);

  //注册

  m_pStateMachine = new StateMachine<ActorOne>(this);

  /*

  一个状态分为三个阶段

  Enter()       //进入

  Execute() //执行

  Exit()           //离开


  当m_pStateMachine.SetCurrentState(ActorOne_StateOne .Instance());

  会先执行ActorOne_StateOne 的Enter()方法,

  然后执行ActorOne_StateOne 的Execute()方法, Execute方法会一直执行直到切换状态

  当在ActorOne_StateOne(Enter(), Execute())中调用Entity.GetFSM().ChangeState(ActorOne_StateTwo.Instance());

  会先执行ActorOne_StateOne 的Exit();

  然后执行ActorOne_StateTwo的Enter()方法,

  然后执行ActorOne_StateTwo的Execute()方法,

[AppleScript] 纯文本查看 复制代码
  */

  //设置当前的状态为ActorOne_StateOne

  m_pStateMachine.SetCurrentState(ActorOne_StateOne .Instance());

  //设置全局的状态

  m_pStateMachine.SetGlobalStateState(ActorOne_GloballState .Instance());

  //实体注册到实体管理器中

  EntityManager.Instance().RegisterEntity(this);

  }

  void Update ()

  {

  //状态机update

  m_pStateMachine.SMUpdate();

  }

  public StateMachine<ActorOne> GetFSM ()

  {

  //获得状态机

  return m_pStateMachine;

  }

  public override bool HandleMessage (Telegram telegram)

  {

  //解析消息

  return     m_pStateMachine.HandleMessage(telegram);

  }

  }


  第2个实体ActorTwo

[AppleScript] 纯文本查看 复制代码
  [csharp] view plaincopy

  using UnityEngine;

  using System.Collections;

  public class ActorTwo  : BaseGameEntity {

  StateMachine<ActorTwo> m_pStateMachine;

  public Transform TwoTransform;

  // Use this for initialization

  void Start () {

  // set id

  SetID((int)EntityID.m_ActorTwo);

  m_pStateMachine = new StateMachine<ActorTwo>(this);

  m_pStateMachine.SetCurrentState(ActorTwo_StateOne.Instance());

  m_pStateMachine.SetGlobalStateState(ActorTwo_GloballState.Instance());

  EntityManager.Instance().RegisterEntity(this);

  }

  void Update ()

  {

  m_pStateMachine.SMUpdate();

  }

  public StateMachine<ActorTwo> GetFSM ()

  {

  return m_pStateMachine;

  }

  public override bool HandleMessage (Telegram telegram)

  {

  return     m_pStateMachine.HandleMessage(telegram);

  }

  }

  ActorOneState 第一个实体的状态

  [csharp] view plaincopy

  using UnityEngine;

  using System.Collections;

  /*


  状态分为两种

  1全局状态 一般情况下会一直执行 可以负责调度

  2普通状态 也就是上面的GameMenu,GameLoading,GameLogic,GameOver,

[AppleScript] 纯文本查看 复制代码
  */

  //全局状态

  public class ActorOne_GloballState :State<ActorOne >

  {

  private static ActorOne_GloballState instance;

  public static ActorOne_GloballState Instance ()

  {

  if (instance == null)

  instance = new ActorOne_GloballState ();

  return instance;

  }

  //当状态被调用是执行一次

  public override void Enter (ActorOne Entity)

  {

  //base.Enter (Entity);

  }

  //相当于update方法

  public override void Execute (ActorOne Entity)

  {

  //base.Execute (Entity);

  }

  //状态退出是被调用

  public override void Exit (ActorOne Entity)

  {

  //base.Exit (Entity);

  }

  //接收消息

  public override bool OnMessage (ActorOne Entity, Telegram telegram)

  {

  return false;

  }

  }

  public class ActorOne_StateOne : State<ActorOne>

  {

  private static ActorOne_StateOne instance;

  public static ActorOne_StateOne Instance ()

  {

  if (instance == null)

  instance = new ActorOne_StateOne ();

  return instance;

  }

  public override void Enter (ActorOne Entity)

  {

  //base.Enter (Entity);

  }

  public override void Execute (ActorOne Entity)

  {

  /*


  调用实体的GetFSM()获得状态机器

  在调用状态机的ChangeState(ActorOne_StateTwo.Instance())

  改变状态

  这里是从当前状态ActorOne_StateOne切换到ActorOne_StateTwo状态;

[AppleScript] 纯文本查看 复制代码
  */

  Entity.GetFSM().ChangeState(ActorOne_StateTwo.Instance());

  //base.Execute (Entity);

  }

  public override void Exit (ActorOne Entity)

  {

  //base.Exit (Entity);

  }

  public override bool OnMessage (ActorOne Entity, Telegram telegram)

  {

  return false;

  }

  }

  public class ActorOne_StateTwo : State<ActorOne>

  {

  private static ActorOne_StateTwo instance;

  public static ActorOne_StateTwo Instance ()

  {

  if (instance == null)

  instance = new ActorOne_StateTwo ();

  return instance;

  }

  public override void Enter (ActorOne Entity)

  {

  /*


  MessageDispatcher.Instance().DispatchMessage();用于在实体间传送消息

  下面代码的意思就是

  发送消息给ActorTwo,延迟5秒发送,消息的类型msg_oneMessage

[AppleScript] 纯文本查看 复制代码
  */

  MessageDispatcher.Instance().DispatchMessage(

  5f, // delay 消息的延迟时间

  Entity.ID(),        // sender 发送者

  (int)EntityID.m_ActorTwo,            // receiver 接收者

  (int)message_type.msg_oneMessage,    //message

  Entity);  //附加信息

  //base.Enter (Entity);

  }

  public override void Execute (ActorOne Entity)

  {

  //base.Execute (Entity);

  }

  public override void Exit (ActorOne Entity)

  {

  //base.Exit (Entity);

  }

  public override bool OnMessage (ActorOne Entity, Telegram telegram)

  {

  /*

  接收ActorTwo发送过来的消息(message_type.msg_twoMessage)

  */

  if(telegram.Msg == (int)message_type.msg_twoMessage)

  {

  /*

  接收成功

  */

  return true;

  }

  return false;

  }

  }

  ActorTwo 第2个实体的具体状态

  [csharp] view plaincopy

  using UnityEngine;

  using System.Collections;

  public class ActorTwo_GloballState : State<ActorTwo>

  {

  private static ActorTwo_GloballState instance;

  public static ActorTwo_GloballState Instance ()

  {

  if (instance == null)

  instance = new ActorTwo_GloballState ();

  return instance;

  }

  public override void Enter (ActorTwo Entity)

  {

  //base.Enter (Entity);

  }

  public override void Execute (ActorTwo Entity)

  {

  //base.Execute (Entity);

  }

  public override void Exit (ActorTwo Entity)

  {

  //base.Exit (Entity);

  }

  //消息处理

  public override bool OnMessage (ActorTwo Entity, Telegram telegram)

  {

  /*

  接收ActorOne发送来的消息(message_type.msg_oneMessage)

  */

  if (telegram.Msg == (int)message_type.msg_oneMessage) {

  /*

  接收成功处理消息从当前状态切换到ActorTwo_StateTwo状态;

  */

  Entity.GetFSM ().ChangeState (ActorTwo_StateTwo.Instance ());

  return true;

  }

  return false;

  }

  }

  public class ActorTwo_StateOne : State<ActorTwo>

  {

  private static ActorTwo_StateOne instance;

  public static ActorTwo_StateOne Instance ()

  {

  if (instance == null)

  instance = new ActorTwo_StateOne ();

  return instance;

  }

  public override void Enter (ActorTwo Entity)

  {

  //base.Enter (Entity);

  }

  public override void Execute (ActorTwo Entity)

  {

  //base.Execute (Entity);

  }

  public override void Exit (ActorTwo Entity)

  {

  //base.Exit (Entity);

  }

  public override bool OnMessage (ActorTwo Entity, Telegram telegram)

  {

  return false;

  }

  }

  public class ActorTwo_StateTwo : State<ActorTwo>

  {

  private static ActorTwo_StateTwo instance;

  public static ActorTwo_StateTwo Instance ()

  {

  if (instance == null)

  instance = new ActorTwo_StateTwo ();

  return instance;

  }

  public override void Enter (ActorTwo Entity)

  {

  /*

  发送消息给ActorOne,延迟1秒,消息类型msg_twoMessage

  */

  MessageDispatcher.Instance ().DispatchMessage(

  1f,

  Entity.ID (),

  (int)EntityID.m_ActorOne,

  (int)message_type.msg_twoMessage,

  Entity);

  //base.Enter (Entity);

  }

  public override void Execute (ActorTwo pMiner)

  {

  //base.Execute (Entity);

  }

  public override void Exit (ActorTwo Entity)

  {

  //base.Exit (Entity);

  }

  public override bool OnMessage (ActorTwo Entity, Telegram telegram)

  {

  return false;

  }

  }



我是一朵内心长满小碎花的女汉子!
回复

使用道具 举报

排名
208
昨日变化
1

24

主题

396

帖子

2996

积分

Rank: 9Rank: 9Rank: 9

UID
10602
好友
15
蛮牛币
6265
威望
0
注册时间
2013-12-18
在线时间
842 小时
最后登录
2017-5-26

专栏作家认证开发者

发表于 2015-5-31 11:33:26 | 显示全部楼层
能不能发一个Demo,光这么看有点生硬

回复

使用道具 举报

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

本版积分规则

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