unity3d 有限状态机 例子

2015年01月22日 10:08 0 点赞 0 评论 更新于 2025-11-21 15:05

本文将分享一个Unity3D有限状态机的例子,供大家学习、参考和交流。在游戏开发中,状态机是一种常用的设计模式,下面我们先来看一个简单的状态机实现示例,代码如下:

// 定义状态类型的枚举
enum State_Type
{
GameMenu,
GameLoading,
GameLogic,
GameOver
}

// 当前状态
State_Type currentstate;

void Update()
{
switch (currentstate)
{
case State_Type.GameMenu:
// 模拟按了开始按钮
if (Input.GetKeyDown(KeyCode.Space))
{
currentstate = State_Type.GameLoading;
}
// 模拟按了成就
if (Input.GetKeyDown(KeyCode.A))
{
// 这里应补充具体状态
// currentstate = State_Type......;
}
// 模拟按了高分榜
if (Input.GetKeyDown(KeyCode.H))
{
// 这里应补充具体状态
// currentstate = State_Type......;
}
break;
case State_Type.GameLoading:
// 模拟加载游戏完成
if (/* 加载完成的条件 */ true)
{
currentstate = State_Type.GameLogic;
}
break;
case State_Type.GameLogic:
// 模拟角色死亡
if (/* 死亡的条件 */ true)
{
currentstate = State_Type.GameOver;
}
break;
case State_Type.GameOver:
currentstate = State_Type.GameMenu;
break;
}
}

这种简单的switch语句实现的状态机在状态较少时是可行的,但当状态数量增多时,代码会变得难以维护和扩展,会让人头疼。接下来,我们介绍一种使用有限状态机(FSM)的方法来解决这个问题。

两个实体的有限状态机实现

实体一:ActorOne

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()方法

// 设置当前的状态为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);
}
}

实体二:ActorTwo

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

ActorOne的状态实现

全局状态:ActorOne_GloballState

using UnityEngine;
using System.Collections;

/*
状态分为两种
1. 全局状态 一般情况下会一直执行 可以负责调度
2. 普通状态 也就是上面的GameMenu, GameLoading, GameLogic, GameOver
*/
// 全局状态
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;
}
}

普通状态:ActorOne_StateOne

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状态;
*/
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;
}
}

普通状态:ActorOne_StateTwo

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
*/
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的全局状态

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)
{
return false;
}
}

通过上述代码,我们展示了如何使用有限状态机来管理实体的状态,这种方式可以让代码更加模块化、可维护和可扩展,避免了简单switch语句在状态增多时带来的问题。在实际开发中,你可以根据具体需求对状态机和状态进行进一步的扩展和优化。