资源的加载卸载

资源的加载

资源的加载卸载可以参见Unity基础-Resources资源动态加载

场景的加载

其中,最常见的就是场景的加载,场景加载的核心分类有:

  • 同步加载
  • 异步加载
    • 多场景叠加加载
  • 流式场景加载

同步加载

同步加载仅适用于极小的Demo以及编辑器测试,在日常开发中一般不使用。

1
2
3
using UnityEngine.SceneManagement;

SceneManager.LoadScene("BattleScene");

异步加载

异步加载分两种加载模式:

  • 替换旧场景:LoadSceneMode.Single
  • 叠加新场景:LoadSceneMode.Additive

这两种加载模式是作为缺省参数传入LoadSceneAsync中的,不写默认就是LoadSceneMode.Single,这个是LoadSceneAsync的源码原型:

1
AsyncOperation LoadSceneAsync(string sceneName, LoadSceneMode mode = LoadSceneMode.Single);
  • 基础异步加载(带进度条)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
IEnumerator LoadSceneAsync(string sceneName)
{
AsyncOperation asyncLoad = SceneManager.LoadSceneAsync(sceneName);

asyncLoad.allowSceneActivation = false;

while(!asyncLoad.isDone)
{
float progress = Mathf.Clamp01(asyncLoad.progress / 0.9f);

// 控制台打印信息,可给UI控件赋值
Debug.Log("加载进度:" + progress);

if(asyncLoad.progress > 0.9f)
{
asyncLoad.allowSceneActivation = true;
}

yield return null;
}
}

其中,IEnumerator是使用异步加载的标志,AsyncOperation是异步加载的控制器,他会告诉你现在异步加载到哪一步了,可以表示出异步加载的状态。

1
asyncLoad.allowSceneActivation = false;

这一句话是先将可以切换场景的状态设置为 否 。这样做的目的是防止进度条还没加载完就切场景了,防止给玩家带来的卡顿感。

接下来的循环是说:当异步加载还没完成时 -> 计算每一帧的加载进度 -> 表示在UI控件上 -> 如果加载完就切场景

其中,除以0.9的原因是:asyncLoad.progress这个加载进度只会跑到0.9就停了

  • 0 ~ 0.9:真正加载场景资源
  • 0.9 ~ 1.0:只有激活场景后,才会从0.9跳到1.0

所以说,除了之后就会让他进度条能够到达100%

  • 多场景叠加加载

核心用途:

  1. 主场景+UI场景+战斗场景 同时存在,不用反复销毁重建
  2. 常驻大地图 + 分块流式加载
1
2
3
4
5
// 叠加加载UI场景,不销毁当前主场景
SceneManager.LoadSceneAsync("UIScene", LoadSceneMode.Additive);

// 卸载叠加的场景
SceneManager.UnLoadSceneAsync("UIScene");

流式场景加载

配合 Addressables / YooAsset(资源管理系统)实现:

  • 把大地图切成多个小块场景
  • 玩家靠近时自动加载,远离时自动卸载
  • 全程无感知,内存占用极低

对象池

对象池就是提前创建一个资源池,把需要频繁使用的预制体提前生成出来,一开始全部设为失活状态放入池中。游戏里需要使用时,直接从池子中取出并激活使用;使用完毕后不销毁,重置失活状态并放回池中循环复用。这种方式避免了游戏运行中频繁创建和销毁物体,有效减少GC垃圾回收带来的卡顿,极大提升游戏运行性能。

以下是创建一个对象池的例子:

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
public class ObjectPool
{
private Queue<GameObject> _poolQueue = new Queue<GameObject>();
private GameObject _prefab;

// 初始化对象池
public ObjectPool(GameObject prefab)
{
_prefab = prefab;

for(int i = 0; i < 10; i ++)
{
GameObject obj = GameObject.Instantiate(_prefab);
obj.SetActive(false);
_poolQueue.EnQueue(obj);
}
}

// 拿出对象
public GameObject Get()
{
if(_poolQueue.Count == 0)
{
GameObject obj = GameObject.Instantiate(_prefab);
obj.SetActive(false);
_poolQueue.EnQueue(obj);
}

GameObject take = _poolQueue.DeQueue();
take.SetActive(true);

return take;
}

// 放回对象
public GameObject Recycle(GameObject obj)
{
obj.SetActive(false);
_poolQueue.EnQueue(obj);
}
}

打包压缩

打包压缩就是把零散的游戏资源打包成整包,然后压缩体积。这个操作直接决定安装包大小、下载速度、加载性能。

热更新

热更新就是游戏不需要玩家重新下载安装完整安装包,在游戏运行过程中,联网对比版本差异,只下载改动的少量资源、代码,更新后直接生效,不用重启重装。