TEngine--Procedure模块

简单了解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>
{
/// <summary>
/// 状态初始化时调用。
/// </summary>
/// <param name="procedureOwner">流程持有者。</param>
protected internal override void OnInit(ProcedureOwner procedureOwner)
{
base.OnInit(procedureOwner);
}

/// <summary>
/// 进入状态时调用。
/// </summary>
/// <param name="procedureOwner">流程持有者。</param>
protected internal override void OnEnter(ProcedureOwner procedureOwner)
{
base.OnEnter(procedureOwner);
}

/// <summary>
/// 状态轮询时调用。
/// </summary>
/// <param name="procedureOwner">流程持有者。</param>
/// <param name="elapseSeconds">逻辑流逝时间,以秒为单位。</param>
/// <param name="realElapseSeconds">真实流逝时间,以秒为单位。</param>
protected internal override void OnUpdate(ProcedureOwner procedureOwner, float elapseSeconds, float realElapseSeconds)
{
base.OnUpdate(procedureOwner, elapseSeconds, realElapseSeconds);
}

/// <summary>
/// 离开状态时调用。
/// </summary>
/// <param name="procedureOwner">流程持有者。</param>
/// <param name="isShutdown">是否是关闭状态机时触发。</param>
protected internal override void OnLeave(ProcedureOwner procedureOwner, bool isShutdown)
{
base.OnLeave(procedureOwner, isShutdown);
}

/// <summary>
/// 状态销毁时调用。
/// </summary>
/// <param name="procedureOwner">流程持有者。</param>
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
/// <summary>
/// 有限状态机状态基类。
/// </summary>
/// <typeparam name="T">有限状态机持有者类型。</typeparam>
public abstract class FsmState<T> where T : class
{
/// <summary>
/// 初始化有限状态机状态基类的新实例。
/// </summary>
public FsmState()
{
}

/// <summary>
/// 有限状态机状态初始化时调用。
/// </summary>
/// <param name="fsm">有限状态机引用。</param>
protected internal virtual void OnInit(IFsm<T> fsm)
{
}

/// <summary>
/// 有限状态机状态进入时调用。
/// </summary>
/// <param name="fsm">有限状态机引用。</param>
protected internal virtual void OnEnter(IFsm<T> fsm)
{
}

/// <summary>
/// 有限状态机状态轮询时调用。
/// </summary>
/// <param name="fsm">有限状态机引用。</param>
/// <param name="elapseSeconds">逻辑流逝时间,以秒为单位。</param>
/// <param name="realElapseSeconds">真实流逝时间,以秒为单位。</param>
protected internal virtual void OnUpdate(IFsm<T> fsm, float elapseSeconds, float realElapseSeconds)
{
}

/// <summary>
/// 有限状态机状态离开时调用。
/// </summary>
/// <param name="fsm">有限状态机引用。</param>
/// <param name="isShutdown">是否是关闭有限状态机时触发。</param>
protected internal virtual void OnLeave(IFsm<T> fsm, bool isShutdown)
{
}

/// <summary>
/// 有限状态机状态销毁时调用。
/// </summary>
/// <param name="fsm">有限状态机引用。</param>
protected internal virtual void OnDestroy(IFsm<T> fsm)
{
}

/// <summary>
/// 切换当前有限状态机状态。
/// </summary>
/// <typeparam name="TState">要切换到的有限状态机状态类型。</typeparam>
/// <param name="fsm">有限状态机引用。</param>
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>();
}

/// <summary>
/// 切换当前有限状态机状态。
/// </summary>
/// <param name="fsm">有限状态机引用。</param>
/// <param name="stateType">要切换到的有限状态机状态类型。</param>
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()等方法。

一个FsmState状态图例

想要切换状态的话,就要使用ChangeState()方法,这个很好理解,就不过多说明。

ps:这里只讲了几个常用的FsmState方法,要想看更详细的说明可以到Fsm模块——todo查看

Procedure模块使用

1.框架内流程

TEngine框架里有已经写好的流程,用来初始化游戏框架。可以在\GameScripts\Main\Procedure里查看。
TEngine流程图例
流程里的内容可以自行查看源码,这里重点讲一下初始化流程。在初始化流程里有一个初始化方法,它可以实现在不同编辑器模式下的流程跳转,编辑器模式跳转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)
{
// 打开启动UI。
UILoadMgr.Show(UIDefine.UILoadUpdate);

Log.Info("Updatable resource mode detected.");
ChangeState<ProcedureUpdateVersion>(procedureOwner);
}
else
{
Log.Error("UnKnow resource mode detected Please check???");
}
}
else
{
// 打开启动UI。
UILoadMgr.Show(UIDefine.UILoadUpdate);

Log.Error($"{initializationOperation.Error}");

// 打开启动UI。
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);//框架加载场景方法,通过YooAsset加载场景
//todo
}

protected override void OnUpdate(IFsm<IProcedureManager> procedureOwner, float elapseSeconds, float realElapseSeconds)
{
base.OnUpdate(procedureOwner, elapseSeconds, realElapseSeconds);
//todo
}

protected override void OnLeave(IFsm<IProcedureManager> procedureOwner, bool isShutdown)
{
base.OnLeave(procedureOwner, isShutdown);
//todo
}
}
}

API类图

流程模块类图


TEngine--Procedure模块
https://www.liu2dream.fun/post/TEngine--Procedure模块/
作者
刘老师 MrLiu
发布于
2024年5月30日
许可协议