一.狀態(tài)機
狀態(tài)機
二.個人理解的狀態(tài)機
個人理解的狀態(tài)機.jpg
三.自己搭建一個狀態(tài)機
搭建狀態(tài)機步驟
狀態(tài)機偷溺,管理多個狀態(tài)缘挑,每個狀態(tài)有多個動作盈简,狀態(tài)下動作的改變切換到另一個狀態(tài)
1.創(chuàng)建狀態(tài)機的管理(Manager)
using UnityEngine;
using System.Collections;
namespace SpacePlanner
{
/// <summary>
/// 處理用戶的一些復雜輸入烦绳,并不是全部
/// 尤其是那些一步一步進行的操作
/// </summary>
public class UserInputHandler : MonoBehaviour
{
public bool IsRunning
{
get
{
return fsm != null;
}
}
static UserInputHandler _instance;
public static UserInputHandler Instance
{
get
{
if (_instance == null)
{
GameObject go = new GameObject("UserInputHandler");
_instance = go.AddComponent<UserInputHandler>();
}
return _instance;
}
}
FSM4InputHandler fsm;
void Update()//狀態(tài)機的執(zhí)行入口
{
if (fsm != null)
fsm.Run();
}
public void StartHandleBuildWallInput()
{
fsm = new FSM4InputHandler();
var tmpState = new State(fsm, "StartState");
tmpState.AddAction(new MouseClickToStart("InBuildWallState"));
tmpState.AddAction(new MouseMoveBeforeBuild());
tmpState.AddAction(new MouseRightClickToStop());
fsm.AddState(tmpState);
fsm.curState = tmpState;
tmpState = new State(fsm, "InBuildWallState");
tmpState.AddAction(new MouseRightClickToStop());
tmpState.AddAction(new MouseClickToContinue("StartState"));
tmpState.AddAction(new MouseMoveInBuild());
fsm.AddState(tmpState);
}
// public void StartHandleBuildWallInput()
// {
// fsm = new FSM4InputHandler();
// var tmpState = new State(fsm, "StartState");
// tmpState.AddAction(new MouseClickToStart("InBuildWallState"));
//tmpState.AddAction(new MouseMoveBeforeBuild());
// tmpState.AddAction(new MouseRightClickToStop());
// fsm.AddState(tmpState);
// fsm.curState = tmpState;
// tmpState = new State(fsm, "InBuildWallState");
// tmpState.AddAction(new MouseRightClickToStop());
// tmpState.AddAction(new MouseClickToContinue());
// tmpState.AddAction(new MouseMoveInBuild());
// fsm.AddState(tmpState);
// }
public void StartHandleBuildAreaInput()
{
fsm = new FSM4InputHandler();
//var tmpState = new State(fsm, "StartState");
//tmpState.AddAction(new MoveBeforBuildArea());
//tmpState.AddAction(new ClickToStartBuildArea("InBuildAreaState"));
//fsm.AddState(tmpState);
//fsm.curState = tmpState;
var tmpState = new State(fsm, "InBuildAreaState");
tmpState.AddAction(new MoveInBuildArea());
tmpState.AddAction(new ClickToContinueBuildArea());
tmpState.AddAction(new RightClickToStopBuildArea());
fsm.AddState(tmpState);
fsm.curState = tmpState;
}
public void StartHandleBuildDoorInput()
{
fsm = new FSM4InputHandler();
var tmpState = new State(fsm, "StartState");
tmpState.AddAction(new MouseMoveBeforeAddDoor());
tmpState.AddAction(new MouseClickToAddDoor());
tmpState.AddAction(new MouseRightClickToStopAddDoor());
fsm.AddState(tmpState);
fsm.curState = tmpState;
}
/// <summary>
/// Alan添加的建立戶型狀態(tài)機控制
/// </summary>
public void StartHandleBuildUnitInput()
{
fsm = new FSM4InputHandler();
var tmpState = new State(fsm, "StartState");
tmpState.AddAction(new MouseMoveBeforeAddUnit());
tmpState.AddAction(new MouseClickToAddUnit());
tmpState.AddAction(new MouseRightClickToStopAddUnit());
fsm.AddState(tmpState);
fsm.curState = tmpState;
}
public void StartHandleBuildWinInput()
{
fsm = new FSM4InputHandler();
var tmpState = new State(fsm, "StartState");
tmpState.AddAction(new MouseMoveBeforeBuildWin());
tmpState.AddAction(new MouseClickToBuildWin());
tmpState.AddAction(new MouseRightClickToStopBuildWindow());
fsm.AddState(tmpState);
fsm.curState = tmpState;
}
//public void StartHandleBuildHandrailInput()
//{
// fsm = new FSM4InputHandler();
// var tmpState = new State(fsm, "StartState");
// tmpState.AddAction(new MouseMoveBeforeAddHandrail());
// tmpState.AddAction(new MouseClickToAddHandrail());
// tmpState.AddAction(new MouseRightClickToStopAddHandrail());
// fsm.AddState(tmpState);
// fsm.curState = tmpState;
//}
public void StartHandleBuildPillarInput()
{
fsm = new FSM4InputHandler();
var tmpState = new State(fsm, "StartState");
tmpState.AddAction(new MouseMoveBeforeAddSpaceObject());
tmpState.AddAction(new MouseClickToAddSpaceObject());
tmpState.AddAction(new MouseRightClickToStopAddSpaceObject());
fsm.AddState(tmpState);
fsm.curState = tmpState;
}
public void StartSetApartmentMapMeasureInput()
{
fsm = new FSM4InputHandler();
var tmpState = new State(fsm, "StartState");
tmpState.AddAction(new MouseClickToStartSetMeasure("InSetApartmentMapMeasureState"));
tmpState.AddAction(new MouseRightClickToStopSetMeasure());
fsm.AddState(tmpState);
fsm.curState = tmpState;
tmpState = new State(fsm, "InSetApartmentMapMeasureState");
tmpState.AddAction(new MouseClickToFinishSetMeasure());
tmpState.AddAction(new MouseRightClickToStopSetMeasure());
tmpState.AddAction(new MouseMoveInSetMeasure());
fsm.AddState(tmpState);
}
具體分析這個狀態(tài)機的例子
1.2個狀態(tài)"StartState"狀態(tài),"InBuildWallState"狀態(tài)
2"StartState"狀態(tài)的三個動作MouseClickToStartMeasure堰汉,MouseMoveBeforeMeasure巷嚣,MouseRightClickToStopMeasure
3"InBuildWallState"狀態(tài)的三個動作MouseMoveInMeasure,MouseClickToContinueMeasure楷扬,MouseRightClickToStopMeasure
4 狀態(tài)下的動作切換到另一個狀態(tài)
public void StartHandleMeasureInput()
{
fsm = new FSM4InputHandler();
var tmpState = new State(fsm, "StartState");
tmpState.AddAction(new MouseClickToStartMeasure("InBuildWallState"));
tmpState.AddAction(new MouseMoveBeforeMeasure());
tmpState.AddAction(new MouseRightClickToStopMeasure());
fsm.AddState(tmpState);
fsm.curState = tmpState;
tmpState = new State(fsm, "InBuildWallState");
tmpState.AddAction(new MouseRightClickToStopMeasure());
tmpState.AddAction(new MouseClickToContinueMeasure("StartState"));
tmpState.AddAction(new MouseMoveInMeasure());
fsm.AddState(tmpState);
}
public void StopHandleInput() // 關(guān)閉狀態(tài)機
{
fsm = null;
}
}
}
2.狀態(tài)控制(入口)
using UnityEngine;
using System.Collections;
using System.Collections.Generic;
namespace SpacePlanner
{
public static class FSM_CACHE_KEY
{
public static readonly string SELECTED = "SELECTED";
}
public class FSM4InputHandler
{
IDictionary<string, State> states = new Dictionary<string, State>();//所有的狀態(tài)
public State curState;//當前的狀態(tài)
public State GetState(string name)
{
return states[name];
}
public void Run()
{
curState = curState.OnStay();
}
State startState;
public State StartState
{
get
{
return startState;
}
set { startState = value; }
}
public void AddState(State state)
{
if (!states.ContainsKey(state.name))
{
states.Add(state.name, state);
if (states.Count == 1)
StartState = state;
}
}
}
}
3.狀態(tài)控制(State)
using UnityEngine;
using System.Collections;
using System.Collections.Generic;
namespace SpacePlanner
{
/// <summary>
/// 用戶所處的交互狀態(tài)
/// </summary>
public class State
{
public string name;//狀態(tài)的名字
public FSM4InputHandler fsm;//所屬的狀態(tài)機
public State(FSM4InputHandler fsm, string name)
{
this.fsm = fsm;
this.name = name;
this.actions = new List<StateAction>();
}
protected List<StateAction> actions;//在這個狀態(tài)下的所用動作都保留下來
public void AddAction(StateAction action)
{
actions.Add(action);
action.SetFSM(fsm);
}
____狀態(tài)機的執(zhí)行方法與切換________
/// <summary>
/// 處于該狀態(tài)下時需要執(zhí)行的方法
/// </summary>
/// <returns>下一個狀態(tài)</returns>
public virtual State OnStay()
{
foreach (var action in actions)
{
try
{
if (action.Execute() && action.nextState != null)
return fsm.GetState(action.nextState);
}
catch (System.Exception e)
{
Debug.Log(e.ToString());
Debug.Log("狀態(tài)機執(zhí)行action異常解幽,轉(zhuǎn)到初始狀態(tài)");
return fsm.StartState;
}
}
return this;
}
}
}
4.動作的抽象方法
using UnityEngine;
using System.Collections;
using System;
namespace SpacePlanner
{
public abstract class StateAction
{
public StateAction() { } //沒有狀態(tài)的切換
public StateAction(string nextState)//有狀態(tài)的切換
{
this.nextState = nextState;
}
FSM4InputHandler _fsm;
public FSM4InputHandler FSM
{
get { return _fsm; }
}
public void SetFSM(FSM4InputHandler fsm)
{
_fsm = fsm;
}
public string nextState = null;
public abstract bool Execute();//這個方法時核心,讓每個狀態(tài)下不同的動作重寫該方法烘苹,從而達到不一樣的效果
}
}
5.動作的執(zhí)行方法(每個狀態(tài)下都有多個動作躲株,每個動作的具體效果的實施)
MouseClickToStartMeasure
using UnityEngine;
using System.Collections;
using System;
namespace SpacePlanner
{
public class MouseClickToStartMeasure : StateAction
{
public MouseClickToStartMeasure(string nextState) : base(nextState)
{
}
public override bool Execute()
{
var uiMgr = UIManager.Instance;
if (uiMgr.ClickOnDrawingPanel())
{
#if UNITY_ANDROID || UNITY_IPHONE
uiMgr.DrawingPanel.SetAuxiliaryMeasureActive(false);
#endif
Vector3 screenPos = uiMgr.ClickDrawingPanelData.position;
Vector3 rwPos = TransformHelper.ScreenToRealWorldPoint(screenPos);
Debug.Log("鼠標點擊開始測量" + screenPos + rwPos + TransformHelper.ScreenToUISpacePoint(screenPos, uiMgr.DrawingPanel.transform, false));
//SPApplication.Instance.SendNotification(MVCNotifications.TO_C_BEGIN_BUILD_WALL, new BoolAndVec(rwPos, true));
SPApplication.Instance.SendNotification(MVCNotifications.TO_C_BEGIN_MEASURE, new BoolAndVec(rwPos, true));
RulerManager.Instance.ClearCurRulers();
return true;
}
return false;
}
}
}
MouseMoveBeforeMeasure
using UnityEngine;
using System.Collections;
using System;
namespace SpacePlanner
{
public class MouseMoveBeforeMeasure : StateAction
{
public MouseMoveBeforeMeasure() : base()
{
}
public override bool Execute()
{
var uiMgr = UIManager.Instance;
if (uiMgr.IsPointerOverDrawingPanel())
{
#if UNITY_EDITOR || UNITY_STANDALONE
Vector3 screenPos = Input.mousePosition;
#elif UNITY_ANDROID || UNITY_IPHONE
Vector3 screenPos = uiMgr.DragDrawingPanelData.position;
#endif
Vector3 rwPos = TransformHelper.ScreenToRealWorldPoint(screenPos);
//VOAndVector3 data = new VOAndVector3(null, rwPos);
MeasurePointAndVector data = new MeasurePointAndVector(null,rwPos);
//Debug.Log("鼠標移動在測量之前"+rwPos);
//SPApplication.Instance.SendNotification(MVCNotifications.TO_C_UPDATE_AUXILIARY_LINE, data);
SPApplication.Instance.SendNotification(MVCNotifications.TO_C_UPDATE_AUXILIARY_LINE_MEASURE, data);
//FPBApplication.Instance.SendNotification(ApplicationConstants.TO_V_POINTER_MOVE_WHEN_DRAW_WALL, screenPos);
}
return false;
}
}
}
MouseRightClickToStopMeasure
using UnityEngine;
using System.Collections;
using System;
namespace SpacePlanner
{
public class MouseRightClickToStopMeasure : StateAction
{
public MouseRightClickToStopMeasure() : base()
{
}
public override bool Execute()
{
//#if UNITY_EDITOR || UNITY_STANDALONE
if (Input.GetMouseButtonDown(1))
//#elif UNITY_ANDROID || UNITY_IPHONE
// //if (UIManager.Instance.IsTouchReleased())
//SendNotification(MVCNotifications.TO_V_CLEAR_AUXILIARY_WALL_MEASURE);// 關(guān)掉輔助墻
//#endif
{
//畫墻結(jié)束后把UIFloatExitButton隱藏掉
//GameObject uiFloatPanel = GameObject.Find("UIFloatExitButton(Clone)");
//uiFloatPanel.SetActive(false);
//SPApplication.Instance.SendNotification(MVCNotifications.TO_C_STOP_BUILD_WALL_MEASURE, DrawingSelection.selectedObject);
SPApplication.Instance.SendNotification(MVCNotifications.TO_C_STOP_BUILD_WALL_MEASURE, DrawingSelection.SelectMeasurePoint);
//DrawingSelection.selectedObject = null;
DrawingSelection.SelectMeasurePoint = null;
CursorManager.Instance.setNormalCursor();
return true;
}
return false;
}
}
}
2.測量狀態(tài)下的動作
MouseMoveInMeasure
using UnityEngine;
using System.Collections;
using System;
using SpacePlanner.Core.DataStructure;
namespace SpacePlanner
{
public class MouseMoveInMeasure : StateAction
{
public MouseMoveInMeasure() : base()
{
}
public override bool Execute()
{
var uiMgr = UIManager.Instance;
MeasurePoint measurePoint = DrawingSelection.SelectMeasurePoint;
if (uiMgr.IsPointerOverDrawingPanel())
{
#if UNITY_EDITOR || UNITY_STANDALONE
Vector3 screenPos = Input.mousePosition;
#elif UNITY_ANDROID || UNITY_IPHONE
//Vector3 screenPos = uiMgr.DragDrawingPanelData.position;
Vector3 endPos = uiMgr.DragDrawingPanelData.position;
Vector3 dir = (measurePoint.Start - endPos).normalized;
float circleRadius = 100f;
Vector3 screenPos = endPos + dir * circleRadius;
#endif
Vector3 rwPos = TransformHelper.ScreenToRealWorldPoint(screenPos);
Wall wall = DrawingSelection.selectedObject as Wall;
VOAndVector3 data = new VOAndVector3(wall, rwPos);
//MeasurePoint measurePoint = DrawingSelection.SelectMeasurePoint;
MeasurePointAndVector data1 = new MeasurePointAndVector(measurePoint,rwPos);
//Debug.Log("在測量時移動鼠標" + screenPos + rwPos);
SPApplication.Instance.SendNotification(MVCNotifications.TO_C_UPDATE_AUXILIARY_WALL_MEASURE, data1);
SPApplication.Instance.SendNotification(MVCNotifications.TO_C_UPDATE_AUXILIARY_LINE_MEASURE, data1);
//FPBApplication.Instance.SendNotification(ApplicationConstants.TO_V_POINTER_MOVE_WHEN_DRAW_WALL, screenPos);
}
return false;
}
}
}
MouseClickToContinueMeasure
using UnityEngine;
using System.Collections;
using System;
using SpacePlanner.Core.DataStructure;
using PureMVC.Patterns;
namespace SpacePlanner
{
public class MouseClickToContinueMeasure : StateAction
{
public MouseClickToContinueMeasure(string nextState) : base(nextState)
{
}
public override bool Execute()
{
var uiMgr = UIManager.Instance;
Vector3 screenPos = uiMgr.ClickDrawingPanelData.position;
Vector3 rwPos = TransformHelper.ScreenToRealWorldPoint(screenPos);
Debug.Log("鼠標點擊結(jié)束畫一面墻" + screenPos + rwPos + TransformHelper.ScreenToUISpacePoint(screenPos, uiMgr.DrawingPanel.transform, false));
Wall wall = DrawingSelection.selectedObject as Wall;
MeasurePoint measurePoint = DrawingSelection.SelectMeasurePoint;
UndoManager.Instance.AddNotification();
#if UNITY_EDITOR || UNITY_STANDALONE
if (uiMgr.ClickOnDrawingPanel())
{
//SPApplication.Instance.SendNotification(MVCNotifications.TO_C_BUILD_ONE_WALL_DONE_MEASURE, wall);
SPApplication.Instance.SendNotification(MVCNotifications.TO_C_BUILD_ONE_WALL_DONE_MEASURE, measurePoint);
//UndoManager.Instance.AddNotification(new Notification(MVCNotifications.TO_C_BUILD_ONE_WALL_DONE, wall));// 添加命令到UndoManager里
return true;
}
#elif UNITY_ANDROID || UNITY_IPHONE
if (uiMgr.IsTouchReleased())
{
//SPApplication.Instance.SendNotification(MVCNotifications.TO_C_BUILD_ONE_WALL_DONE_MEASURE, wall);
SPApplication.Instance.SendNotification(MVCNotifications.TO_C_BUILD_ONE_WALL_DONE_MEASURE_ANDROID, measurePoint);
//UndoManager.Instance.AddNotification(new Notification(MVCNotifications.TO_C_BUILD_ONE_WALL_DONE, wall));// 添加命令到UndoManager里
return true;
}
#endif
{
RulerManager.Instance.DisplayAllWallRuler();// 刷新標尺
}
return false;
}
}
}
MouseRightClickToStopMeasure
using UnityEngine;
using System.Collections;
using System;
namespace SpacePlanner
{
public class MouseRightClickToStopMeasure : StateAction
{
public MouseRightClickToStopMeasure() : base()
{
}
public override bool Execute()
{
//#if UNITY_EDITOR || UNITY_STANDALONE
if (Input.GetMouseButtonDown(1))
//#elif UNITY_ANDROID || UNITY_IPHONE
// //if (UIManager.Instance.IsTouchReleased())
//SendNotification(MVCNotifications.TO_V_CLEAR_AUXILIARY_WALL_MEASURE);// 關(guān)掉輔助墻
//#endif
{
//畫墻結(jié)束后把UIFloatExitButton隱藏掉
//GameObject uiFloatPanel = GameObject.Find("UIFloatExitButton(Clone)");
//uiFloatPanel.SetActive(false);
//SPApplication.Instance.SendNotification(MVCNotifications.TO_C_STOP_BUILD_WALL_MEASURE, DrawingSelection.selectedObject);
SPApplication.Instance.SendNotification(MVCNotifications.TO_C_STOP_BUILD_WALL_MEASURE, DrawingSelection.SelectMeasurePoint);
//DrawingSelection.selectedObject = null;
DrawingSelection.SelectMeasurePoint = null;
CursorManager.Instance.setNormalCursor();
return true;
}
return false;
}
}
}
總結(jié)一下狀態(tài)機的流程(注意事項)
1.有狀態(tài)切換的動作,stateAction的構(gòu)造函數(shù)不一樣镣衡,需要把狀態(tài)傳過去霜定。
2.狀態(tài),動作廊鸥,動作改變狀態(tài)望浩。