2.9 KiB
1.加载界面卡顿
我们在点击开始游戏的时候加载到游戏界面的过程中会卡顿,他会先卡顿一秒然后才进入到加载页面,他的问题就是SceneManager.LoadSceneAsync(). Unity 的所有核心逻辑,包括UI渲染、输入处理和大部分游戏逻辑的执行,都发生在主线程上。如果主线程被一个耗时很长的任务(比如一次性从硬盘读取大量数据并解压)卡住,那么整个应用程序就会冻结——画面停止渲染,UI无法响应。这就是你遇到的“卡顿”。
-
SceneManager.LoadSceneAsync()的“陷阱”-
用途:它的设计初衷是为了在后台线程加载场景资源,避免长时间冻结主线程。
-
原理:虽然名字里有
Async(异步),但它在被调用的第一帧,仍然需要在主线程上执行一些同步的准备工作。这包括:从磁盘定位场景文件、读取场景的元数据、准备反序列化等等。如果你的场景很大,有很多GameObject和资源引用,这个“准备工作”本身就可能耗时几十到几百毫秒,足以造成肉眼可见的卡顿。 -
好/不好:这个函数本身是好的,是异步加载的唯一标准方式。但不好的地方在于,开发者很容易误解它,以为调用它的瞬间就是完全异步的。 代码1的问题剖析:
-
// 在主线程的某个 Update 或按钮点击事件中被调用
public void Load(string next)
{
LoadingViewController.Instance.Open(); // 1. 请求打开UI
LoginViewController.Instance.Close();
StartCoroutine(LoadSceneAsync(next)); // 2. 启动协程
}
private IEnumerator LoadSceneAsync(string next)
{
// 3. 协程在下一帧开始执行
var operation = SceneManager.LoadSceneAsync(next); // 4. 问题点!
// ...
}
执行流程与卡顿原因:
-
点击按钮(第N帧):
Load()方法被调用。它请求打开 Loading UI。但这只是一个请求,真正的UI绘制要等到这一帧的渲染阶段。 -
启动协程:
StartCoroutine启动了协程,但协程的代码要到**下一帧(第N+1帧)**的Update阶段才会开始执行。 -
协程开始(第N+1帧): 协程的第一行代码
SceneManager.LoadSceneAsync(next)被执行。 -
主线程阻塞:此时,
LoadSceneAsync的同步准备阶段开始,它会阻塞主线程。如果场景很大,主线程可能会在这里卡住 1-2 秒。 -
卡顿后果:因为主线程被阻塞,第N帧请求绘制的 Loading UI 根本没有机会被渲染出来。所以你的游戏画面会停留在上一个界面(LoginView),直到
LoadSceneAsync的同步阶段完成。 -
加载飞快:当卡顿结束后,
LoadSceneAsync已经把大部分重活都干完了,operation.progress的值可能直接就是0.8或接近0.9。所以你的进度条看起来一瞬间就加载完了。