抱歉,您的浏览器无法访问本站
本页面需要浏览器支持(启用)JavaScript
了解详情 >

简介

基于 addressable,结合对象池进行对象资源的管理。并且提供定时清理资源的接口。

原理

资源管理

打包的部分就是官方的 addressable 使用方式,本项目主要是对资源加载和持续化进行管理。

首先我们定义一个资源数据类 ResInfo 用于保存加载器的资源名、异步加载句柄和引用数。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
using System;
using UnityEngine.ResourceManagement.AsyncOperations;

namespace ResourceUtils
{
public class ResInfo
{
public string name = String.Empty;

public int reference = 0;

public AsyncOperationHandle handle;
}
}

然后我们定义一个加载器类 ABLoader 用于实现资源加载相关的功能,包括同步加载、异步加载、资源释放、资源引用数记录等。

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
121
122
123
using System;
using UnityEngine;
using UnityEngine.AddressableAssets;
using UnityEngine.ResourceManagement.AsyncOperations;

namespace ResourceUtils
{
public class ABLoader
{
private ResInfo _res;

private bool _isLoaded = false;

// private List<>

public ABLoader(string name)
{
_res = new ResInfo();
_res.name = name;
}

/// <summary>
/// 增加引用
/// </summary>
/// <param name="add">true 增加,false 减少</param>
public void AddReference(bool add = true)
{
if (add)
{
_res.reference++;
}
else
{
_res.reference--;
}
}

/// <summary>
/// 获取引用
/// </summary>
/// <returns></returns>
public int GetReference()
{
return _res.reference;
}

/// <summary>
/// 异步加载
/// </summary>
/// <param name="callback"></param>
/// <typeparam name="T"></typeparam>
public void LoadAsync<T>(Action<T> callback = null) where T:class
{
if (_isLoaded)
{
if (_res.handle.IsDone)
{
callback?.Invoke(_res.handle.Result as T);
}
else
{
Loading(callback);
}
}
else
{
Loading(callback);
}
}

/// <summary>
/// 同步加载
/// </summary>
/// <typeparam name="T"></typeparam>
/// <returns></returns>
public T Load<T>() where T:class
{
_isLoaded = true;
_res.handle = Addressables.LoadAssetAsync<T>(_res.name);
T obj = _res.handle.WaitForCompletion() as T;
_isLoaded = false;
Debug.Log("同步加载完成");

return obj;
}

/// <summary>
/// 释放
/// </summary>
public void Release()
{
if (_isLoaded)
{
_isLoaded = false;
Addressables.Release(_res.handle);
}
}

/// <summary>
/// 加载
/// </summary>
/// <param name="callback"></param>
/// <typeparam name="T"></typeparam>
private void Loading<T>(Action<T> callback) where T:class
{
_isLoaded = true;
_res.handle = Addressables.LoadAssetAsync<T>(_res.name);
_res.handle.Completed += result =>
{
if (result.Status == AsyncOperationStatus.Succeeded)
{
T obj = result.Result as T;
callback?.Invoke(obj);
}
else
{
callback?.Invoke(null);
Debug.LogError(_res.name + " 加载失败");
}
};
}
}
}

我们对资源的加载和释放,都是根据加载器类进行判断和实现。

为了管理每种资源的加载器,我们定义一个加载类 ABManager 进行管理。我们定义一个字典保存每一个资源名对应的 ABLoader,第一次加载的时候初始化,之后就用第一次加载的 ABLoader 进行相关的操作。

释放的时候也要调用对应的 Release 方法并且从字典移除。

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
121
122
123
124
125
126
127
128
using System;
using System.Collections.Generic;

namespace ResourceUtils
{
public class ABManager : Singleton<ABManager>
{
private Dictionary<string, ABLoader> _loaders = new Dictionary<string, ABLoader>();

private Dictionary<string, int> _resourceCount = new Dictionary<string, int>();

/// <summary>
/// 异步加载
/// </summary>
/// <param name="name"></param>
/// <param name="callback"></param>
/// <param name="loader"></param>
/// <typeparam name="T"></typeparam>
public void LoadAsync<T>(string name, Action<T> callback) where T : class
{
ABLoader loader;
_loaders.TryGetValue(name, out loader);

if (loader == null)
{
loader = new ABLoader(name);
_loaders.Add(name, loader);
}

loader.LoadAsync(callback);
}

/// <summary>
/// 同步加载
/// </summary>
/// <param name="name"></param>
/// <param name="loader"></param>
/// <typeparam name="T"></typeparam>
/// <returns></returns>
public T Load<T>(string name) where T : class
{
ABLoader loader;
_loaders.TryGetValue(name, out loader);

if (loader == null)
{
loader = new ABLoader(name);
_loaders.Add(name, loader);
}

T obj = loader.Load<T>();
return obj;
}

/// <summary>
/// 添加引用
/// </summary>
/// <param name="name">资源名</param>
/// <param name="add">true 添加,false 减少</param>
public void AddReference(string name, bool add = true)
{
if (_loaders.ContainsKey(name))
{
_loaders[name].AddReference(add);
}
else
{
if (!_resourceCount.TryAdd(name, 1))
{
if (add)
{
_resourceCount[name]++;
}
else
{
_resourceCount[name]--;
}
}
}
}

/// <summary>
/// 获取引用
/// </summary>
/// <param name="name"></param>
/// <returns></returns>
public int GetReference(string name)
{
if (_loaders.ContainsKey(name))
{
return _loaders[name].GetReference();
}
else
{
return _resourceCount[name];
}
}

/// <summary>
/// 移除加载器
/// </summary>
/// <param name="name"></param>
public void Release(string name)
{
ABLoader loader;
_loaders.TryGetValue(name, out loader);
if (loader != null)
{
loader.Release();
}

_loaders.Remove(name);
}

/// <summary>
/// 完全清除
/// </summary>
public void Clear()
{
foreach (var loader in _loaders)
{
loader.Value.Release();
}

_loaders = null;
}
}
}

上述资源加载和释放相关的功能都是调用 addressable 相关的 API 实现。

对象池

对象池的原理很简单,就是在不需要对象的时候回收到一个池里,一般用栈来存储,然后定义一个字典来存储不同名字对象的栈。在获取对象的时候,根据对象名来获取对应的存储池,然后从池里拿到我们需要的对象,如果没有对象则返回 null。在场景上我们创建一个 inactive 的对象用于挂载对象池中的对象。

本项目的对象池还有设置了定时清理的方法。

定时清理分为两个阶段:

  1. 清理到目标数量为止。
  2. 全部清理。

为了实现对象池清理的两个阶段,我们定义枚举 ReleaseFlag ,一共有两种状态:

  1. New。
  2. Old。

当我们回收或者获取对象的时候,更新目标对象池状态为 New;当清理的时候,如果对象池状态是 New 的话就清理到目标数量为止,然后把该对象池状态置为 Old;当清理的时候对象池的状态为 Old 的话,就把该对象池清空,然后移除。

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
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
using System.Collections.Generic;
using System.Linq;
using GameObjectUtils;
using UnityEngine;

namespace PoolUtils
{
public class ObjPoolManager : Singleton<ObjPoolManager>
{
enum ReleaseFlag
{
New,
Old
}

private Transform _root;

private Dictionary<string, Stack<GameObject>> _pool = new Dictionary<string, Stack<GameObject>>();

private Dictionary<string, ReleaseFlag> _releaseFlags = new Dictionary<string, ReleaseFlag>();

/// <summary>
/// 水位线
/// </summary>
private int _waterline = 10;

public void Init()
{
_root = new GameObject().transform;
_root.name = "ObjPoolRoot";
_root.gameObject.SetActive(false);
}

/// <summary>
/// 获取对象
/// </summary>
/// <param name="name"></param>
/// <returns></returns>
public GameObject Get(string name)
{
Stack<GameObject> stack;

GameObject obj = null;

_pool.TryGetValue(name, out stack);

stack?.TryPop(out obj);

_releaseFlags[name] = ReleaseFlag.New;

return obj;
}

/// <summary>
/// 回收对象
/// </summary>
/// <param name="name"></param>
/// <param name="obj"></param>
public void Recycle(string name, GameObject obj)
{
//回收到对象池
Stack<GameObject> stack;
_pool.TryGetValue(name, out stack);

if (stack == null)
{
stack = new Stack<GameObject>();
_pool[name] = stack;
}

stack.Push(obj);

//设置对象到对象池根节点

obj.transform.SetParent(_root);

_releaseFlags[name] = ReleaseFlag.New;
}

/// <summary>
/// 检测闲置对象池并清除
/// </summary>
public void CheckRelease()
{
var keys = _pool.Keys.ToList();

foreach (var key in keys)
{
Stack<GameObject> stack = _pool[key];

ReleaseFlag flag = _releaseFlags[key];

switch (flag)
{
case ReleaseFlag.New:

while (stack.Count > _waterline)
{
GameObject obj = stack.Pop();
ObjManager.Ins().Release(key, obj);
}

_releaseFlags[key] = ReleaseFlag.Old;

break;
case ReleaseFlag.Old:

while (stack.Count > 0)
{
GameObject obj = stack.Pop();
ObjManager.Ins().Release(key, obj);
}

_pool.Remove(key);
_releaseFlags.Remove(key);

break;
}
}
}

/// <summary>
/// 清空对象池
/// </summary>
public void Clear()
{
foreach (var data in _pool)
{
foreach (var obj in data.Value)
{
ObjManager.Ins().Release(data.Key,obj);
}
}

_pool.Clear();
}
}
}

对象管理

有了资源管理和对象池之后,我们把这两个功能都封装到一个类 ObjManager 中。

在这个类中我们定义一个字典用于保存对象的预制体,这样我们之后需要创建新的对象的时候就可以克隆该预制体而不用重新从 AB 包中加载。

同步获取对象的流程如下:

graph TD;

    A["对象池"]
    B["对象"]
    C["预制体字典"]
    D["克隆预制体"]
    E["加载对象预制体并保存"]
    F["增加引用计数"]

    A--"有对象"-->B
    A--"没有对象"-->C
    C--"有预制体"-->D
    C--"没有预制体"-->E
    E-->D
    D-->F

异步获取对象主要用于提前加载预制体,因此流程比较简单:

graph TD;
    A["预制体字典"]
    B["加载对象预制体"]
    C["保存到预制体字典并触发回调"]

    A--"不存在预制体"-->B
    B-->C

对象的引用计数一般在获取对象和销毁对象的时候变化,回收对象不做改变。

对象管理器也有定时清理资源的方法,清理资源的时候遍历预制体字典获取对象名称,然后查询其引用计数是否为 0,为 0 的就释放并移出字典。

考虑到可能对象管理类的定时清理资源和对象池的定时清理资源方法存在调用时机不同的问题,这两个方法没有合为同一个方法,需要手动分辨调用。

不过清空对象的方法是集中为一个。

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
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
using System;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
using ResourceUtils;
using PoolUtils;
using Object = UnityEngine.Object;

namespace GameObjectUtils
{
public class ObjManager : Singleton<ObjManager>
{
private Dictionary<string, GameObject> _prefabs = new Dictionary<string, GameObject>();

/// <summary>
/// 同步获取对象
/// </summary>
/// <param name="name"></param>
/// <returns></returns>
public GameObject Get(string name)
{
GameObject obj = ObjPoolManager.Ins().Get(name);

if (obj == null)
{
GameObject prefab;

_prefabs.TryGetValue(name, out prefab);

if (prefab == null)
{
prefab = ABManager.Ins().Load<GameObject>(name);
_prefabs.Add(name, prefab);
}

obj = Object.Instantiate(prefab);

ABManager.Ins().AddReference(name);
}

return obj;
}

/// <summary>
/// 同步获取对象(Resources)
/// </summary>
/// <param name="name"></param>
/// <returns></returns>
public GameObject GetRes(string name)
{
GameObject obj = ObjPoolManager.Ins().Get(name);
if (obj == null)
{
GameObject prefab;

_prefabs.TryGetValue(name, out prefab);

if (prefab == null)
{
prefab = Resources.Load<GameObject>(name);
_prefabs.Add(name, prefab);
}

obj = Object.Instantiate(prefab);

ABManager.Ins().AddReference(name);
}

return obj;
}

/// <summary>
/// 异步获取对象,主要用于提前加载prefab
/// </summary>
/// <param name="name"></param>
/// <param name="callback"></param>
public void GetAsync(string name, Action<GameObject> callback)
{
GameObject prefab;

_prefabs.TryGetValue(name, out prefab);

if (prefab == null)
{
ABManager.Ins().LoadAsync<GameObject>(name, res =>
{
callback?.Invoke(res);
_prefabs.Add(name, prefab);
});
}
}

/// <summary>
/// 回收对象
/// </summary>
/// <param name="name"></param>
/// <param name="obj"></param>
public void Recycle(string name, GameObject obj)
{
ObjPoolManager.Ins().Recycle(name, obj);
}

/// <summary>
/// 销毁对象
/// </summary>
/// <param name="name"></param>
/// <param name="obj"></param>
public void Release(string name, GameObject obj)
{
Object.Destroy(obj);
ABManager.Ins().AddReference(name,false);
}


/// <summary>
/// 监测空闲资源并卸载
/// </summary>
public void CheckRelease()
{
var keys = _prefabs.Keys.ToList();
foreach (var key in keys)
{
int reference = ABManager.Ins().GetReference(key);
if (reference == 0)
{
ABManager.Ins().Release(key);
_prefabs.Remove(key);
}
}
}

/// <summary>
/// 清空
/// </summary>
public void Clear()
{
ObjPoolManager.Ins().Clear();;
ABManager.Ins().Clear();
_prefabs.Clear();
}
}
}

代码

ResInfo
1
2
3
4
5
6
7
8
9
10
11
12
13
14
using System;
using UnityEngine.ResourceManagement.AsyncOperations;

namespace ResourceUtils
{
public class ResInfo
{
public string name = String.Empty;

public int reference = 0;

public AsyncOperationHandle handle;
}
}
ABLoader
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
121
122
123
using System;
using UnityEngine;
using UnityEngine.AddressableAssets;
using UnityEngine.ResourceManagement.AsyncOperations;

namespace ResourceUtils
{
public class ABLoader
{
private ResInfo _res;

private bool _isLoaded = false;

// private List<>

public ABLoader(string name)
{
_res = new ResInfo();
_res.name = name;
}

/// <summary>
/// 增加引用
/// </summary>
/// <param name="add">true 增加,false 减少</param>
public void AddReference(bool add = true)
{
if (add)
{
_res.reference++;
}
else
{
_res.reference--;
}
}

/// <summary>
/// 获取引用
/// </summary>
/// <returns></returns>
public int GetReference()
{
return _res.reference;
}

/// <summary>
/// 异步加载
/// </summary>
/// <param name="callback"></param>
/// <typeparam name="T"></typeparam>
public void LoadAsync<T>(Action<T> callback = null) where T:class
{
if (_isLoaded)
{
if (_res.handle.IsDone)
{
callback?.Invoke(_res.handle.Result as T);
}
else
{
Loading(callback);
}
}
else
{
Loading(callback);
}
}

/// <summary>
/// 同步加载
/// </summary>
/// <typeparam name="T"></typeparam>
/// <returns></returns>
public T Load<T>() where T:class
{
_isLoaded = true;
_res.handle = Addressables.LoadAssetAsync<T>(_res.name);
T obj = _res.handle.WaitForCompletion() as T;
_isLoaded = false;
Debug.Log("同步加载完成");

return obj;
}

/// <summary>
/// 释放
/// </summary>
public void Release()
{
if (_isLoaded)
{
_isLoaded = false;
Addressables.Release(_res.handle);
}
}

/// <summary>
/// 加载
/// </summary>
/// <param name="callback"></param>
/// <typeparam name="T"></typeparam>
private void Loading<T>(Action<T> callback) where T:class
{
_isLoaded = true;
_res.handle = Addressables.LoadAssetAsync<T>(_res.name);
_res.handle.Completed += result =>
{
if (result.Status == AsyncOperationStatus.Succeeded)
{
T obj = result.Result as T;
callback?.Invoke(obj);
}
else
{
callback?.Invoke(null);
Debug.LogError(_res.name + " 加载失败");
}
};
}
}
}
ABManager
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
121
122
123
124
125
126
127
128
using System;
using System.Collections.Generic;

namespace ResourceUtils
{
public class ABManager : Singleton<ABManager>
{
private Dictionary<string, ABLoader> _loaders = new Dictionary<string, ABLoader>();

private Dictionary<string, int> _resourceCount = new Dictionary<string, int>();

/// <summary>
/// 异步加载
/// </summary>
/// <param name="name"></param>
/// <param name="callback"></param>
/// <param name="loader"></param>
/// <typeparam name="T"></typeparam>
public void LoadAsync<T>(string name, Action<T> callback) where T : class
{
ABLoader loader;
_loaders.TryGetValue(name, out loader);

if (loader == null)
{
loader = new ABLoader(name);
_loaders.Add(name, loader);
}

loader.LoadAsync(callback);
}

/// <summary>
/// 同步加载
/// </summary>
/// <param name="name"></param>
/// <param name="loader"></param>
/// <typeparam name="T"></typeparam>
/// <returns></returns>
public T Load<T>(string name) where T : class
{
ABLoader loader;
_loaders.TryGetValue(name, out loader);

if (loader == null)
{
loader = new ABLoader(name);
_loaders.Add(name, loader);
}

T obj = loader.Load<T>();
return obj;
}

/// <summary>
/// 添加引用
/// </summary>
/// <param name="name">资源名</param>
/// <param name="add">true 添加,false 减少</param>
public void AddReference(string name, bool add = true)
{
if (_loaders.ContainsKey(name))
{
_loaders[name].AddReference(add);
}
else
{
if (!_resourceCount.TryAdd(name, 1))
{
if (add)
{
_resourceCount[name]++;
}
else
{
_resourceCount[name]--;
}
}
}
}

/// <summary>
/// 获取引用
/// </summary>
/// <param name="name"></param>
/// <returns></returns>
public int GetReference(string name)
{
if (_loaders.ContainsKey(name))
{
return _loaders[name].GetReference();
}
else
{
return _resourceCount[name];
}
}

/// <summary>
/// 移除加载器
/// </summary>
/// <param name="name"></param>
public void Release(string name)
{
ABLoader loader;
_loaders.TryGetValue(name, out loader);
if (loader != null)
{
loader.Release();
}

_loaders.Remove(name);
}

/// <summary>
/// 完全清除
/// </summary>
public void Clear()
{
foreach (var loader in _loaders)
{
loader.Value.Release();
}

_loaders = null;
}
}
}
ObjPoolManager
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
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
using System.Collections.Generic;
using System.Linq;
using GameObjectUtils;
using UnityEngine;

namespace PoolUtils
{
public class ObjPoolManager : Singleton<ObjPoolManager>
{
enum ReleaseFlag
{
New,
Old
}

private Transform _root;

private Dictionary<string, Stack<GameObject>> _pool = new Dictionary<string, Stack<GameObject>>();

private Dictionary<string, ReleaseFlag> _releaseFlags = new Dictionary<string, ReleaseFlag>();

/// <summary>
/// 水位线
/// </summary>
private int _waterline = 10;

public void Init()
{
_root = new GameObject().transform;
_root.name = "ObjPoolRoot";
_root.gameObject.SetActive(false);
}

/// <summary>
/// 获取对象
/// </summary>
/// <param name="name"></param>
/// <returns></returns>
public GameObject Get(string name)
{
Stack<GameObject> stack;

GameObject obj = null;

_pool.TryGetValue(name, out stack);

stack?.TryPop(out obj);

_releaseFlags[name] = ReleaseFlag.New;

return obj;
}

/// <summary>
/// 回收对象
/// </summary>
/// <param name="name"></param>
/// <param name="obj"></param>
public void Recycle(string name, GameObject obj)
{
//回收到对象池
Stack<GameObject> stack;
_pool.TryGetValue(name, out stack);

if (stack == null)
{
stack = new Stack<GameObject>();
_pool[name] = stack;
}

stack.Push(obj);

//设置对象到对象池根节点

obj.transform.SetParent(_root);

_releaseFlags[name] = ReleaseFlag.New;
}

/// <summary>
/// 检测闲置对象池并清除
/// </summary>
public void CheckRelease()
{
var keys = _pool.Keys.ToList();

foreach (var key in keys)
{
Stack<GameObject> stack = _pool[key];

ReleaseFlag flag = _releaseFlags[key];

switch (flag)
{
case ReleaseFlag.New:

while (stack.Count > _waterline)
{
GameObject obj = stack.Pop();
ObjManager.Ins().Release(key, obj);
}

_releaseFlags[key] = ReleaseFlag.Old;

break;
case ReleaseFlag.Old:

while (stack.Count > 0)
{
GameObject obj = stack.Pop();
ObjManager.Ins().Release(key, obj);
}

_pool.Remove(key);
_releaseFlags.Remove(key);

break;
}
}
}

/// <summary>
/// 清空对象池
/// </summary>
public void Clear()
{
foreach (var data in _pool)
{
foreach (var obj in data.Value)
{
ObjManager.Ins().Release(data.Key,obj);
}
}

_pool.Clear();
}
}
}
ObjManager
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
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
using System;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
using ResourceUtils;
using PoolUtils;
using Object = UnityEngine.Object;

namespace GameObjectUtils
{
public class ObjManager : Singleton<ObjManager>
{
private Dictionary<string, GameObject> _prefabs = new Dictionary<string, GameObject>();

/// <summary>
/// 同步获取对象
/// </summary>
/// <param name="name"></param>
/// <returns></returns>
public GameObject Get(string name)
{
GameObject obj = ObjPoolManager.Ins().Get(name);

if (obj == null)
{
GameObject prefab;

_prefabs.TryGetValue(name, out prefab);

if (prefab == null)
{
prefab = ABManager.Ins().Load<GameObject>(name);
_prefabs.Add(name, prefab);
}

obj = Object.Instantiate(prefab);

ABManager.Ins().AddReference(name);
}

return obj;
}

/// <summary>
/// 同步获取对象(Resources)
/// </summary>
/// <param name="name"></param>
/// <returns></returns>
public GameObject GetRes(string name)
{
GameObject obj = ObjPoolManager.Ins().Get(name);
if (obj == null)
{
GameObject prefab;

_prefabs.TryGetValue(name, out prefab);

if (prefab == null)
{
prefab = Resources.Load<GameObject>(name);
_prefabs.Add(name, prefab);
}

obj = Object.Instantiate(prefab);

ABManager.Ins().AddReference(name);
}

return obj;
}

/// <summary>
/// 异步获取对象,主要用于提前加载prefab
/// </summary>
/// <param name="name"></param>
/// <param name="callback"></param>
public void GetAsync(string name, Action<GameObject> callback)
{
GameObject prefab;

_prefabs.TryGetValue(name, out prefab);

if (prefab == null)
{
ABManager.Ins().LoadAsync<GameObject>(name, res =>
{
callback?.Invoke(res);
_prefabs.Add(name, prefab);
});
}
}

/// <summary>
/// 回收对象
/// </summary>
/// <param name="name"></param>
/// <param name="obj"></param>
public void Recycle(string name, GameObject obj)
{
ObjPoolManager.Ins().Recycle(name, obj);
}

/// <summary>
/// 销毁对象
/// </summary>
/// <param name="name"></param>
/// <param name="obj"></param>
public void Release(string name, GameObject obj)
{
Object.Destroy(obj);
ABManager.Ins().AddReference(name,false);
}


/// <summary>
/// 监测空闲资源并卸载
/// </summary>
public void CheckRelease()
{
var keys = _prefabs.Keys.ToList();
foreach (var key in keys)
{
int reference = ABManager.Ins().GetReference(key);
if (reference == 0)
{
ABManager.Ins().Release(key);
_prefabs.Remove(key);
}
}
}

/// <summary>
/// 清空
/// </summary>
public void Clear()
{
ObjPoolManager.Ins().Clear();;
ABManager.Ins().Clear();
_prefabs.Clear();
}
}
}

测试用例

测试用例引用了时间轮定时器

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
using System;
using ResourceUtils;
using GameObjectUtils;
using PoolUtils;
using Timer;
using UnityEditor;
using UnityEngine;

namespace Script
{
public class ABTest : MonoBehaviour
{
private void Awake()
{
TimerUtils.Init();
ObjPoolManager.Ins().Init();

#if UNITY_EDITOR
EditorApplication.playModeStateChanged += (PlayModeStateChange state) =>
{
//ConsoleUtils.Log("运行状态改变",state);
if (state == PlayModeStateChange.ExitingPlayMode)
{
TimerUtils.Stop();
}
};
#endif
}

private void Start()
{
var obj = ObjManager.Ins().Get("pre_face");

TimerUtils.Once(2000, () => { ObjManager.Ins().Recycle("pre_face", obj); });

TimerUtils.Loop(5000, () =>
{
ObjPoolManager.Ins().CheckRelease();
ObjManager.Ins().CheckRelease();
}, 1000);
}
}
}

项目

若干功能的测试项目,目前更新在 xLua 分支。

更新日志

2024-06-11

  1. 新增 Resources 文件夹资源管理。

2024-06-10

  1. 更新基本内容。

评论