赞
踩
最近在研究一些与游戏架构无关,却觉得相当重要的小功能,只有在需要用到的时候想到不如在用之前研究好,这篇文章是个人方法,因为网上实现加载界面的功能的方式很多,全文就当参考了。
我们在玩游戏时,经常会见到加载界面,或者说几乎没有没有加载界面的游戏。
下面这是堕落之主(我发现最近老是拿它说事)的加载界面,这已经算是比较普通的加载界面了,有一些还会提供游戏提示,背景介绍之类的游戏信息。对于玩家来说,加载界面是“喘息”和“思考”的间隙,而对于游戏工作者,加载界面有更多意义,比如提前异步加载场景避免让玩家看到一个虚空世界,或者别的什么处理。
总之就是向玩家提供信息和为加载提供时间。
我们看到堕落之主的加载界面只有一个图案和一个进度条,这其实也是基本加载界面需要的,当然不可能所有游戏都一样。比如怪猎的加载界面就没有进度条,取而代之的是两个导虫转圈圈。所以只要让玩家看得出来是个加载界面就行了。
这次的笔记将制作一个只有一个进度条和文本提示的加载界面。并且实现“按任意键继续”的功能。
直接上图看看是什么样子的。
它的组件很简单,
Progress(进度条) 下的fill和Text分别对应控制进度条填充和文本的改变。当然怎么做和命名不是重点,重要的是这些所有内容,或者说这整个加载界面是一个场景Scene。
我将LoadingPanel设置为预制体,并在上面添加一个脚本以实现其功能。
在进行脚本讲解前,我想先说明把整个加载界面独立成场景的想法:
1.方便管理。直接管理对应场景即可,简洁明了。
2.逻辑易实现。很多时候,比如以Panel作为加载界面时,是在当前场景加载到目标场景,也就是说还需要管理加载时当前场景的逻辑,避免BUG。但是先加载到一个统一的场景就可以不管上个场景的逻辑了,这个场景有且只有一个逻辑——加载界面。
- using System.Collections;
- using UnityEngine;
- using UnityEngine.SceneManagement;
- using UnityEngine.UI;
- /// <summary>
- /// 场景加载过渡场景。
- /// </summary>
- public class LoadPanel : Singleton<LoadPanel>
- {
- private const string LoadingSceneName = "Loading";
- private static string TargetScene;//目标场景
-
- public GameObject fill;
- public GameObject text;
- private void Awake()
- {
- StartCoroutine(LoadSceneAsync(TargetScene));
- }
- public static void LoadScene(string sceneName)
- {
- TargetScene = sceneName;
- SceneManager.LoadScene(LoadingSceneName,LoadSceneMode.Single);//优先加载Loading场景
- }
-
- IEnumerator LoadSceneAsync(string sceneName)
- {
- fill.GetComponent<Image>().fillAmount = 0f;
-
- yield return new WaitForSeconds(0.5f);//等待0.5s先,这很重要
- AsyncOperation operation = SceneManager.LoadSceneAsync(sceneName);
- operation.allowSceneActivation = false;
-
- while (!operation.isDone)
- {
- yield return null;
- if(operation.progress >= 0.9f)
- {
- text.GetComponent<Text>().text = "Press To Continue...";
- fill.GetComponent<Image>().fillAmount = 1f;
- if (Input.anyKeyDown)
- {
- operation.allowSceneActivation = true;
- }
- }
- else
- {
- fill.GetComponent<Image>().fillAmount = operation.progress;
- }
- }
-
- }
- }
那我从上到下详细说下这坨代码:
1.这个类继承自Singleton<T>,这是个单例母版类,而它继承自Monobehaviour,只需要将其视为写了一点单例模式的代码的Monobehaviour就行了。这个与正文没什么联系。
2.下面两行是做软编码和声明目标场景。LoadingSceneName是加载界面对应的那个场景,我这里是“Loading”。TargetScene就是接下来要加载的下一个场景。
3.下面两个共有声明是进度条对应的填充和文本。这里我是直接将搭载脚本的物体做成预制体,然后在预制体界面将他们两个赋值。当然其他赋值方式也行。
4.在周期函数Awake里直接进行协程的启动。传入TargetScene作为参数。详细看一下这个协程。首先第一句话就是改变填充量归零。这里我是用Image填充方式做进度条而不是Slider,具体可以看我之前的一篇UI制作相关的文章。
然后就是异步加载的一般操作,存储操作,将操作允许场景激活设为false,因为我们要实现“按任意键继续”的功能。但是前面这个停留0.5秒很重要,因为如果没有等待,allowSceneActivation将会失效,场景会直接跳转不会停留。这个你等待哪怕一帧都是可以的。具体原因不太清楚,有清楚的请请请告诉我。
接下来的While中编写了进度同步和功能逻辑。我相信这个逻辑很简单,大家都应该看得懂,那我就说一下为什么要以0.9作为分界点,因为当allowSceneActivation=false时,加载进度只会加载到0.9(0~1)时就会停下,剩下0.1只会在allowSceneActivation=true时加载。所以为了美观,我们在进度加载到0.9时将填充量设为1,即进度条填充满。不然它会剩一小段空的。没到0.9就保持加载进度和填充量一致就好了。
5.最后我们来看静态方法LoadScene,它先是将参数传赋值给目标场景,再用一般方式加载加载界面场景。简单来讲就是,我先把这个脚本的目标场景设置为我想要加载的场景,然后固定地先加载到加载界面这个场景,最后通过那个协程实现加载逻辑。这就是为什么TargetScene要设置为静态的,这是为了确保加载场景不存在时,你可以提前为TargetScene赋值,而在加载场景加载出来后,Awake将直接调用协程从而加载你想要的那个场景,你可以把整个流程视为转乘航班。因为加载场景体量很小,所以不需要异步加载(不会真有人在加载界面放一大堆东西吧?!)。
这样一来,在其他脚本中,一旦你想加载某个场景,只需要直接调用静态方法LoadScene即可,传入你想加载的那个场景作为参数。这里是名字,当然你想用编号之类的也行。
- using UnityEngine;
-
- public class Menu : MonoBehaviour
- {
- private const string BattleScene = "Battle";
-
- public void NewGame()
- {
- LoadPanel.LoadScene(BattleScene);
- }
- }
这里是一个叫做Menu的脚本,想也知道它是干什么的,NewGame已经与按钮事件绑定,里面只有一句话。就是调用静态方法LoadScene,传入了一个叫做Battle的场景名称。
可以看见点击按钮后,显示加载到了加载界面场景,然后从加载界面场景再加载到目标场景。
这样一来我们就实现了统一加载界面功能,以后需要加载场景只用一个方法即可。如果你想要不同的加载方式可以试试修改,这样仅当参考。
这样的场景加载方式是相当较为简单的,所以它也是有很多弊端的,比如加载较小的场景时,如果每个小场景都需要这样跳转等待,那么未免会让人烦躁,最好的是多写几种不同的场景加载方式,让玩家在玩游戏时不至于因加载太多而烦恼。
这个笔记仅提供思路,希望能有所帮助。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。