GameFramework生命周期

最近又在写一些游戏项目,想要看一些有什么方便开发的框架,来来回回发现 GameFramework 依然是绕不过去的一个框架。本章主要是分析一下 GameFramework 的生命周期。

Unity 生命周期

先看一下常见的 Unity 的生命周期

graph LR
    A[Awake] --> B[Start]
    B --> C[Update]
    C --> C
    C --> D[OnDestroy]

    E[其他MonoBehaviour] --> F[独立生命周期]

主要有几个问题:

  • 各个模块之间的生命周期是独立的,执行顺序不确定
  • 难以控制正确的初始化和销毁顺序
  • 无法更好的处理依赖关系

GameFramework 生命周期

GameFrameworkModule

GameFramework 通过 GameFrameworkModule 来管理模块的生命周期。GameFrameworkModule 是一个抽象类,主要有三个方法:

graph TB
    A[GameFrameworkEntry.GetModule] --> B[自动创建模块]
    B --> C[按优先级排序]
    C --> D[统一Update循环]
    D --> E[逆序Shutdown]

    F[高优先级模块] --> G[先执行Update]
    F --> H[后执行Shutdown]

   

代码是这样的:

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
/// <summary>
/// 游戏框架模块抽象类。
/// </summary>
internal abstract class GameFrameworkModule
{
/// <summary>
/// 获取游戏框架模块优先级。
/// </summary>
/// <remarks>优先级较高的模块会优先轮询,并且关闭操作会后进行。</remarks>
internal virtual int Priority
{
get
{
return 0;
}
}

/// <summary>
/// 游戏框架模块轮询。
/// </summary>
/// <param name="elapseSeconds">逻辑流逝时间,以秒为单位。</param>
/// <param name="realElapseSeconds">真实流逝时间,以秒为单位。</param>
internal abstract void Update(float elapseSeconds, float realElapseSeconds);

/// <summary>
/// 关闭并清理游戏框架模块。
/// </summary>
internal abstract void Shutdown();
}
  1. 通过 Priority 来控制模块的执行顺序
  2. 通过 Update 来控制模块的更新
  3. 通过 Shutdown 来控制模块的销毁

GameFrameworkEntry

看了 GameFrameworkModule 的实现,接下来看看 GameFrameworkEntry 的实现。GameFrameworkEntry 中是如何管理项目中所有的模块的。

1. CreateModule

  1. 使用 System.Activator.CreateInstance 来创建模块
  2. 通过 LinkedList 来管理模块的顺序,保证在数据结构中模块是有序的
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
/// <summary>
/// 创建游戏框架模块。
/// </summary>
/// <param name="moduleType">要创建的游戏框架模块类型。</param>
/// <returns>要创建的游戏框架模块。</returns>
private static GameFrameworkModule CreateModule(Type moduleType)
{
GameFrameworkModule module = (GameFrameworkModule)Activator.CreateInstance(moduleType);
if (module == null)
{
throw new GameFrameworkException(Utility.Text.Format("Can not create module '{0}'.", moduleType.FullName));
}

// 根据优先级插入,高优先级在前
LinkedListNode<GameFrameworkModule> current = s_GameFrameworkModules.First;
while (current != null)
{
if (module.Priority > current.Value.Priority)
{
break;
}
current = current.Next;
}

if (current != null)
{
s_GameFrameworkModules.AddBefore(current, module);
}
else
{
s_GameFrameworkModules.AddLast(module);
}

return module;
}

2. GetModule

  1. 强制使用接口来获取模块,依赖倒置原则:
    • 高层模块不应该依赖低层模块,二者都应该依赖抽象
    • 通过接口来获取模块,避免了直接依赖实现类
  2. 通过命名约定来获取模块
    • IXxxManager -> XxxManager
    • 通过反射来获取模块的类型
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
/// <summary>
/// 获取游戏框架模块。
/// </summary>
/// <typeparam name="T">要获取的游戏框架模块类型。</typeparam>
/// <returns>要获取的游戏框架模块。</returns>
/// <remarks>如果要获取的游戏框架模块不存在,则自动创建该游戏框架模块。</remarks>
public static T GetModule<T>() where T : class
{
Type interfaceType = typeof(T);
// 1. 必须是接口类型
if (!interfaceType.IsInterface)
{
throw new GameFrameworkException(Utility.Text.Format("You must get module by interface, but '{0}' is not.", interfaceType.FullName));
}
// 2. 必须是游戏框架模块, 必须是 GameFramework 命名空间下的类型
if (!interfaceType.FullName.StartsWith("GameFramework.", StringComparison.Ordinal))
{
throw new GameFrameworkException(Utility.Text.Format("You must get a Game Framework module, but '{0}' is not.", interfaceType.FullName));
}
// 3. 命名约定:IXxxManager -> XxxManager
string moduleName = Utility.Text.Format("{0}.{1}",
interfaceType.Namespace,
interfaceType.Name.Substring(1)); // 去掉前缀 I
Type moduleType = Type.GetType(moduleName);
if (moduleType == null)
{
throw new GameFrameworkException(Utility.Text.Format("Can not find Game Framework module type '{0}'.", moduleName));
}

return GetModule(moduleType) as T;
}

/// <summary>
/// 获取游戏框架模块。
/// </summary>
/// <param name="moduleType">要获取的游戏框架模块类型。</param>
/// <returns>要获取的游戏框架模块。</returns>
/// <remarks>如果要获取的游戏框架模块不存在,则自动创建该游戏框架模块。</remarks>
private static GameFrameworkModule GetModule(Type moduleType)
{
foreach (GameFrameworkModule module in s_GameFrameworkModules)
{
if (module.GetType() == moduleType)
{
return module;
}
}

return CreateModule(moduleType);
}

3. Update/Shutdown

这部分就没什么特别需要注意的地方了,唯一需要注意的是在 Shutdown 的时候是逆序的(优先级低的模块可能用到了高优先级的模块)。

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
/// <summary>
/// 所有游戏框架模块轮询。
/// </summary>
/// <param name="elapseSeconds">逻辑流逝时间,以秒为单位。</param>
/// <param name="realElapseSeconds">真实流逝时间,以秒为单位。</param>
public static void Update(float elapseSeconds, float realElapseSeconds)
{
foreach (GameFrameworkModule module in s_GameFrameworkModules)
{
module.Update(elapseSeconds, realElapseSeconds);
}
}

/// <summary>
/// 关闭并清理所有游戏框架模块。
/// </summary>
public static void Shutdown()
{
for (LinkedListNode<GameFrameworkModule> current = s_GameFrameworkModules.Last; current != null; current = current.Previous)
{
current.Value.Shutdown();
}

s_GameFrameworkModules.Clear();
ReferencePool.ClearAll();
Utility.Marshal.FreeCachedHGlobal();
GameFrameworkLog.SetLogHelper(null);
}

其他

用到的设计模式

  • 工厂模式、单例模式
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
// GameFrameworkEntry 充当了工厂和单例管理器
public static class GameFrameworkEntry
{
// 单例容器
private static readonly GameFrameworkLinkedList<GameFrameworkModule> s_GameFrameworkModules;

// 工厂方法
public static T GetModule<T>() where T : class
{
// 1. 检查是否已存在
GameFrameworkModule existingModule = GetModule(moduleType);
if (existingModule != null) return existingModule as T;

// 2. 不存在则创建新实例
return CreateModule(moduleType) as T;
}
}

工厂模式:


graph TB
A[Client 客户端] --> B[Factory 工厂类]
B --> C{产品类型判断}
C -->|TypeA| D[ProductA 产品 A]
C -->|TypeB| E[ProductB 产品 B]
C -->|TypeC| F[ProductC 产品 C]

    D --> G[IProduct产品接口]
    E --> G
    F --> G

    G --> H[返回给客户端]


单例模式:

graph TB
A[Client 客户端] --> B[Singleton 单例类]
B --> C{判断是否已存在}
C -->|已存在| D[返回实例]
C -->|不存在| E[创建新实例]

    E --> F[返回实例]


LinkedList

使用了 LinkedList 来管理模块的顺序,LinkedList 是一个双向链表,支持在 O(1) 的时间复杂度内插入和删除节点。适合频繁插入和删除的场景。


GameFramework生命周期
https://lshgame.com/2025/05/24/GameFramework_Lifecycle/
作者
SuHang
发布于
2025年5月24日
许可协议