本文最后更新于 2024-07-02T01:30:44+08:00
简单了解Fsm状态机 学习Procedure流程模块前需要先了解一下Fsm状态机,因为Procedurebase类就是继承了FsmState类。
1 2 3 4 5 6 7 8 9 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 public abstract class ProcedureBase : FsmState <IProcedureManager > { protected internal override void OnInit (ProcedureOwner procedureOwner ) { base .OnInit(procedureOwner); } protected internal override void OnEnter (ProcedureOwner procedureOwner ) { base .OnEnter(procedureOwner); } protected internal override void OnUpdate (ProcedureOwner procedureOwner, float elapseSeconds, float realElapseSeconds ) { base .OnUpdate(procedureOwner, elapseSeconds, realElapseSeconds); } protected internal override void OnLeave (ProcedureOwner procedureOwner, bool isShutdown ) { base .OnLeave(procedureOwner, isShutdown); } protected internal override void OnDestroy (ProcedureOwner procedureOwner ) { base .OnDestroy(procedureOwner); } }
1 2 3 4 5 6 7 8 9 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 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 public abstract class FsmState <T > where T : class { public FsmState () { } protected internal virtual void OnInit (IFsm<T> fsm ) { } protected internal virtual void OnEnter (IFsm<T> fsm ) { } protected internal virtual void OnUpdate (IFsm<T> fsm, float elapseSeconds, float realElapseSeconds ) { } protected internal virtual void OnLeave (IFsm<T> fsm, bool isShutdown ) { } protected internal virtual void OnDestroy (IFsm<T> fsm ) { } protected void ChangeState <TState >(IFsm<T> fsm ) where TState : FsmState<T> { Fsm<T> fsmImplement = (Fsm<T>)fsm; if (fsmImplement == null ) { throw new GameFrameworkException("FSM is invalid." ); } fsmImplement.ChangeState<TState>(); } protected void ChangeState (IFsm<T> fsm, Type stateType ) { Fsm<T> fsmImplement = (Fsm<T>)fsm; if (fsmImplement == null ) { throw new GameFrameworkException("FSM is invalid." ); } if (stateType == null ) { throw new GameFrameworkException("State type is invalid." ); } if (!typeof (FsmState<T>).IsAssignableFrom(stateType)) { throw new GameFrameworkException(Utility.Text.Format("State type '{0}' is invalid." , stateType.FullName)); } fsmImplement.ChangeState(stateType); } }
在FsmState类里面,比较常用的就是OnEnter()、OnUpdate()、OnLeave()和ChangeState()方法。 OnEnter()方法表示进入状态时执行,只执行一次。 OnUpdate()方法表示在unity的Update上每帧执行。 Onleave()方法则表示离开状态的时候执行,只执行一次。
因为ProcedureBase类继承了FsmState类,所以ProcedureBase类下的子类都可以用OnEnter()、OnUpdate()和OnLeave()等方法。
想要切换状态的话,就要使用ChangeState()方法,这个很好理解,就不过多说明。
ps:这里只讲了几个常用的FsmState方法,要想看更详细的说明可以到Fsm模块——todo查看
Procedure模块使用 1.框架内流程 TEngine框架里有已经写好的流程,用来初始化游戏框架。可以在\GameScripts\Main\Procedure里查看。 流程里的内容可以自行查看源码,这里重点讲一下初始化流程。在初始化流程里有一个初始化方法,它可以实现在不同编辑器模式下的流程跳转,编辑器模式跳转ProcedurePreload流程、单机模式跳转ProcedureInitResources流程、更新模式跳转ProcedureUpdateVersion流程。
1 2 3 4 5 6 7 8 9 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 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 private async UniTaskVoid InitPackage (ProcedureOwner procedureOwner ) { try { if (GameModule.Resource.PlayMode == EPlayMode.HostPlayMode || GameModule.Resource.PlayMode == EPlayMode.WebPlayMode) { if (SettingsUtils.EnableUpdateData()) { UpdateData updateData = await RequestUpdateData(); if (updateData != null ) { if (!string .IsNullOrEmpty(updateData.HostServerURL)) { SettingsUtils.FrameworkGlobalSettings.HostServerURL = updateData.HostServerURL; } if (!string .IsNullOrEmpty(updateData.FallbackHostServerURL)) { SettingsUtils.FrameworkGlobalSettings.FallbackHostServerURL = updateData.FallbackHostServerURL; } } } } var initializationOperation = await GameModule.Resource.InitPackage(); if (initializationOperation.Status == EOperationStatus.Succeed) { LoadText.Instance.InitConfigData(null ); GameEvent.Send(RuntimeId.ToRuntimeId("RefreshVersion" )); EPlayMode playMode = GameModule.Resource.PlayMode; if (playMode == EPlayMode.EditorSimulateMode) { Log.Info("Editor resource mode detected." ); ChangeState<ProcedurePreload>(procedureOwner); } else if (playMode == EPlayMode.OfflinePlayMode) { Log.Info("Package resource mode detected." ); ChangeState<ProcedureInitResources>(procedureOwner); } else if (playMode == EPlayMode.HostPlayMode || playMode == EPlayMode.WebPlayMode) { UILoadMgr.Show(UIDefine.UILoadUpdate); Log.Info("Updatable resource mode detected." ); ChangeState<ProcedureUpdateVersion>(procedureOwner); } else { Log.Error("UnKnow resource mode detected Please check???" ); } } else { UILoadMgr.Show(UIDefine.UILoadUpdate); Log.Error($"{initializationOperation.Error} " ); UILoadMgr.Show(UIDefine.UILoadUpdate, $"资源初始化失败!" ); UILoadTip.ShowMessageBox( $"资源初始化失败!点击确认重试 \n \n <color=#FF0000>原因{initializationOperation.Error} </color>" , MessageShowType.TwoButton, LoadStyle.StyleEnum.Style_Retry , () => { Retry(procedureOwner); }, UnityEngine.Application.Quit); } } catch (Exception e) { OnInitPackageFailed(procedureOwner, e.Message); } }
2.自定义流程 TEngine在加载程序集流程里,通过反射执行了GameApp里的Entrance方法。其中GameModule.Procedure.RestartProcedure(new GameLogic.OnEnterGameAppProcedure())语句会开启自定义流程。我们在OnEnterGameAppProcedure里编写代码就可以实现自己的流程了!
想要续写流程可以自己定义OnEnterGameAppProcedure之后的流程类(继承Procedurebase类),通过ChangeState()方法进行跳转,用法和框架内流程一样,就不在赘述了。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 public static void Entrance (object [] objects ) { _hotfixAssembly = (List<Assembly>)objects[0 ]; Log.Warning("======= 看到此条日志代表你成功运行了热更新代码 =======" ); Log.Warning("======= Entrance GameApp =======" ); Instance.Init(); Instance.Start(); Utility.Unity.AddUpdateListener(Instance.Update); Utility.Unity.AddFixedUpdateListener(Instance.FixedUpdate); Utility.Unity.AddLateUpdateListener(Instance.LateUpdate); Utility.Unity.AddDestroyListener(Instance.OnDestroy); Utility.Unity.AddOnDrawGizmosListener(Instance.OnDrawGizmos); Utility.Unity.AddOnApplicationPauseListener(Instance.OnApplicationPause); GameModule.Procedure.RestartProcedure(new GameLogic.OnEnterGameAppProcedure()); Instance.StartGameLogic(); }
注意:自定义流程可以进行热更,因为它在热更程序集里。但框架内流程就无法热更了,所以最好不要在自定义流程和框架内流程之间跳转,而且也没有这个必要。
OnEnterGameAppProcedure样例: 在Assets\AssetRaw\Scenes新建一个测试场景,名为test。在里面放入一些测试内容,然后再OnEnterGameAppProcedure的OnEnter方法里写入GameModule.Scene.LoadScene(test,LoadSceneMode.Single); 加载场景。最后打包ab测试。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 using GameConfig;using TEngine;using UnityEngine;using UnityEngine.SceneManagement;namespace GameLogic { public class OnEnterGameAppProcedure : ProcedureBase { protected override void OnEnter (IFsm<IProcedureManager> procedureOwner ) { base .OnEnter(procedureOwner); Log.Debug("OnEnter GameApp Procedure" ); GameModule.Scene.LoadScene("test" ,LoadSceneMode.Single); } protected override void OnUpdate (IFsm<IProcedureManager> procedureOwner, float elapseSeconds, float realElapseSeconds ) { base .OnUpdate(procedureOwner, elapseSeconds, realElapseSeconds); } protected override void OnLeave (IFsm<IProcedureManager> procedureOwner, bool isShutdown ) { base .OnLeave(procedureOwner, isShutdown); } } }
API类图