unity学习24:场景scene相关生成,加载,卸载,加载进度,异步加载场景等
目录
1 场景数量 SceneManager.sceneCount
2 直接代码生成新场景 SceneManager.CreateScene
3 场景的加载
3.1 用代码加载场景,仍然build setting里先加入配置
3.2 卸载场景 SceneManager.UnloadSceneAsync();
3.3 同步加载场景 SceneManager.LoadScene
3.3.1 两种加载方式
3.4 异步加载场景
3.5 测试代码
3.5.1 有问题的测试代码
(代码创建的新Scene 需要手动去build Setting添加?)
3.6 场景的叠加效果
4 同步和异步
4.1 同步和异步
4.2 多线程 协程
4.2.1 多线程
4.2.2 协程
4.3 异步加载场景UnityEngine.SceneManagement;
4.3.1 除了默认的,还需要额外导入其他包
4.3.2 测试异步跳转场景,可成功
4.3.3 详细代码和注释
4.3.4 注释内容
5 加载进度
5.1 对应的协程的进度 operation1.progress
5.2 关于进度的数值
5.3 对应代码
5.4 如何做个显示的UI进度条
6 按条件跳转新地图
6.1 延迟跳转
6.2 测试代码
1 场景数量 SceneManager.sceneCount
- //统计已经加载的场景数量
- Debug.Log(SceneManager.sceneCount);
2 直接代码生成新场景 SceneManager.CreateScene
- // 代码里可以创建新场景:直接用代码
- Scene scene3=SceneManager.CreateScene("Scene3");
3 场景的加载
3.1 用代码加载场景,仍然build setting里先加入配置
- 也是要注意,新场景的加载模式
- 用代码创建的Scene也可以现在build setting里先加入配置
Scene 'Scene3' couldn't be loaded because it has not been added to the build settings or the AssetBundle has not been loaded.
To add a scene to the build settings use the menu File->Build Settings...
UnityEngine.SceneManagement.SceneManager:LoadScene (string)
SceneTest:Start () (at Assets/SceneTest.cs:43)
3.2 卸载场景 SceneManager.UnloadSceneAsync();
- 卸载场景
- SceneManager.UnloadSceneAsync("Scene3");
3.3 同步加载场景 SceneManager.LoadScene
- //同步加载场景,卡顿,等待
- SceneManager.LoadScene("Scene3");
- SceneManager.loadScene("scene3",LoadSceneMode.Single);
- SceneManager.loadScene("scene3",LoadSceneMode.Additive);
3.3.1 两种加载方式
只加载1个,替换之前的Scene
- SceneManager.LoadScene("Scene2")
- 默认方式是 LoadSceneMode.Single
- SceneManager.LoadScene("Scene2",LoadSceneMode.Single)
新的场景加载,老的也在,相当于同时都加载生效
- SceneManager.LoadScene("Scene2",LoadSceneMode.Additive)
3.4 异步加载场景
- //异步加载场景
- //SceneManager.loadSceneAsync("scene3");
3.5 测试代码
3.5.1 有问题的测试代码
(代码创建的新Scene 需要手动去build Setting添加?)
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.SceneManagement;
public class SceneTest : MonoBehaviour
{
// Start is called before the first frame update
void Start()
{
///先查看当前Scene
//获取当前场景
Scene scene1=SceneManager.GetActiveScene();
//场景名称
Debug.Log(scene1.name);
//场景路径
Debug.Log(scene1.path);
//场景索引
Debug.Log(scene1.buildIndex);
GameObject[] gb1=scene1.GetRootGameObjects();
Debug.Log(gb1.Length);
//跳转场景
//SceneManager.LoadScene(2);
//SceneManager.LoadScene("Scene2");
//调用异步的Start1
Start1();
//统计已经加载的场景数量
Debug.Log(SceneManager.sceneCount);
//创建新场景:直接用代码
Scene scene3=SceneManager.CreateScene("Scene3");
//卸载场景
//SceneManager.UnloadSceneAsync("Scene3");
//同步加载场景,卡顿,等待
SceneManager.LoadScene("Scene3");
//SceneManager.loadScene("scene3",LoadSceneMode.Single);
//SceneManager.loadScene("scene3",LoadSceneMode.Additive);
//异步加载场景
//SceneManager.loadSceneAsync("scene3");
}
async void Start1()
{
AsyncOperation asyncLoad = SceneManager.LoadSceneAsync(2);
// 等待场景加载完成
while (!asyncLoad.isDone)
{
await System.Threading.Tasks.Task.Yield();
}
// 场景加载完成后获取信息
Debug.Log(SceneManager.GetActiveScene().name);
//获取当前场景
//新定义1个scene2 Scene scene2=
Scene scene2=SceneManager.GetActiveScene();
//场景是否已经加载, 但是可能还没有激活新的Scene
Debug.Log(scene2.isLoaded);
///再次查看当前Scene
//场景名称
Debug.Log(scene2.name);
//场景路径
Debug.Log(scene2.path);
//场景索引
Debug.Log(scene2.buildIndex);
GameObject[] gb2=scene2.GetRootGameObjects();
Debug.Log(gb2.Length);
}
// Update is called once per frame
void Update()
{
}
}
3.6 场景的叠加效果
- 多个场景一起生效,叠加,效果
- 从 Hierarchy 窗口里可以看到
- 现在有3个场景,同时生效了,场景内的gb也都显示出来了
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.SceneManagement;
public class SceneTest : MonoBehaviour
{
// Start is called before the first frame update
void Start()
{
///先查看当前Scene
//获取当前场景
Scene scene1=SceneManager.GetActiveScene();
//场景名称
Debug.Log(scene1.name);
//场景路径
Debug.Log(scene1.path);
//场景索引
Debug.Log(scene1.buildIndex);
GameObject[] gb1=scene1.GetRootGameObjects();
Debug.Log(gb1.Length);
//跳转场景
//SceneManager.LoadScene(2);
//SceneManager.LoadScene("Scene2");
//调用异步的Start1
Start1();
//统计已经加载的场景数量
Debug.Log(SceneManager.sceneCount);
//创建新场景:直接用代码
Scene scene3=SceneManager.CreateScene("Scene3");
//卸载场景
//SceneManager.UnloadSceneAsync("Scene3");
//同步加载场景,卡顿,等待
SceneManager.LoadScene("Scene3");
//SceneManager.loadScene("scene3",LoadSceneMode.Single);
//SceneManager.loadScene("scene3",LoadSceneMode.Additive);
//异步加载场景
//SceneManager.loadSceneAsync("scene3");
}
async void Start1()
{
AsyncOperation asyncLoad = SceneManager.LoadSceneAsync(2,LoadSceneMode.Additive);
// 等待场景加载完成
while (!asyncLoad.isDone)
{
await System.Threading.Tasks.Task.Yield();
}
// 场景加载完成后获取信息
Debug.Log(SceneManager.GetActiveScene().name);
//获取当前场景
//新定义1个scene2 Scene scene2=
Scene scene2=SceneManager.GetActiveScene();
//场景是否已经加载, 但是可能还没有激活新的Scene
Debug.Log(scene2.isLoaded);
///再次查看当前Scene
//场景名称
Debug.Log(scene2.name);
//场景路径
Debug.Log(scene2.path);
//场景索引
Debug.Log(scene2.buildIndex);
GameObject[] gb2=scene2.GetRootGameObjects();
Debug.Log(gb2.Length);
}
// Update is called once per frame
void Update()
{
}
}
4 同步和异步
4.1 同步和异步
- 同步: 纯线性
- 异步: 也是线性,但是只是逻辑上还是线性。但是有了分支,把消耗时间的操作,放到其他线程里去执行
下面几个图都是网上找的参考的
4.2 多线程 协程
- 多线程
- 协程
4.2.1 多线程
多线程是一种同时运行多个执行路径的技术,每个执行路径称为一个线程。
多个线程可以在多核CPU上真正并行运行,或者在单核CPU上通过时间片轮转模拟并发。多线程通过操作系统调度,能够充分利用计算资源,在处理I/O密集型和CPU密集型任务时具有优势。
特点:
每个线程都有独立的栈空间和执行路径。
线程之间可以共享内存数据,因此需要进行同步控制,以避免数据竞争和死锁问题。
线程调度由操作系统控制,可能涉及上下文切换,带来一定的开销。4.2.2 协程
协程是一种比线程更轻量级的并发实现方式。
与多线程不同,协程不是由操作系统调度,而是由编程语言或运行时环境来管理。
协程可以在需要时暂停自身,并将控制权交还给调用方,稍后再恢复执行。
它们适用于处理需要频繁暂停和恢复的任务,如异步I/O操作。
特点:
协程不会并行运行,单个线程中可以运行多个协程。
协程之间共享执行线程,但不需要上下文切换,切换开销非常小。
协程适用于I/O密集型任务,如网络请求、文件读写等,能够实现高效的异步操作。
4.3 异步加载场景UnityEngine.SceneManagement;
4.3.1 除了默认的,还需要额外导入其他包
using UnityEngine;
using UnityEngine.SceneManagement;
4.3.2 测试异步跳转场景,可成功
去掉各种注释的代码如下
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
//导入场景管理类
using UnityEngine.SceneManagement;
public class AsyncTest : MonoBehaviour
{
void Start()
{
StartCoroutine(loadScene());
}
IEnumerator loadScene()
{
// 异步的协程
AsyncOperation operation1=SceneManager.LoadSceneAsync(2);
yield return operation1;
}
// Update is called once per frame
void Update()
{
}
}
4.3.3 详细代码和注释
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
//导入场景管理类
using UnityEngine.SceneManagement;
public class AsyncTest : MonoBehaviour
{
//异步,需要先声明SceneManager.LoadSceneAsync(2)的返回值
//AsyncOperation operation1;
// Start is called before the first frame update
void Start()
{
//协程不能直接LoadScene(),必须新建一个协程方法StartCoroutine
StartCoroutine(loadScene());
}
//以协程的方法来异步加载场景
//必须单独写一个 loadScene()方法,而不能用Application.LoadScene()方法
//这个异步的方法,有返回值,返回值是固定的IEnumerator
IEnumerator loadScene()
{
// 异步的协程
// SceneManager.LoadSceneAsync()有返回值,返回值类型AsyncOperation
AsyncOperation operation1=SceneManager.LoadSceneAsync(2);
yield return operation1;
}
// Update is called once per frame
void Update()
{
}
}
4.3.4 注释内容
//异步,需要先声明SceneManager.LoadSceneAsync(2)的返回值
// 也是可以在函数内,使用 operation1 时当时声明, 但是函数内声明的,函数外就无法条用operation1,所以为了外面可以调用,还是在外面声明
//AsyncOperation operation1;
// Start is called before the first frame update
void Start()
{
//协程不能直接LoadScene(),必须新建一个协程方法StartCoroutine
StartCoroutine(loadScene());
}
//以协程的方法来异步加载场景
//必须单独写一个 loadScene()方法,而不能用Application.LoadScene()方法
//这个异步的方法,有返回值,返回值是固定的IEnumerator
IEnumerator loadScene()
{
// 异步的协程
// SceneManager.LoadSceneAsync()有返回值,返回值类型AsyncOperation
// 也可以在函数外,最开始声明
AsyncOperation operation1=SceneManager.LoadSceneAsync(2);
yield return operation1;
}
5 加载进度
5.1 对应的协程的进度 operation1.progress
- operation1.progress
- 适合放在 void Update() 方法里去实现,因为逐帧加载。
5.2 关于进度的数值
- unity里,输出进度 0-0.9,其中0.9 在unity里就是100%
- 实际游戏里
- 有的0.9-100%飞速,有的是按比例0.9折算到100%
- 场景小异步加载也就很快
5.3 对应代码
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
//导入场景管理类
using UnityEngine.SceneManagement;
public class AsyncTest : MonoBehaviour
{
//异步,需要先声明SceneManager.LoadSceneAsync(2)的返回值
AsyncOperation operation1;
// Start is called before the first frame update
void Start()
{
//协程不能直接LoadScene(),必须新建一个协程方法StartCoroutine
StartCoroutine(loadScene());
}
//以协程的方法来异步加载场景
//必须单独写一个 loadScene()方法,而不能用Application.LoadScene()方法
//这个异步的方法,有返回值,返回值是固定的IEnumerator
IEnumerator loadScene()
{
// 异步的协程
// SceneManager.LoadSceneAsync()有返回值,返回值类型AsyncOperation
operation1=SceneManager.LoadSceneAsync(2);
yield return operation1;
}
// Update is called once per frame
void Update()
{
Debug.Log(operation1.progress);
}
}
5.4 如何做个显示的UI进度条
。。。。是个问题,学到了再说
6 按条件跳转新地图
6.1 延迟跳转
- 跳转地图也可以不是即可生效的
- 可以加定时器, 按任意键跳转,下面的例子可以实现10秒后跳转
- 除了延迟跳转新地图,也可以设置其他条件:比如 响应键盘,UI等等
6.2 测试代码
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
//导入场景管理类
using UnityEngine.SceneManagement;
public class AsyncTest : MonoBehaviour
{
//异步,需要先声明SceneManager.LoadSceneAsync(2)的返回值
AsyncOperation operation1;
float timer1=0;
// Start is called before the first frame update
void Start()
{
//协程不能直接LoadScene(),必须新建一个协程方法StartCoroutine
StartCoroutine(loadScene());
}
//以协程的方法来异步加载场景
//必须单独写一个 loadScene()方法,而不能用Application.LoadScene()方法
//这个异步的方法,有返回值,返回值是固定的IEnumerator
IEnumerator loadScene()
{
// 异步的协程
// SceneManager.LoadSceneAsync()有返回值,返回值类型AsyncOperation
operation1=SceneManager.LoadSceneAsync(2);
operation1.allowSceneActivation=false;
yield return operation1;
}
// Update is called once per frame
void Update()
{
Debug.Log(operation1.progress);
timer1=timer1+Time.deltaTime;
if (timer1>10)
{
operation1.allowSceneActivation=true;
}
}
}