Unity 分享載入場景跳出載入中的畫面
分類
說明
有時候在載入場景時因為遊戲物件太多,導致要等很多時間,若使用同步的載入方式畫面會卡住直到場景載入為止,造成使用者體驗不佳,所以這次將分享一套簡易的非同步載入場景方法給大家。
畫面
首先我們必須實作載入中的畫面,礙於我的能力有限,我想到的做法就是將整個 Canvas 做成預製,這樣就可以設定 Canvas Sort Order,確保載入中的畫面要跳出在最上面,然後將預製放在 Resources 資料夾,使用 Resources 方式載入預製。
這裡我只簡單地告訴大家大致上需要哪些畫面,實作細節還再自行依照自己的需求調整。
LoadingCanvas
一般的畫布,用來設定 Sort Order,重點只有新增 LoadingCanvas 組件,存取 LoadingPanel 遊戲物件
LoadingCanvas.cs
using UnityEngine;
/// <summary>
/// 載入中畫布
/// </summary>
public class LoadingCanvas : MonoBehaviour
{
/// <summary>
/// 載入中面板
/// </summary>
[SerializeField]
private LoadingPanel loadingPanel;
/// <summary>
/// 載入中面板
/// </summary>
public LoadingPanel LoadingPanel => loadingPanel;
}
上面有一個 LoadingPanel 組件,一樣等等會實作 LoadingPanel 組件。
LoadingPanel
UI Panel 用來覆蓋整個畫面的背景,重點是新增 LoadingPanel 組件,用來存取 ProgressBar。
LoadingPanel.cs
using UnityEngine;
/// <summary>
/// 載入中面板
/// </summary>
public class LoadingPanel : MonoBehaviour
{
/// <summary>
/// 進度條
/// </summary>
[SerializeField]
private ProgressBar progressBar;
/// <summary>
/// 進度條
/// </summary>
public ProgressBar ProgressBar => progressBar;
}
LoadingText
單純顯示文字。
Pickaxe 1
Unity Asset Store 上的動畫,可免費下載,直接將下載的 Prefab 動畫放上去而已。
下載連結: https://assetstore.unity.com/packages/2d/gui/icons/animated-loading-icons-47844
ProgressBar
進度條比較複雜一點,關於進度條畫面實作可以參考我之前寫的 Unity 簡易血條製作。
簡單介紹如下
ProgressBar
它是一個 Slider,重點在我自訂的 ProgressBar 組件,以及 OnValueChanged 事件調用 ProgressBar.OnValueChanged,用來修改 ProgressText 的進度文字。
- Fill Rect: 進度填充的畫面,這裡綁定 Status,Status 是 Images UI,就是一條長方形的條狀物圖片。
ProgressBar.cs
using TMPro;
using UnityEngine.UI;
using UnityEngine;
/// <summary>
/// 進度條 UI
/// </summary>
public class ProgressBar : MonoBehaviour
{
/// <summary>
/// 進度滑桿
/// </summary>
private Slider slider;
/// <summary>
/// 進度文字
/// </summary>
[SerializeField]
private TMP_Text progressText;
private void Awake()
{
slider = GetComponent<Slider>();
progressText.text = slider.value.ToString("P0");
}
/// <summary>
/// 進度變更
/// </summary>
/// <param name="value">進度0~1</param>
public void OnValueChanged(float value)
{
progressText.text = value.ToString("P0");
}
/// <summary>
/// 設定進度
/// </summary>
/// <param name="value">進度0~1</param>
public void SetProgress(float value)
{
slider.value = value;
}
}
SetProgress()
用給給外部腳本設定進度的,當 slider.value
改變時會觸發 OnValueChanged()
,接著改變進度條文字。
StatusBar
進度條的外框圖片。
Status
進度條框內的填充圖片。
ProgressText
進度文字。
載入中腳本
SceneLoader.cs
using System.Collections;
using UnityEngine;
using UnityEngine.SceneManagement;
/// <summary>
/// 場景載入器,用來給 UI 按鈕調用
/// </summary>
public class SceneLoader : MonoBehaviour
{
/// <summary>
/// 載入中畫布
/// </summary>
private static LoadingCanvas loadingCanvas;
private void Awake()
{
// 初始化載入中畫布,確保不會重複生成
if (loadingCanvas == null)
{
loadingCanvas = FindFirstObjectByType<LoadingCanvas>();
// 第一次載入載入中畫布
if (loadingCanvas == null)
{
GameObject LoadingCanvasPrefab =
Resources.Load<GameObject>("Prefabs/UIs/LoadingCanvas");
GameObject loadingCanvasGameObject = Instantiate(LoadingCanvasPrefab, null);
loadingCanvasGameObject.SetActive(false);
DontDestroyOnLoad(loadingCanvasGameObject);
loadingCanvas = loadingCanvasGameObject.GetComponent<LoadingCanvas>();
SceneManager.sceneLoaded += OnSceneLoaded;
}
}
}
/// <summary>
/// 載入場景時顯示載入中畫面
/// </summary>
/// <param name="sceneName">場景名稱</param>
/// <returns></returns>
private IEnumerator LoadSceneWithLoadingPage(string sceneName)
{
AsyncOperation asyncOperation = SceneManager.LoadSceneAsync(sceneName);
while (!asyncOperation.isDone)
{
loadingCanvas.LoadingPanel.ProgressBar.SetProgress(asyncOperation.progress);
if (asyncOperation.progress >= 0.9f)
{
loadingCanvas.LoadingPanel.ProgressBar.SetProgress(1f);
}
yield return null;
}
}
/// <summary>
/// 當場景載入後調用
/// </summary>
/// <param name="scene">場景名稱</param>
/// <param name="mode">載入模式</param>
private void OnSceneLoaded(Scene scene, LoadSceneMode mode)
{
loadingCanvas.gameObject.SetActive(false);
}
/// <summary>
/// 按鈕點擊場入場景,並顯示載入中畫面
/// </summary>
/// <param name="sceneName">場景名稱</param>
public void ClickLoadSceneWithLoadingPage(string sceneName)
{
loadingCanvas.gameObject.SetActive(true);
StartCoroutine(LoadSceneWithLoadingPage(sceneName));
}
/// <summary>
/// 載入場景,給按鈕使用
/// </summary>
/// <param name="sceneName">場景名稱</param>
public void LoadScene(string sceneName)
{
SceneManager.LoadScene(sceneName);
}
}
上述腳本 loadingCanvas 使用類似單例的設計方式,避免發生重複生成 LoadingCanvasPrefab 遊戲物件。
將腳本添加在按鈕上,在點擊事件調用 ClickLoadSceneWithLoadingPage()
方法,然後寫上場景名稱即可。
LoadScene()
是同步載入的方式,使用方式同上,只是方便給按鈕點擊事件使用,不用另外建立按鈕腳本來實作功能。
一杯咖啡的力量,勝過千言萬語的感謝。
支持我一杯咖啡,讓我繼續創作優質內容,與您分享更多知識與樂趣!