【Unity】场景过渡

需求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);
    }
}

猜你喜欢

转载自blog.csdn.net/qq_36622009/article/details/87618011