预加载

ObjectPoolManager添加API

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
/// <summary>
/// 预加载GameObject
/// </summary>
/// <param name="path">路径</param>
/// <param name="count">预加载个数</param>
/// <param name="clear">跳场景是否清除</param>
public void PreloadGameObject(string path,int count = 1,bool clear = false)
{
List<GameObject> tempGameObjectList = new List<GameObject>(count);
for (int i = 0; i < count; i++)
{
GameObject obj = InstantiateObject(path, false, bClear:clear);
tempGameObjectList.Add(obj);
}
for (int i = 0; i < count; i++)
{
GameObject obj = tempGameObjectList[i];
ReleaseObject(obj);//注意其他参数是默认的,这意味着预加载对象的对象池缓存是无限的,还必须有回收的父级
obj = null;
}
tempGameObjectList.Clear();
}

注意ReleaseObject的参数是默认的,这意味着预加载对象的对象池缓存是无限的,还必须有回收的父级

预加载示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
using UnityEngine;

public class GameStart : MonoBehaviour
{
private GameObject m_GameObject;
private void Awake()
{
DontDestroyOnLoad(gameObject);
AssetBundleManager.Instance.LoadAssetBundleConfig();
ResourceManager.Instance.Init(this);//初始化异步加载
ObjectPoolManager.Instance.Init(transform.Find("RecyclePoolTrans"),transform.Find("SceneTrans"));
}
private void Start()
{
//预加载
ObjectPoolManager.Instance.PreLoadGameObject("Assets/Prefabs/Attack.prefab",20);
}
}

对象池取消异步加载

如果一个对象在异步加载的过程中不需要了(比如多人游戏中其他玩家一闪而过),那么就需要异步加载。

为了准确取消每个异步加载方法,我们需要让每个对象池的异步加载方法都返回一个GUID。

我们让Resource Manager提供一个方法来返回这个GUID

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public class ResourceManager : SingletonPattern<ResourceManager>
{
//...
protected long m_Guid = 0;
//...
/// <summary>
/// 创建异步任务的GUID
/// </summary>
/// <returns>Guid</returns>
public long CreateGuid()
{
return m_Guid++;
}
//...
}

修改ObjectPool manager的异步加载方法AsyncInstantiateObject,让它能返回自己的GUID

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

//根据异步的guid储存ResourceObj,来判断是否正在异步加载
protected Dictionary<long,ResourceObj> m_AsyncResObjs = new Dictionary<long,ResourceObj>();//+++

public long AsyncInstantiateObject(//++
string path,
OnAsyncObjFinish dealFinish,
LoadResPriority priority,
bool setSceneObj = false,
object param1 = null,
object param2 = null,
object param3 = null,
bool bClear = true)
{
if (string.IsNullOrEmpty(path))
{
return 0;//+++
}
//...
if (resObj != null)
{
//...
if(dealFinish != null)
{
dealFinish.Invoke(path, resObj.m_CloneObj, param1, param2, param3);
}
return resObj.m_Guid;//+++
}

long guid = ResourceManager.Instance.CreateGuid();//+++

//...
//调用ResourceManager的对象池异步加载接口
ResourceManager.Instance.AsyncLoadPoolResource(path, resObj, OnLoadResourceObjFinish, priority);
m_AsyncResObjs.Add(guid, resObj);//+++
return guid;//+++
}

void OnLoadResourceObjFinish(string path, ResourceObj resObj, object param1 = null, object param2 = null, object param3 = null)
{
//...
if(resObj.m_ResItem.m_Obj == null)
{
//...
}
else
{
//...
}
//加载完成就从缓存的正在加载的字典中移除
if(m_AsyncResObjs.ContainsKey(resObj.m_Guid))
{
m_AsyncResObjs.Remove(resObj.m_Guid);
}
//...
}

Resource Manager添加取消异步加载API

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
/// <summary>
/// 取消对象池异步加载
/// </summary>
/// <param name="res">对象池对象</param>
/// <returns>是否成功取消</returns>
public bool CancelAsyncLoad(ResourceObj res)
{
AsyncLoadResParam para = null;
if (m_LoadingAssetDic.TryGetValue(res.m_Crc, out para) && m_LoadingAssetList[(int)para.m_Priority].Contains(para))
{
for (int i = para.m_CallBackList.Count - 1; i >= 0; i--)
{
AsyncCallBack tempCallBack = para.m_CallBackList[i];
if (tempCallBack != null && res == tempCallBack.m_ResObj)
{
tempCallBack.Reset();
m_AsyncCallBackPool.Recycle(tempCallBack);
para.m_CallBackList.Remove(tempCallBack);
}
}
if (para.m_CallBackList.Count <= 0)
{
para.Reset();
m_LoadingAssetList[(int)(para.m_Priority)].Remove(para);
m_AsyncLoadResParamPool.Recycle(para);
m_LoadingAssetDic.Remove(res.m_Crc);
return true;
}
}
return false;
}

在上述代码中。m_LoadingAssetList[(int)para.m_Priority].Contains(para)用来判断此资源对象是否已经在异步加载协程中完成了。

加载一种资源只会生成一个AsyncLoadResParam对象,但是这个对象可以有很多个AsyncCallBack(有多个地方请求了这个资源对象),当我们取消异步加载时,如果这个资源已经加载完毕,我们只能删除后续的CallBack(可以看到我们是将para.m_CallBackList反向移除的);除非这个资源没有被加载出来过,此时para.m_CallBackList.Count <= 0,这才是真正取消异步加载,我们返回true。

不过在实际使用中,一旦一个资源被加载出来,所有的CallBack都会同时触发,不会出现上述前面CallBack已经触发后面CallBack没有触发的情况

Object Pool Manager添加取消异步加载的API

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
/// <summary>
/// 取消异步加载
/// </summary>
/// <param name="guid">此异步resObj的Guid</param>
public void CancelAsyncLoad(long guid)
{
ResourceObj resObj = null;
if(m_AsyncResObjs.TryGetValue(guid, out resObj) && ResourceManager.Instance.CancelAsyncLoad(resObj))
{
m_AsyncResObjs.Remove(guid);
resObj.Reset();
m_ResourceObjPool.Recycle(resObj);
}
}