需求1
场景之间必须加过渡,否则硬切很难看。如果场景比较小,加黑场过渡就可以。
解决方法1
【简单方法】: 给每个场景加一个Panel,在点击下一关时,黑场动画。每次加载该场景时,自动播放黑场消失动画。需要注意的是,黑场消失最好用一个黑色的图片来做。如果直接控制CanvasGroup的透明度,其他的子UI不会有渐变的效果,会突然一下变亮。
【资源节约型方法】:跨关卡管理,每次场景过渡的时候自动生成一个panel,不需要给每个场景都添加,自动控制渐入和渐出。
using UnityEngine;
using UnityEngine.SceneManagement;
using System.Collections;
using UnityEngine.UI;
using System;
/// <summary>
/// Fade transition 的脚本
/// </summary>
public class FadeTransition : MonoBehaviour
{
//需要用代码生成loading的黑屏image和canvas
private Image loadingImag;
private Canvas loadingCanvas;
//下一关的名字,检查是否加载完毕,进入下一关
private string nextScene = "";
private float sceneStartTimeStamp;
//fade句柄,在需要切换关卡的时候进行调用
private static FadeTransition _instance;
public static FadeTransition instance
{
get
{
if( !_instance )
{
// check if there is a TransitionKit instance already available in the scene graph before creating one
_instance = FindObjectOfType( typeof( FadeTransition ) ) as FadeTransition;
if( !_instance )
{//生成 fade object
var obj = new GameObject( "FadeTransition" );
_instance = obj.AddComponent<FadeTransition>();
DontDestroyOnLoad( obj );
}
}
return _instance;
}
}
/// <summary>
/// Transitions the scene 函数(其他脚本调用)
/// </summary>
/// <param name="name">Name.</param>
public void transitionScene(string name, float p_fadeOutDuration, float p_fadeInDuration )
{
nextScene = name;
StartCoroutine( transition(p_fadeOutDuration, p_fadeInDuration) );
}
/// <summary>
/// 渐出、加载场景、渐入的过程
/// </summary>
private IEnumerator transition(float p_fadeOutDuration, float p_fadeInDuration)
{
//先行清理
clearFadeTransitionContent ();
//set canvas
GameObject canvasObject = new GameObject("FadeTransitionCanvas");
loadingCanvas = canvasObject.AddComponent<Canvas>();
loadingCanvas.transform.SetParent(transform);
loadingCanvas.renderMode = RenderMode.ScreenSpaceOverlay;
loadingCanvas.sortingOrder = 10;
GameObject iamgeObject = new GameObject("FadeTransitionImage");
loadingImag = iamgeObject.AddComponent<Image>();
loadingImag.transform.SetParent(loadingCanvas.transform);
loadingImag.color = Color.clear;
loadingImag.rectTransform.anchoredPosition = Vector2.zero;
loadingImag.rectTransform.sizeDelta = new Vector2 (Screen.width,Screen.height);
//fade out
yield return StartCoroutine (tickChangeAlpha (p_fadeOutDuration));
//waitting for loaded
if (nextScene != "") {
SceneManager.LoadSceneAsync (nextScene);//unity异步加载场景函数
yield return StartCoroutine(waitForLevelToLoad( nextScene ) );//输出信息
}
//fade in
yield return StartCoroutine( tickChangeAlpha(p_fadeInDuration, true) );
clearFadeTransitionContent ();
}
/// <summary>
/// 清除已有的 fade object
/// </summary>
private void clearFadeTransitionContent(){
if (loadingCanvas != null) {
GameObject.Destroy (loadingCanvas.gameObject);
}
if(loadingImag != null){
GameObject.Destroy (loadingImag.gameObject);
}
}
/// <summary>
/// 检查是否加载完毕,进入了下一关
/// </summary>
public IEnumerator waitForLevelToLoad( string level )
{
while (SceneManager.GetActiveScene().name != level) {
Debug.Log("loading scene:"+ SceneManager.GetActiveScene().name);
yield return null;
}
}
/// <summary>
/// image颜色渐变,用while循环来计算
/// </summary>
private IEnumerator tickChangeAlpha( float duration, bool reverseDirection = false )
{
var start = reverseDirection ? Color.black : Color.clear;
var end = reverseDirection ? Color.clear : Color.black;
var elapsed = 0f;
while( elapsed < duration )
{
elapsed += Time.deltaTime;
Color step = Color.Lerp( start, end, Mathf.Pow( elapsed / duration, 2f ) );
if (loadingImag != null) {
loadingImag.color = step;
}
yield return null;
}
}
}
需求2
有时候加载时间太长,长时间黑屏也不是办法,要播放一个loading的动画,同时显示进度的百分比。
解决方法2
1.我对于跨关卡这个摸得还不太清,还是先用分关卡的方式了。
2.渐入就用自动播放动画来做。把fadePanel提前做好,做成prefab,放到Resources文件夹中。在UI的脚本里,生成该fade object(带有fadeScript的脚本)。
GameObject fadeObject = Resources.Load<GameObject>(MainContainer.PrefabFolder + "FadePanel");
Instantiate(fadeObject, transform);
3.loading动画,我选择新建一个loading关卡,因为该场景只有一个UI,所以加载速度非常快。动画就是下面这个,特别简单,依然是自动播放。而下面的text用来显示进度。
4.渐出、场景加载、显示数字。
//我之前是用FadeManager的句柄进行过渡管理的,已经写了太多FadeManager.Instance的代码了。所以我保留
//了这个脚本,把后面的fadeScript作为instance。
public class FadeManager : MonoBehaviour {
public static GameObject fadeInstance;
public static string nextScene;
}
using System.Collections;
using UnityEngine;
using UnityEngine.UI;
using DG.Tweening;
using UnityEngine.SceneManagement;
public class FadeScript : MonoBehaviour {
string sceneName;
bool isPlaying = false;
bool needLoading = false;
AsyncOperation async;//异步加载object,用于判断是否加载完成
Image image;
void Start()
{
image = GetComponent<Image>();
image.color = Color.black;
image.raycastTarget = false;
image.DOFade(0f,1.5f);//自动播放渐入动画,黑屏消失。
FadeManager.fadeInstance = gameObject;//赋值instance
}
///summary
///其他脚本通过instance,调用这个函数
///summary
public void goToSceneByFade(string sceneName,bool needLoading=true,float fadeOutDuration=0.3f,float fadeInDuration=1f)
{
if (isPlaying == true) return;
this.needLoading = needLoading;
this.sceneName = sceneName;
StartCoroutine(Transition(fadeOutDuration, fadeInDuration));
}
///summary
///渐出,然后加载loading场景
///summary
private IEnumerator Transition(float fadeOutDuration, float fadeInDuration)
{
//先变黑
isPlaying = true;
yield return StartCoroutine(Fade(0.3f, false)); //颜色渐变
//动画播完之后:
if (async != null){
async.allowSceneActivation = true;
/*这里要解释一下:
async.allowSceneActivation这个属性为true时,加载完就直接进入下一关,反之则停住。
这是为什么呢?原来我们要根据async.progress这个属性来显示进度,但是这个数字达到90后就会直接进
入下一关。所以我们要判断一下它是否到达了89,设置allowSceneActivation为false,此时我们让进度
继续递增到100,再手将allowSceneActivation设置为true.
*/
}else {
if (needLoading)//需要播放loading动画
{
FadeManager.nextScene = sceneName;
SceneManager.LoadScene("Loading");//加载
}
else SceneManager.LoadScene(sceneName);
}
}
///summary
///颜色渐变的过程
///summary
private IEnumerator Fade(float duration, bool reverseDirection = false)
{
float end = reverseDirection ? 0 : 1;
image.DOFade(1f, duration); //正向是黑色出现,反向是黑色消失。
yield return null;
}
///summary
///Loading脚本通过instance,调用这个函数,获得async的加载进度
///summary
public float getProgress()
{
return async.progress;
}
public void loadLevelBackground(string levelName)
{
StartCoroutine(loadLevelAsync(levelName));
}
///summary
///异步加载场景,赋值async,设置allowSceneActivation为false
///summary
IEnumerator loadLevelAsync(string levelName)
{
async = SceneManager.LoadSceneAsync(levelName);
async.allowSceneActivation = false;
yield return async;
}
}
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
//Loading脚本:即进入Loading关卡之后做什么
public class LoadingLevel : MonoBehaviour {
public GameObject fadeObject;
FadeScript fadeInstance;
Text percentText;
bool startLoadFlag = false;
int count = 0;
///summary
///初始化UI,启动加载函数
///summary
void Start () {
percentText = transform.Find("planet/percentText").gameObject.GetComponent<Text>();
percentText.text = "0%";
percentText.gameObject.SetActive(false);
fadeInstance = fadeObject.GetComponent<FadeScript>();//这个关卡放置一个fade object
Invoke("startLoad", 1);//加载关卡
}
///summary
///更新数字
///summary
void Update (){
if (startLoadFlag == false) return;
float progress = fadeInstance.getProgress();//获得progress属性
//对progress进行变形,得到count
if (progress * 100 > count)
{
count += 1;//count递增
}
if (count > 88)
{
percentText.text = "100%";
fadeInstance.goToSceneByFade("", false);
}
else
{
percentText.text = count.ToString("f0") + "%";//更新text为百分比格式
}
}
///summary
///unity异步加载函数,加载要去的场景
///summary
void startLoad()
{
startLoadFlag = true;
fadeInstance.loadLevelBackground(FadeManager.nextScene);
percentText.gameObject.SetActive(true);
}
}