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에 대해 알고 있는 내용: 링크 .