"잃어버린 섬 2" 게임 개발 프레임워크 개발 일기: 장면 전환 및 페이드 효과

M_Studio의 튜토리얼: ["잃어버린 섬 2" 게임 프레임워크 개발 01: 장면 변환 구현|Unity 튜토리얼]

장면 만들기

다운로드한 자료를 사용하여 H1-H4 및 H2A 장면과 영구적인 장면을 만들고 모든 장면을 Hierachy 패널로 드래그 앤 드롭하고 H1 및 Persistent 장면만 로드하고 H1을 활성 장면으로 사용하고 장면을 전환합니다. 각 장면 아이콘에 2DCollider가 있는 빈 개체를 추가하고 Persistent 장면에 카메라만 유지하고 나머지 장면에서 카메라를 삭제하고 카메라의 배경색을 검은색으로 설정하고 크기를 5.4로 설정하고 게임 패널의 디스플레이 크기를 1920*1080으로 설정하면 사진이 화면에 정확하게 표시될 수 있습니다.

여기에 이미지 설명 삽입
여기에 이미지 설명 삽입

여기에 이미지 설명 삽입

각본

구현 논리: 해당 아이콘을 클릭하면 해당 충돌체를 감지하고 충돌체의 게임 오브젝트 레이블이 지정된 유형 레이블이면 장면 변환 메소드를 호출합니다. 장면마다 장면 전환이 있기 때문에 장면 전환의 클래스는 싱글톤으로 부르기 쉽다.
여기에 이미지 설명 삽입

스크립트 만들기: SingleTon.cs, CursorManager.cs, Teleport.cs, TransitionManager.cs.

// SingleTon.cs 
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Singleton<T> : MonoBehaviour where T : Singleton<T> // 类型约束,类T必须继承Singleton
{
    
    
    // 单例
    protected static T instance;

    // 设置只读属性
    public static T Instance
    {
    
    
        get {
    
     return instance; }
    }

    private void Awake()
    {
    
    
        if (instance == null)
        {
    
    
            instance = (T)this;
        }
        else
        {
    
    
            Destroy(this);
        }

        DontDestroyOnLoad(this);
    }

    // 是否创建实例
    private bool IsInitial()
    {
    
    
        return instance != null;
    }

    // 销毁单例
    protected void OnDestroy()
    {
    
    
        if (instance == this)
        {
    
    
            instance = null;
        }
    }
}
CursorManager.cs脚本编辑:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class CursorManager : MonoBehaviour
{
    
    
    // 将鼠标点击的屏幕坐标转换成世界坐标
    private Vector2 mouseWorldPoint => Camera.main.ScreenToWorldPoint(new Vector3(Input.mousePosition.x, Input.mousePosition.y, 0));
    // 如果鼠标点击了
    private bool isClick;
    private Collider2D coll;

    // Update is called once per frame
    void Update()
    {
    
    
        isClick = ObjectAtMouseClick();
        if (isClick && Input.GetMouseButton(0))
        {
    
    
            // 根据游戏对象的不同标签来判断执行什么操作
            coll = ObjectAtMouseClick();
            ClickAction(coll.gameObject);
        }

    }

    public void ClickAction(GameObject clickObject)
    {
    
    
        switch (coll.gameObject.tag)
        {
    
    
            case "Teleport":

                // 获取对象上的Teleport组件,执行场景切换方法
                Teleport t = clickObject.GetComponent<Teleport>();
                t?.TransitionScene();
                break;
            default:
                break;
        }
    }

    public Collider2D ObjectAtMouseClick()
    {
    
    
        return Physics2D.OverlapPoint(mouseWorldPoint);
    }
}

스크립트 Teleport.cs를 각 장면의 전환 아이콘 개체에 추가하고 파일->설정 빌드 패널에서 "열린 장면 추가"를 클릭하여 모든 장면을 추가합니다.

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

public enum SceneName
{
    
    
    H1,
    H2,
    H3,
    H4,
    H2A,
}
public class Teleport : MonoBehaviour
{
    
    
    // 现在处于的场景
    public SceneName from;
    // 要切换到的场景
    public SceneName to;

    public void TransitionScene()
    {
    
    
        // 场景切换
        TransitionManager.Instance.TransitionScene(from, to);
    }
}

장면 전환

TransitionManager.cs 스크립트를 편집하여 페이드 인 및 페이드 아웃을 추가하지 않고 장면 전환을 달성하고 페이드 인 및 페이드 아웃 효과가 실현되지 않는 코드:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine .SceneManagement,
UnityEngine.UI 사용;

공개 클래스 TransitionManager : 싱글톤
{

// 启动协程
public void TransitionScene(SceneName from, SceneName to)
{

    // 如果实现切换场景淡入淡出效果则不能进行场景切换
    StartCoroutine(SwitchScene(from, to));

}
/// <summary>
/// 切换场景
/// </summary>
/// <param name="from"></param>
/// <param name="to"></param>
/// <returns></returns>
public IEnumerator SwitchScene(SceneName from, SceneName to)
{

    // 屏蔽鼠标操作
    anim.gameObject.GetComponent<Image>().raycastTarget = true;


    // 卸载当前场景
    yield return AsyncOperation unloadScene = SceneManager.UnloadSceneAsync(from.ToString());
   
    // 加载要加载的场景
     yield return AsyncOperation loadScene = SceneManager.LoadSceneAsync(to.ToString(), LoadSceneMode.Additive);
    
    // 激活场景
    Scene newScene = SceneManager.GetSceneByName(to.ToString()); // 通过场景名称来获取场景
    SceneManager.SetActiveScene(newScene);
}

}

장면 전환은 정상
이지만 페이드인, 페이드아웃 관련 기능 코드 추가 후(아래),



public IEnumerator SwitchScene(SceneName from, SceneName to)
    {
    
    
        // 当设置好场景后就加入Fade,1是全黑,0是透明
        yield return Fade(1);

        // 卸载当前场景
        yield return SceneManager.UnloadSceneAsync(from.ToString());
        // 加载要加载的场景
        yield return SceneManager.LoadSceneAsync(to.ToString(), LoadSceneMode.Additive);

        // 激活场景
        // Scene newScene = SceneManager.GetSceneByName(to.ToString()); // 通过场景名称来获取场景
        Scene newScene = SceneManager.GetSceneByBuildIndex((int)to); // 通过场景在build setting中的序号来获取场景,使用这个也会经常报错

        if (newScene == null)
        {
    
    
            SceneManager.SetActiveScene(newScene);
        }
        // 恢复场景可见
        yield return Fade(0);

        // 鼠标点击有效
        cp.blocksRaycasts = false;
    }
    
    /// <summary>
    /// 设置转场时的遮罩颜色渐变
    /// </summary>
    /// <param name="alpha"></param>
    private IEnumerator Fade(float alpha)
    {
    
    
        // 正在开始淡入特效
        isFade = true;
        // 屏蔽所有的鼠标点击
        cp.blocksRaycasts = true;

        // 计算淡入速度, 现在的alpha与目标alpha的差值再除以持续时间得到Fade速度
        float speed = Mathf.Abs(cp.alpha - alpha) / fadeDuaration;
        while (Mathf.Approximately(cp.alpha, alpha))
        {
    
    
            // 线性差值来实现Fade
            cp.alpha = Mathf.Lerp(cp.alpha, alpha, speed * Time.deltaTime);
            yield return null;
        }
        // 淡出后就重新设置isFade
        isFade = false;
    }
   

오류 발생: ArgumentException: 언로드할 장면이 유효하지 않음
특히 이 코드 "yield return SceneManager.UnloadSceneAsync(from.ToString());"에서 얻은 장면이 유효하지 않습니다.

온라인에서 찾은 정보를 참조하십시오.

SceneManager.LoadSceneAsync를 사용하는 경우 사용 후 특성에 주의하도록 allowSceneActivation을 설정합니다. 사용 후
Yield Return
AsyncOperation은 절대 반환되지 않습니다. UnloadSceneAsync를 사용할 때 활성 장면이 하나만 있고 다른 장면이 로드되지 않은 경우 allowSceneActivation이 false로 설정되어 있으면 UnloadSceneAsync가 정상적으로 실행되지 않습니다. 그리고 빈 값을 반환합니다.
또한 AsyncOperation의 진행률이 0이면 일반적으로 이전에 실행되지 않은 AsyncOperation이 있습니다.사용할 때 특성에 특히 주의하십시오.자세한 내용은 Unity Scripting API 검색 allowSceneActivation을 참조하십시오. , LoadSceneAsync
및 UnloadSceneAsync는
지침 및 사용 예를 주의 깊게 살펴봅니다. ——————————————— 저작권 진술: 이 기사는 CC
4.0 BY-SA 저작권 계약에 따른 CSDN 블로거 "Peter_Gao_"의 원본 기사입니다. 원본 소스 링크와 이 진술을 첨부하십시오. 재인쇄용 . 원본 링크: https://blog.csdn.net/qq_42672770/article/details/116023292

AsyncOperation이 실행되지 않아서 그런것 같아서 아래와 같이 실행을 감지하여 실행하도록 코드를 설정했습니다.


    public void TransitionScene(SceneName from, SceneName to)
    {
    
    
       
        // 如果实现切换场景淡入淡出效果则不能进行场景切换
        if (!isFade)
            StartCoroutine(SwitchScene2(from, to));
    }
    /// <summary>
    /// 切换场景
    /// </summary>
    /// <param name="from"></param>
    /// <param name="to"></param>
    /// <returns></returns>
    public IEnumerator SwitchScene2(SceneName from, SceneName to)
    {
    
    
         yield return Fade(1);
        // 卸载当前场景
        AsyncOperation unloadScene = SceneManager.UnloadSceneAsync(from.ToString());
        while (!unloadScene.isDone)
        {
    
    
            yield return null;
        }

        // 加载要加载的场景
        AsyncOperation loadScene = SceneManager.LoadSceneAsync(to.ToString(), LoadSceneMode.Additive);
        loadScene.allowSceneActivation = false;
        while (!loadScene.isDone)
        {
    
    
            yield return null;
            loadScene.allowSceneActivation = true;

        }

        // 激活场景
        Scene newScene = SceneManager.GetSceneByName(to.ToString()); // 通过场景名称来获取场景
        // Scene newScene = SceneManager.GetSceneByBuildIndex((int)to); // 通过场景在build setting中的序号来获取场景

        bool isActive = SceneManager.SetActiveScene(newScene);
        while (isActive)
        {
    
    
            // 恢复场景可见
            yield return Fade(0);

            // 鼠标点击有效
            cp.blocksRaycasts = false;
        }
    }
   

장면을 전환하려면 클릭하면 오류가 발생합니다.


ArgumentException: 언로드 할 장면이 유효하지 않습니다. 90f
> :0) UnityEngine.SceneManagement.SceneManager.UnloadSceneNameIndexInternal (System.String sceneName, System.Int32 sceneBuildIndex, System.Boolean 즉시, UnityEngine.SceneManagement.UnloadSceneOptions 옵션, System.Boolean& outSuccess)(<9c2babab467c4d89beebe2f694dc090f>:0에서) UnityEngine.SceneMan agement.SceneManager.UnloadSceneAsync







(System.String sceneName) (at <9c2babab467c4d89beebe2f694dc090f>:0)
TransitionManager+d__5.MoveNext () (at
Assets/Scripts/Transition/TransitionManager.cs:82)

결국 이유를 못찾겠다, "yield return Fade(1);" 와 "Scene newScene = SceneManager.GetSceneByBuildIndex((int)to); // 씬의 일련번호로 씬 가져오기 빌드 설정에서 장면을 사용하면 종종 오류를 보고합니다. 비디오 자습서의 또 다른 제안은 StatCrountine을 사용하여 Fade를 시작하는 것입니다. 수정 후 장면 전환은 정상이며 오류는 보고되지 않지만 페이드 인 및 페이드가 없습니다. 아웃 효과

   public void TransitionScene(SceneName from, SceneName to)
    {
    
    
        // 进行淡入淡出
        StartCoroutine(Fade(1));

        // 如果实现切换场景淡入淡出效果则不能进行场景切换
        if (!isFade)
            StartCoroutine(SwitchScene(from, to));
    }

    /// <summary>
    /// 切换场景
    /// </summary>
    /// <param name="from"></param>
    /// <param name="to"></param>
    /// <returns></returns>
    public IEnumerator SwitchScene(SceneName from, SceneName to)
    {
    
    
        // 卸载当前场景
        AsyncOperation unloadScene = SceneManager.UnloadSceneAsync(from.ToString());
        while (!unloadScene.isDone)
        {
    
    
            yield return null;
        }
        // 加载要加载的场景
        AsyncOperation loadScene = SceneManager.LoadSceneAsync(to.ToString(), LoadSceneMode.Additive);
        loadScene.allowSceneActivation = false;
        while (!loadScene.isDone)
        {
    
    
            yield return null;
            loadScene.allowSceneActivation = true;
        }

        // 激活场景
        Scene newScene = SceneManager.GetSceneByName(to.ToString()); // 通过场景名称来获取场景

        bool isActive = SceneManager.SetActiveScene(newScene);
        while (isActive)
        {
    
    
            // 恢复场景可见
            yield return Fade(0);

            // 鼠标点击有效
            cp.blocksRaycasts = false;
        }
    }

페이드 인 및 페이드 아웃 전환 구현

결국 이 문제를 해결할 수 없었기 때문에 페이드 인 및 페이드 아웃 애니메이션을 재생하는 다른 방식으로 페이드 인 및 페이드 아웃 효과를 구현했습니다. 참조 튜토리얼: [Unity 튜토리얼: 장면 전환 전환 효과 만들기]
패널 페이드인 및 페이드아웃 애니메이션을 만드는 것은 패널의 이미지 구성 요소인 fadeIn 및 fadeOut의 색상 속성 알파를 변경하고 애니메이터에서 빈 애니메이션을 만드는 두 개의 애니메이션입니다. , 그리고 빈 애니메이션에 대한 진입점을 만드십시오 빈 애니메이션 설정 매개변수 fadeIn이 true일 때 페이드 인 애니메이션이 재생되고, fadeOut=true일 때 페이드 아웃 애니메이션이 재생됩니다. 애니메이션 시간은 0.1초로 설정할 수 있습니다.

애니메이션의 코드 설정은 TransitionManager에서 직접 패널의 상태 머신을 가져와 코드 설정을 사용하여 페이드 인 및 페이드 아웃 애니메이션을 재생합니다.



using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.SceneManagement;
using UnityEngine.UI;// 可以访问到panel的UI

// TransitionManager.cs
public class TransitionManager : Singleton<TransitionManager>
{
    
    
    // panel上的淡入淡出的动画状态机,在面板中拖拽添加
    public Animator anim;
    // 等待时长
    public float waitTime = 0.1f;
    WaitForSeconds wait;

    private void Start()
    {
    
    
        // 较频繁使用的引用类型作
        wait = new WaitForSeconds(waitTime);
    }

    // 启动协程
    public void TransitionScene(SceneName from, SceneName to)
    {
    
    

        // 如果实现切换场景淡入淡出效果则不能进行场景切换
        StartCoroutine(SwitchScene(from, to));

    }

    // private IEnumerator Fade()
    // {
    
    
    //     anim.SetBool("fadeIn", true);
    //     anim.SetBool("fadeOut", false);

    //     anim.gameObject.GetComponent<Image>().raycastTarget = true;

    //     yield return wait;
    // }


    /// <summary>
    /// 切换场景
    /// </summary>
    /// <param name="from"></param>
    /// <param name="to"></param>
    /// <returns></returns>
    public IEnumerator SwitchScene(SceneName from, SceneName to)
    {
    
    
        // 播放淡入动画
        anim.SetBool("fadeIn", true);
        anim.SetBool("fadeOut", false);

        // 屏蔽鼠标操作
        anim.gameObject.GetComponent<Image>().raycastTarget = true;


        // 卸载当前场景
        AsyncOperation unloadScene = SceneManager.UnloadSceneAsync(from.ToString());
        while (!unloadScene.isDone)
        {
    
    
            yield return wait;
        }

        // 加载要加载的场景
        AsyncOperation loadScene = SceneManager.LoadSceneAsync(to.ToString(), LoadSceneMode.Additive);
        loadScene.allowSceneActivation = false;
        while (!loadScene.isDone)
        {
    
    
            yield return null;
            loadScene.allowSceneActivation = true;

        }
        // 播放淡出动画
        loadScene.completed += OnLoadedScene;

        // 激活场景
        Scene newScene = SceneManager.GetSceneByName(to.ToString()); // 通过场景名称来获取场景
        SceneManager.SetActiveScene(newScene);
    }

    private void OnLoadedScene(AsyncOperation async)
    {
    
    
        anim.SetBool("fadeOut", true);
        anim.SetBool("fadeIn", false);
        anim.gameObject.GetComponent<Image>().raycastTarget = false;
    }
}

나중에 케이스에서 AsyncOperation.completed에 대해 알게 되었고, 새로운 방법을 시도해 볼 수 있을 것 같습니다.
또한 두 번째 에피소드에서 한 가지를 발견했습니다. 장면을 전환하기 위해 버튼을 클릭하는 충돌기가 IsTrigger를 확인하지 않습니다. 다른 블로거가 IsTrigger에 대해 알고 있는 내용: 링크 .

추천

출처blog.csdn.net/weixin_44848852/article/details/127127519