文件规制

Assets——新建UI文件夹——在其中新建MainUI和GameUI文件夹——把之前的Controller文件夹和View文件夹转移到MainUI文件夹内。

Assets——新建Logic文件夹

GameObjectPool

Assets——Module——新建Pool文件夹,在其中新建GameObjectPool

Module内的代码都是独立的模块,各自的逻辑都是独立的,不能引用LoadMgr等在游戏内使用的逻辑

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
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
using System;
using System.Threading.Tasks;
using System.Collections.Generic;
using UnityEngine;

public class GameObjectPool
{
private GameObject _prefab;
private GameObject _selfGO;//此对象池对应的GameObject

private List<GameObject> _activeList;
private List<GameObject> _inactiveList;

private readonly int _useFrequency = 5;//生命长度,单位是秒,超时后开始销毁对象,注意这是整个对象池计算的生命长度
private int _minNum;//最小数量,保证不会被销毁的对象数量
private DateTime _spawnTime;
private bool _isDestroying;
/// <summary>
/// 初始化对象池
/// </summary>
/// <param name="prefab">对象池管理的prefab</param>
/// <param name="parent">对象池Go的父对象</param>
public void Init(GameObject prefab, Transform parent, int preloadCount, bool autoDestroy)
{
_isDestroying = false;
_minNum = preloadCount;
_activeList = new List<GameObject>(preloadCount);
_inactiveList = new List<GameObject>(preloadCount);
_prefab = prefab;
_selfGO = new GameObject(_prefab.name + "Pool");
_selfGO.transform.SetParent(parent);
Preload(preloadCount);
if (autoDestroy)
AutoDestroy();
}
/// <summary>
/// 每隔一秒钟检测是否需要销毁。
/// </summary>
private async void AutoDestroy()
{
while (true)
{
await Task.Delay(TimeSpan.FromSeconds(1));
int spendTime = (_spawnTime - DateTime.Now).Seconds;
if (spendTime >= _useFrequency && !_isDestroying)
{
_isDestroying = true;
StartDestory();
}
}
}
private async void StartDestory()
{
GameObject go;
while (_inactiveList.Count > _minNum)
{
await Task.Delay(100);//每100ms销毁一个
go = _inactiveList[0];
_inactiveList.RemoveAt(0);
UnityEngine.Object.Destroy(go);
}
_isDestroying = false;
}
/// <summary>
/// 预加载
/// </summary>
/// <param name="count">数量</param>
private void Preload(int count)
{
GameObject temp;
for (int i = 0; i < count; i++)
{
temp = SpawnNew();
_inactiveList.Add(temp);
temp.SetActive(false);
}
}
/// <summary>
/// 生成对象
/// </summary>
/// <returns>GameObject</returns>
public GameObject Spawn()
{
_spawnTime = DateTime.Now;
GameObject temp;
if ( _inactiveList.Count > 0 )
{
temp = _inactiveList[0];
_inactiveList.RemoveAt(0);
}
else
{
temp = SpawnNew();
}
_activeList.Add(temp);
temp.SetActive(true);
return temp;
}
/// <summary>
/// 如果inactiveList中没有prefab,新建prefab对象
/// </summary>
/// <returns>新建的prefab</returns>
private GameObject SpawnNew()
{
return UnityEngine.Object.Instantiate(_prefab,_selfGO.transform);//新的对象都是对象池的子对象
}
/// <summary>
/// 回收对象
/// </summary>
/// <param name="gameObject">对象</param>
public void Despawn(GameObject gameObject)
{
if (_activeList.Contains(gameObject))
{
_activeList.Remove(gameObject);
_inactiveList.Add(gameObject);
gameObject.SetActive(false);
}
}
}

PoolMgr

每种prefab的GameObjectPool都在PoolMgr当中管理。

这里的PoolMgr单独写一个单例,它只在Game场景中起作用,在Main场景中无法创建它。

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
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System.Threading.Tasks;

public class PoolMgr : IInit
{
private static PoolMgr _instance;
private static GameObject _selfGO;
public static PoolMgr Instance
{
get
{
if (GameStateModel.Instance.CurrentScene == SceneName.Game)
{
if (_instance == null)
{
_instance = new PoolMgr();
_selfGO = new GameObject("PoolMgr");
}
return _instance;
}
else
{
Debug.LogError("对象池只能在Game场景中生成");
return null;
}
}
}

private Dictionary<string, GameObjectPool> _poolsDic;
private System.Action _initComplete;
public void Init(System.Action callback)
{
_initComplete = callback;
Init();
}
public async void Init()
{
_poolsDic = new Dictionary<string, GameObjectPool>();
PoolConfig poolConfig = new();
GameObject temp;
GameObjectPool pool;
foreach (var poolData in poolConfig.PoolDatas)
{
temp = LoadMgr.Instance.LoadPrefab(poolData.Path);
pool = new GameObjectPool();
pool.Init(temp, _selfGO.transform, poolData.PreloadCount, poolData.AutoDestroy);
_poolsDic.Add(poolData.Path, pool);
await Task.Delay(100);
}
_initComplete?.Invoke();
}
/// <summary>
/// 从指定的对象池中生成对象
/// </summary>
/// <param name="path">此对象的prefab路径</param>
/// <returns>从对象池中生成的对象</returns>
public GameObject Spawn(string path)
{
if (_poolsDic.TryGetValue(path, out var pool))
{
return pool.Spawn();
}
else
{
Debug.LogErrorFormat("当前prefab没有在池的管理中,请检查PoolConfig.cs配置,Prefab路径:{0}",path);
return null;
}
}
/// <summary>
/// 回收对象
/// </summary>
public bool Despawn(GameObject go)
{
string goName = go.name.Replace("(Clone)", "");
foreach (var poolPair in _poolsDic)
{
if (poolPair.Key.Contains(goName))
{
poolPair.Value.Despawn(go);
return true;
}
}
return false;
}
}

这里提供了async Init()Init(Action callback)两种方法。在下一节中,我们主要通过SceneConfig调用Init(Action callback)方法来初始化PoolMgr,详见下一节。

PoolConfig

对象池需要管理的对象都在PoolConfig当中指定好,在Config文件夹中新建PoolConfig

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
```



## PoolData

一个配置类。每种对象池管理的prefab路径、预加载的数量、是否自动销毁都存储在这里。这个类写在`PoolConfig`里面

```csharp
public class PoolData
{
public string Path { get; set; }
public int PreloadCount { get; set; }
public bool AutoDestroy { get; set; }
}

修改ILoader

修改ILoader,添加直接加载Prefab的方法LoadPrefab,并将之前LoadPrefab方法改为LoadPrefabAndInstantiate

1
2
3
4
5
6
7
8
9
10
11
using System;
using UnityEngine;

public interface ILoader
{
public GameObject LoadPrefab(string path);//+++
public GameObject LoadPrefabAndInstantiate(string path, Transform parent = null);//+++
void LoadConfig(string path,Action<object> onComplete);
T Load<T>(string path) where T : UnityEngine.Object;
T[] LoadAll<T>(string path) where T: UnityEngine.Object;
}

修改ResourceLoader

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public class ResourceLoader : ILoader
{
public GameObject LoadPrefab(string path)//+++
{
GameObject prefab = Resources.Load<GameObject>(path);
return prefab;
}

public GameObject LoadPrefabAndInstantiate(string path,Transform parent = null)
{
GameObject prefab = LoadPrefab(path);//+++
GameObject temp = Object.Instantiate(prefab,parent);
return temp;
}
//...
}

修改LoadMgr

1
public GameObject LoadPrefab(string path) => m_Loader.LoadPrefab(path);