Unity中UI框架的使用2-进度条跳转到主页面

本文介绍了如何在Unity中创建一个Loading面板,并通过协程控制进度条动画,当加载完成后自动跳转到主页面。详细步骤包括编写LoadingPanel脚本,控制进度条的移动,以及在条件满足时关闭Loading面板并显示主页面。

效果图:Loading面板的进度条加载完毕之后,直接跳转到主页面

 

实现方法:

1.首先要控制进度条的移动:这部分功能我们是在LoadingPanel面板上写了一个名LoadingPanel的脚本,其中利用一个协程,来控制进度条的移动。

2.其次是跳到主页面:在协程条件退出的时候,(这里我们设置的是三秒后退出协程),退出时先关闭当前UI面板,再显示主面板即可。


LoadingPanel.cs

using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;

public class LodingPanel : NBasePanel {


	void Start () {
        StartCoroutine(Loding());//开启协程
	}

    private IEnumerator Loding()
    {
        var t = Time.time;//记录一开始的时间
        var img = transform.Find("bottom/Image").GetComponent<Image>();
<think>我们有两种常见的实现异步加载场景并显示进度条的方式: 1. 使用真正的异步加载进度(AsyncOperation.progress) 2. 使用模拟进度条(适用于场景加载很快,但需要等待其他操作的情况) 根据用户需求:先跳转到loading加载界面,然后等待进度条加载完成后跳转场景。 步骤: 1. 首先,我们需要有一个专门的Loading场景,在这个场景中有一个进度条(Slider或Image)和显示百分比的文本。 2. 从当前场景(如开始菜单)跳转到Loading场景。 3. 在Loading场景中,开始异步加载目标场景,并显示加载进度。 注意:在异步加载时,我们通常设置allowSceneActivation为false,这样当加载到90%时(Unity异步加载到0.9时会暂停),我们可以等待进度条到100%后再激活新场景。 但是,如果我们在加载目标场景前还有其他操作(如加载资源、网络连接等),则需要将这些操作也计入进度条。 下面我们提供两种方案: 方案一:只加载场景,使用真实进度(参考引用[2]和[1]) 方案二:模拟进度条(参考引用[3]),但我们可以结合真实进度和模拟进度。 这里我们给出一个结合真实进度和额外操作的方案(扩展自引用[1]的思路)。 步骤详解: 1. 在当前场景中调用跳转到Loading场景,并传递目标场景名称(或索引)。传递参数可以使用PlayerPrefs、静态变量或SceneManager.LoadScene的参数(但Unity场景跳转本身不支持传递参数,所以常用静态变量或Persistent对象)。 2. 在Loading场景中,我们使用异步加载目标场景,同时监控加载进度,并更新进度条。 3. 如果还有额外操作,我们可以将这些操作分成多个步骤,并分配权重,计算总体进度。 由于用户需求中没有提到额外操作,我们先实现一个基本的真实进度版本。 如何传递目标场景信息? 我们可以使用一个静态类来存储目标场景的名称或索引。 例如,我们创建一个静态类SceneLoader: ```csharp public static class SceneLoader { public static string nextSceneName; } ``` 在跳转到Loading场景之前,设置nextSceneName。 在Loading场景的脚本中,我们读取nextSceneName并开始异步加载。 代码实现: Loading场景中的脚本(LoadingScreen.cs): ```csharp using UnityEngine; using UnityEngine.UI; using UnityEngine.SceneManagement; using System.Collections; public class LoadingScreen : MonoBehaviour { public Slider loadingSlider; public Text progressText; private void Start() { StartCoroutine(LoadSceneAsync(SceneLoader.nextSceneName)); } IEnumerator LoadSceneAsync(string sceneName) { AsyncOperation asyncLoad = SceneManager.LoadSceneAsync(sceneName); asyncLoad.allowSceneActivation = false; // 禁止自动激活场景 float progress = 0; // 当加载进度小于0.9时,Unity认为加载未完成,因为最后10%是在激活时完成的 while (!asyncLoad.isDone) { // 异步加载的进度在0-0.9之间,我们将其映射到0-100% progress = Mathf.Clamp01(asyncLoad.progress / 0.9f) * 100; // 0.9f是Unity加载到90%会暂停,等待激活 loadingSlider.value = progress / 100f; progressText.text = progress.ToString("F0") + "%"; // 当加载进度达到0.9(即90%)时,Unity会暂停,等待我们允许激活 if (asyncLoad.progress >= 0.9f) { // 这里可以等待一下,让进度条显示100%,或者直接激活 // 我们等待1秒,让进度条走完100% progress = 100; loadingSlider.value = 1; progressText.text = "100%"; yield return new WaitForSeconds(1); asyncLoad.allowSceneActivation = true; // 激活场景 } yield return null; } } } ``` 然后,在跳转到Loading场景之前,我们需要设置SceneLoader.nextSceneName。 例如,在开始菜单中有一个按钮,点击后跳转到Loading场景,并设置目标场景为“GameScene”: ```csharp public void OnPlayButtonClicked() { SceneLoader.nextSceneName = "GameScene"; SceneManager.LoadScene("LoadingScene"); } ``` 注意事项: 1. 需要将Loading场景添加到Build Settings中,并确保目标场景也在其中。 2. 在Loading场景中,创建一个Canvas,包含Slider和Text,并将它们拖拽到LoadingScreen脚本的对应字段。 但是,有时加载太快,进度条瞬间完成,玩家来不及看到。我们可以考虑在加载完成后等待几秒(如上面代码中的1秒)再激活场景,这样玩家可以看到100%的进度条。 如果除了场景加载还有额外操作,我们可以这样扩展: 假设我们有多个任务(包括场景加载),每个任务有一个权重。总进度是这些任务进度的加权和。 例如: 任务1:加载场景(权重0.7) 任务2:加载资源(权重0.3) 那么总进度 = 任务1进度 * 0.7 + 任务2进度 * 0.3 然后在协程中分步执行这些任务,并更新进度条。 但是,由于用户没有要求,我们只实现场景加载。 现在,我们按照用户要求,先跳转到loading界面,然后在loading界面中加载目标场景。 我们将上述代码整理如下: 步骤: 1. 创建静态类SceneLoader(用于传递目标场景名) 2. 创建Loading场景,并挂载LoadingScreen脚本到游戏物体(如Canvas)。 3. 在LoadingScreen脚本中,获取Slider和Text的引用,并在Start协程中加载目标场景。 注意:如果场景加载太快,我们可能需要人为延长加载时间(比如最少显示2秒的加载界面),但这里我们先不做。 下面给出完整代码: 静态类(可以放在任意脚本中,但注意不要放在Editor文件夹): 新建一个脚本SceneLoader.cs: ```csharp using UnityEngine; public static class SceneLoader { public static string nextSceneName; } ``` 在开始菜单中,跳转时设置: ```csharp public class StartMenu : MonoBehaviour { public void LoadGameScene() { SceneLoader.nextSceneName = "GameScene"; // 替换成你的目标场景名称 SceneManager.LoadScene("LoadingScene"); // 替换成你的Loading场景名称 } } ``` LoadingScreen.cs(挂在Loading场景的Canvas上): ```csharp using UnityEngine; using UnityEngine.UI; using UnityEngine.SceneManagement; using System.Collections; public class LoadingScreen : MonoBehaviour { public Slider progressBar; public Text progressText; void Start() { StartCoroutine(LoadAsyncOperation()); } IEnumerator LoadAsyncOperation() { // 异步加载场景 AsyncOperation gameLevel = SceneManager.LoadSceneAsync(SceneLoader.nextSceneName); gameLevel.allowSceneActivation = false; while (gameLevel.progress < 0.9f) { // 加载进度在0-0.9之间,我们将其转换到0-1(或0-100%) float progress = Mathf.Clamp01(gameLevel.progress / 0.9f); progressBar.value = progress; progressText.text = (progress * 100).ToString("F0") + "%"; yield return null; } // 当加载到0.9后,我们等待进度条显示100% // 设置进度条为100% progressBar.value = 1; progressText.text = "100%"; // 等待1秒(为了让玩家看到100%) yield return new WaitForSeconds(1); // 允许激活场景 gameLevel.allowSceneActivation = true; } } ``` 这样就实现了先跳转到loading场景,然后加载目标场景,显示进度条,加载完成后等待1秒再跳转。 注意:如果目标场景加载非常快,可能会出现一闪而过的加载界面,我们可以设置一个最小加载时间(例如至少显示2秒的加载界面),但这需要记录开始加载的时间,并在协程中等待剩余时间。 我们扩展一下,设置最小显示时间: ```csharp IEnumerator LoadAsyncOperation() { float minLoadingTime = 2.0f; // 最小加载时间(秒) float startTime = Time.realtimeSinceStartup; AsyncOperation gameLevel = SceneManager.LoadSceneAsync(SceneLoader.nextSceneName); gameLevel.allowSceneActivation = false; float progress = 0; while (gameLevel.progress < 0.9f) { progress = Mathf.Clamp01(gameLevel.progress / 0.9f); progressBar.value = progress; progressText.text = (progress * 100).ToString("F0") + "%"; yield return null; } progress = 1; progressBar.value = progress; progressText.text = "100%"; // 计算已用时间 float elapsedTime = Time.realtimeSinceStartup - startTime; if (elapsedTime < minLoadingTime) { // 如果还没到最小时间,等待剩余时间 yield return new WaitForSeconds(minLoadingTime - elapsedTime); } gameLevel.allowSceneActivation = true; } ``` 这样,即使加载很快,也会至少显示2秒的加载界面。 以上就是完整的实现。 注意:这个最小时间是在场景加载到90%后开始计算的,所以实际加载时间可能比最小时间要长(如果加载时间本身就超过了最小时间,那么加载完成后立即跳转)。 最后,提供相关问题: </think>### Unity场景跳转进度条加载实现方案 在Unity中实现先跳转到Loading界面,再加载目标场景的核心思路是通过异步加载机制控制进度条显示。以下是完整实现方案: #### 步骤1:场景设置 1. **创建两个场景**: - `MainScene`:主场景(如开始菜单) - `LoadingScene`:加载过渡场景(包含进度条UI2. **Loading场景UI配置**: - 添加Slider组件作为进度条 - 添加Text组件显示百分比 - 示例UI层级: ``` Canvas ├─ Background (Image) ├─ ProgressBar (Slider) │ ├─ Fill Area │ └─ Handle Slide Area └─ ProgressText (Text) ``` #### 步骤2:场景跳转管理器 ```csharp using UnityEngine; using UnityEngine.SceneManagement; public static class SceneLoader { // 存储目标场景名(静态变量跨场景传递数据) public static string TargetSceneName { get; set; } // 从任意场景跳转到加载界面 public static void LoadSceneWithLoading(string sceneName) { TargetSceneName = sceneName; SceneManager.LoadScene("LoadingScene"); // 先跳转到加载场景 } } ``` #### 步骤3:加载场景控制器(挂载到LoadingScene) ```csharp using UnityEngine; using UnityEngine.UI; using System.Collections; using UnityEngine.SceneManagement; public class LoadingController : MonoBehaviour { [SerializeField] Slider progressBar; [SerializeField] Text progressText; [SerializeField] float minLoadingTime = 2.0f; // 最小加载时间(避免闪屏) void Start() { StartCoroutine(LoadTargetSceneAsync()); } IEnumerator LoadTargetSceneAsync() { float timer = 0; AsyncOperation asyncLoad = SceneManager.LoadSceneAsync(SceneLoader.TargetSceneName); asyncLoad.allowSceneActivation = false; // 禁止自动跳转 // 第一阶段:加载到90% while (!asyncLoad.isDone && asyncLoad.progress < 0.9f) { timer += Time.deltaTime; UpdateProgressUI(asyncLoad.progress); yield return null; } // 第二阶段:确保最小加载时间 while (timer < minLoadingTime) { timer += Time.deltaTime; float progress = Mathf.Lerp(0.9f, 1f, timer / minLoadingTime); UpdateProgressUI(progress); yield return null; } // 激活目标场景 asyncLoad.allowSceneActivation = true; } void UpdateProgressUI(float progress) { float displayProgress = Mathf.Clamp01(progress / 0.9f); // 映射到0-1范围 progressBar.value = displayProgress; progressText.text = $"{(displayProgress * 100):F0}%"; } } ``` #### 步骤4:使用示例(主场景按钮调用) ```csharp public class MainSceneController : MonoBehaviour { public void OnPlayButtonClick() { // 跳转到加载场景,并指定目标场景 SceneLoader.LoadSceneWithLoading("GameScene"); } } ``` ### 关键实现细节说明 1. **跨场景数据传递**: - 使用`static string TargetSceneName`存储目标场景名 - 通过`SceneLoader`类实现场景名称的传递[^1] 2. **异步加载控制**: - `allowSceneActivation=false`确保场景不会自动切换 - 分两个阶段加载: - 实际加载阶段(0%-90%) - 最小等待阶段(90%-100%) 3. **进度条优化**: - **最小加载时间**:防止加载太快导致界面闪烁 - **进度映射**:将Unity的0-0.9进度映射到0-1范围 - **平滑过渡**:使用`Mathf.Lerp`实现进度条平滑填充 4. **UI更新技巧**: - 在协程中每帧更新UI元素 - 使用`F0`格式显示整数百分比 - 进度条值范围限定在0-1之间 ### 常见问题解决方案 1. **加载卡顿**: - 将大场景拆分为多个子场景 - 使用`Addressables`或`AssetBundle`分块加载 - 在后台预加载资源[^2] 2. **进度条不准确**: ```csharp // 在加载协程中添加额外任务 float totalWeight = 100f; float currentWeight = 0f; // 示例:加载场景占70%权重 while (asyncLoad.progress < 0.9f) { currentWeight = asyncLoad.progress * 70f; UpdateProgressUI(currentWeight / totalWeight); yield return null; } // 额外任务占30%权重 yield return LoadAdditionalResources(30f, totalWeight); ``` 3. **进度条动画效果**: ```csharp // 添加平滑动画效果 [SerializeField] float smoothSpeed = 2f; float targetProgress = 0f; void Update() { progressBar.value = Mathf.Lerp( progressBar.value, targetProgress, smoothSpeed * Time.deltaTime ); } void UpdateProgressUI(float progress) { targetProgress = progress; // 只更新目标值 } ``` ### 引用说明 - Unity异步加载机制通过`SceneManager.LoadSceneAsync`实现非阻塞加载[^2] - 最小加载时间防止进度条瞬间完成影响用户体验[^1] - 权重分配法解决多任务加载的进度计算问题[^1]
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值