欢迎来到尧图网

客户服务 关于我们

您的位置:首页 > 房产 > 家装 > Unity3D仿星露谷物语开发26之创建场景控制管理器

Unity3D仿星露谷物语开发26之创建场景控制管理器

2025/2/2 23:41:15 来源:https://blog.csdn.net/benben044/article/details/145404546  浏览:    关键词:Unity3D仿星露谷物语开发26之创建场景控制管理器

1、目标

创建场景控制管理器,来加载和卸载场景,以实现场景之间的切换。

2、思路

Fade To Back是黑色的过渡场景,透明度逐渐变为1。

Fade To Transparent To Show Scene:黑色消失的过渡场景,透明度逐渐变为0.

事件触发机制:

3、代码编写

(1)优化Enum.cs脚本

创建Scene的枚举类

public enum SceneName
{Scene1_Farm,Scene2_Field,Scene3_Cabin
}

(2)优化EventHandler.cs脚本

添加4个阶段的事件:

// Scene Load Events - in the order they happen
// Before Scene Unload Fade Out Event
public static event Action BeforeSceneUnloadFadeOutEvent;public static void CallBeforeSceneUnloadFadeOutEvent()
{if(BeforeSceneUnloadFadeOutEvent != null){BeforeSceneUnloadFadeOutEvent();}
}// Before Scene Unload Event
public static event Action BeforeSceneUnloadEvent;public static void CallBeforeSceneUnloadEvent()
{if( BeforeSceneUnloadEvent != null){BeforeSceneUnloadEvent();}
}// After Scene Loaded Event
public static event Action AfterSceneLoadEvent;public static void CallAfterSceneLoadEvent()
{if(AfterSceneLoadEvent != null){AfterSceneLoadEvent();}
}// After Scene Load Fade In Event
public static event Action AfterSceneLoadFadeInEvent;public static void CallAfterSceneLoadFadeInEvent()
{if(AfterSceneLoadFadeInEvent != null){AfterSceneLoadFadeInEvent();}
}

(3)创建SceneControllerManager.cs脚本

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.SceneManagement;
using UnityEngine.UI;public class SceneControllerManager : SingletonMonobehaviour<SceneControllerManager>
{private bool isFading;[SerializeField] private float fadeDuration = 1f;[SerializeField] private CanvasGroup faderCanvasGroup = null;[SerializeField] private Image faderImage = null;public SceneName startingSceneName;// This is the main external point of contact and influence from the rest of the project.// This will be called when the player wants to switch scenes.// sceneName:目标场景名称// spawnPosition: 主角出现的位置public void FadeAndLoadScene(string sceneName, Vector3 spawnPosition){// If a fade isn't happening then start fading and switching scenes.if (!isFading){StartCoroutine(FadeAndSwitchScenes(sceneName, spawnPosition));}}// This is the coroutine where the 'building blocks' of the script are put together.private IEnumerator FadeAndSwitchScenes(string sceneName, Vector3 spawnPosition){// Call before scene unload fade out eventEventHandler.CallBeforeSceneUnloadFadeOutEvent();// Start fading to block and wait for it to finish before continuing.yield return StartCoroutine(Fade(1f));  // 变黑色// Set player positionPlayer.Instance.gameObject.transform.position = spawnPosition;// Call before scene unload event.EventHandler.CallBeforeSceneUnloadEvent();// Unload the current active scene.yield return SceneManager.UnloadSceneAsync(SceneManager.GetActiveScene().buildIndex);// Start loading the given scene and wait for it to finish.yield return StartCoroutine(LoadSceneAndSetActive(sceneName));// Call after scene load eventEventHandler.CallAfterSceneLoadEvent();// Start fading back in and wait for it to finish before exiting the function.yield return StartCoroutine(Fade(0f)); // 变白色// Call after scene load fade in eventEventHandler.CallAfterSceneLoadFadeInEvent();}private IEnumerator Fade(float finalAlpha){// Set the fading flag to true so the FadeAndSwitchScenes coroutine won't be called again.isFading = true;// Make sure the CanvasGroup blocks raycasts into the scene so no more input can be accepted.faderCanvasGroup.blocksRaycasts = true;// Calculate how fast the CanvasGroup should fade based on it's current alpha,// it's final alpha and how long it has to change between the two.float fadeSpeed = Mathf.Abs(faderCanvasGroup.alpha - finalAlpha) / fadeDuration;// while the CanvasGroup hasn't reached the final alpha yet...while( !Mathf.Approximately(faderCanvasGroup.alpha, finalAlpha)){// ... move the alpha towards it's target alpha.faderCanvasGroup.alpha = Mathf.MoveTowards(faderCanvasGroup.alpha, finalAlpha,fadeSpeed * Time.deltaTime);// Wait for a frame then continue.yield return null;}// Set the flag to false since the fade has finished.isFading = false;// Stop the CanvasGroup from blocking raycasts so input is no longer ignored.faderCanvasGroup.blocksRaycasts = false;}private IEnumerator LoadSceneAndSetActive(string sceneName){// Allow the given scene to load over serval frames and add it to the already// loaded scenes (just the Persistent scene at this point).yield return SceneManager.LoadSceneAsync(sceneName, LoadSceneMode.Additive);// Find the scene that was most recently loaded (the one at the last index of the loaded scenes).Scene newlyLoadedScene = SceneManager.GetSceneAt(SceneManager.sceneCount - 1);// Set the newly loaded scene as the active scene(this marks it as the one to be unloaded next).SceneManager.SetActiveScene(newlyLoadedScene);}private IEnumerator Start(){// Set the initial alpha to start off with a block screen.faderImage.color = new Color(0f, 0f, 0f, 1f);faderCanvasGroup.alpha = 1f;// Start the first scene loading and wait for it to finishyield return StartCoroutine(LoadSceneAndSetActive(startingSceneName.ToString()));// If this event has any subscribers, call itEventHandler.CallAfterSceneLoadEvent();// Once the scene is finished loading, start fading inStartCoroutine(Fade(0f));}}
  • CanvasGroup的alpha值,其子元素的alpha是子元素alpha和对应CanvasGroup中alpha的乘积。
  • 周期函数中的Start方法可以直接当成协程用,使用方法也很简单,直接将返回值void改成IEnumerator即可。Update,LateUpdate,FixedUpdate,Awake,OnEnable等都不能这么用

(4)优化UIInventorySlot.cs脚本

对于如下的代码:

parentItem = GameObject.FindGameObjectWithTag(Tags.ItemsParentTransform).transform;、

在切换场景的过程中,我们并不能总是找到他们。因为场景加载需要时间,可能场景还没加载完成就在取值了。

所以需要订阅加载完成的事件,在事件中处理元素的获取。

添加如下代码:

private void OnDisable()
{EventHandler.AfterSceneLoadEvent -= SceneLoaded;
}private void OnEnable()
{EventHandler.AfterSceneLoadEvent += SceneLoaded;
}public void SceneLoaded()
{parentItem = GameObject.FindGameObjectWithTag(Tags.ItemsParentTransform).transform;
}

同时注释掉Start()中的元素获取方法。

(5)优化SwitchConfineBoundingShape.cs脚本

元素获取基于同样的理由,需要在场景确认加载完毕后才能去获取。

using UnityEngine;
using Cinemachine;public class SwitchConfine : MonoBehaviour
{//private void Start()//{//    SwitchBoundingShape();//}private void OnEnable(){EventHandler.AfterSceneLoadEvent += SwitchBoundingShape;}private void OnDisable(){EventHandler.AfterSceneLoadEvent -= SwitchBoundingShape;}/// <summary>/// Switch the collider that cinemachine uses to define edges of the screen/// </summary>private void SwitchBoundingShape(){// Get the polygon collider on the 'boundsconfiner' gameobject which is used by Cinemachine to prevent the camera going beyond the screen edgesPolygonCollider2D polygonCollider2D = GameObject.FindGameObjectWithTag(Tags.BoundsConfiner).GetComponent<PolygonCollider2D>();CinemachineConfiner cinemachineConfiner = GetComponent<CinemachineConfiner>();  cinemachineConfiner.m_BoundingShape2D = polygonCollider2D;// since the confiner bounds have changed need to call this to clear the cachecinemachineConfiner.InvalidatePathCache();}
}

(6)优化Player.cs脚本

修改PlayerTestInput()方法。

 private void PlayerTestInput(){// Trigger Advance Timeif (Input.GetKeyDown(KeyCode.T)){TimeManager.Instance.TestAdvanceGameMinute();}// Trigger Advance Dayif (Input.GetKeyDown(KeyCode.G)){TimeManager.Instance.TestAdvanceGameDay();}// Test scene unload / loadif (Input.GetKeyDown(KeyCode.L)){SceneControllerManager.Instance.FadeAndLoadScene(SceneName.Scene1_Farm.ToString(), transform.position);}}

4、创建对象

 (1)FadeImage对象

在PersistentScene -> UI -> MainGameUICanvas -> UICanvasGroup下新建空对象命名为FadeImage。

作用:让屏幕变黑再变透明。

创建完之后,stretch让其铺满屏幕。

添加Image组件。

将颜色调整为黑色,并且将A置为0。

添加Canvas Group组件,并且勾选 Ignore Parent Groups选项,忽略父物体的管理。

(2)SceneControllerManager对象

在PersistentScene下新建空对象命名为SceneControllerManager。

添加SceneControllerManager组件,并且给元素赋值。

5、改变脚本的执行顺序

在多个脚本中,我们无法确定哪个脚本的Start()方法先被执行。

现在,在其他游戏对象开始访问第一个场景之前,我们需要确保SceneControllerManager对象已经在其Start()方法中加载了第一个场景。

Edit -> Project Settings -> Script Execution Order 

在Default Time之前保证SceneControllerManager的脚本被执行。

6、卸载场景

卸载已有的Scene1_Farm场景,

点击该场景后选择 Unload Scene。

因为SceneControllerManager的Start方法会加载当前场景一次。

执行程序后,按"L"键后效果如下:

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com