文件规制
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;
private List<GameObject> _activeList; private List<GameObject> _inactiveList;
private readonly int _useFrequency = 5; private int _minNum; private DateTime _spawnTime; private bool _isDestroying; 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(); } 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); go = _inactiveList[0]; _inactiveList.RemoveAt(0); UnityEngine.Object.Destroy(go); } _isDestroying = false; } private void Preload(int count) { GameObject temp; for (int i = 0; i < count; i++) { temp = SpawnNew(); _inactiveList.Add(temp); temp.SetActive(false); } } 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; } private GameObject SpawnNew() { return UnityEngine.Object.Instantiate(_prefab,_selfGO.transform); } 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(); } 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; } } 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);
|