本系列笔记转载自游戏蛮牛专栏作家Jackel的论坛文章,详细介绍了FSM的创建与使用,特与众分享。链接:http://www.manew.com/thread-37136-1-1.html
一、实例图例
该实例主要是按钮状态的转换。
给大家解析一下,程序运行首先进入主菜单,里面有三个按钮,开始游戏,音量,退出游戏。先从第一个说起,如果是开始游戏,它会进入到下一个界面游戏界面,游戏界面有个返回主菜单功能。二者可以互相切换。接下来是音量按钮,整个按钮是调节音量的,调节好了后,点确认和取消都是返回主菜单。二者之间互相切换,最后一个是退出游戏,会进入是否退出界面,如果否,返回主界面,如果是真正的关闭游戏。我们就把这个简单的功能用我们的有限状态机实现一下:
二、文件结构
左图是有限状态机的代码,共5个,右侧是实例的代码,共6个。下面给出有图的6个文件源码:
一、代码
1、AudioMenuUI
using System.Collections;
public class AudioMenuUI : MenuUI, IState
{
public void OnEnter( string nextState )
{
}
public void OnExit( string nextState )
{
}
public void OnUpdate()
{
}
public override void DoGUI()
{
if( GUILayout.Button( "Back to menu", GUILayout.Width( Screen.width ), GUILayout.Height( Screen.height / 2 )))
{
TestUIState.Events.Trigger( "BackToMenu" );
}
// if( GUILayout.Button( "CloseAudio", GUILayout.Width( Screen.width ), GUILayout.Height( Screen.height / 2 )))
// {
// TestUIState.Events.Trigger( "CancelQuit" );
// }
}
}
2、MainGame
using UnityEngine;
using System.Collections;
public class MainGame : MenuUI, IState
{
protected FiniteStateMachine FSM;
protected float Score = 0f;
public MainGame( FiniteStateMachine parentMachine )
{
FSM = parentMachine;
}
public void OnEnter( string prevState )
{
Score = 0f;
}
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;
}
}
3、MainMenuUI
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" );
}
}
}
4、MenuUI
using UnityEngine;
using System.Collections;
public class MenuUI
{
public virtual void DoGUI()
{
}
}
5、QuitGameUI
using UnityEngine;
using System.Collections;
public 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();
}
}
6、TestUIState
using UnityEngine;
using System.Collections;
public class TestUIState : MonoBehaviour
{
public static EventSystem.Dispatcher Events = new EventSystem.Dispatcher();
public FiniteStateMachine FSM = new FiniteStateMachine();
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 );
});
}
void Update()
{
FSM.Update();
}
void OnGUI()
{
if( FSM.CurrentState == null )
{
return;
}
MenuUI ui = (MenuUI)FSM.CurrentState.StateObject;
ui.DoGUI();
}
}
二、使用
只需把TestUIState挂在场景的一个对象中即可。
代码:http://pan.baidu.com/s/1c0x1dMK