基本流程
制作场景之间的切换
1.代码思路
(1)为了实现不同场景切换,并且保持当前的persistentScene一直存在,则需要一个Manager去控制场景的加载和卸载,并且在加载每一个场景之后,都要将当前的场景Set Active Scene,保证其为激活的场景,在卸载的时候也可以方便调用当前激活的场景,然后把它卸载掉
(2)每次创建一个新的场景之后都要去Build Settings当中,将所有创建的场景都添加到这个列表当中
(3)由于游戏的场景是逐一叠加的,那么异步加载的模式就为Additive(在原有的场景当中叠加)
(4)场景之间切换是通过碰撞触发的,需要指定切换后的场景和坐标
(5)切换场景需要用一个新的脚本来控制,它所需要的变量有目标场景名,目标坐标,要注意在卸载场景的时候人物是不能被玩家控制的,还需要注意的是,在传送过程中选中物品的情况(举起物品),也就是说要在卸载场景之前,恢复player的基本动画(AnimatorOverride.cs),取消物品的高亮显示(InventoryUI.cs)
2.代码实现
TransitionManager.cs
namespace FuliFarm.Transition
{
public class TransitionManager : MonoBehaviour
{
//游戏开始的场景
public string startSceneName = string.Empty;
private void Start()
{
StartCoroutine(LoadSceneSetActive(startSceneName));
}
private void OnEnable()
{
EventHandler.TransitionEvent += OnTransitionEvent;
}
private void OnDisable()
{
EventHandler.TransitionEvent -= OnTransitionEvent;
}
private void OnTransitionEvent(string sceneToGo, Vector3 positionToGo)
{
StartCoroutine(Transition(sceneToGo, positionToGo));
}
/// <summary>
/// 卸载一个场景,加载另外一个场景
/// </summary>
/// <param name="sceneName">目标场景</param>
/// <param name="targetPosition">目标位置</param>
/// <returns></returns>
private IEnumerator Transition(string sceneName, Vector3 targetPosition)
{
//呼叫卸载场景之前要做的事
EventHandler.CallBeforeSceneUnloadEvent();
yield return SceneManager.UnloadSceneAsync(SceneManager.GetActiveScene());
yield return LoadSceneSetActive(sceneName);
//移动人物坐标
EventHandler.CallMoveToPosition(targetPosition);
//呼叫加载场景之后的事件
EventHandler.CallAfterSceneLoadedEvent();
}
/// <summary>
/// 加载场景并设置为激活
/// </summary>
/// <param name="sceneName">场景名</param>
/// <returns></returns>
private IEnumerator LoadSceneSetActive(string sceneName)
{
//协成当中所有的加载场景都是异步加载
yield return SceneManager.LoadSceneAsync(sceneName, LoadSceneMode.Additive);
Scene newScene = SceneManager.GetSceneAt(SceneManager.sceneCount - 1);//序号从0开始,而数量(count)是从1开始的,所以减1
SceneManager.SetActiveScene(newScene);
}
}
}
Teleport.cs
namespace FuliFarm.Transition
{
public class Teleport : MonoBehaviour
{
public string sceneToGo;
public Vector3 positionToGo;
private void OnTriggerEnter2D(Collider2D other)
{
if (other.CompareTag("Player"))
{
//把目标位置和目标场景传给TransitionManager中,然后调用协成Transition,就去到了对应的场景
EventHandler.CallTransitionEvent(sceneToGo, positionToGo);
}
}
}
}
新增事件
//切换场景
public static event Action<string, Vector3> TransitionEvent;
public static void CallTransitionEvent(string sceneName,Vector3 pos)
{
TransitionEvent?.Invoke(sceneName,pos);
}
//卸载场景之前的事件
public static event Action BeforeSceneUnloadEvent;
public static void CallBeforeSceneUnloadEvent()
{
BeforeSceneUnloadEvent?.Invoke();
}
//加载场景之后的事件
public static event Action AfterSceneLoadedEvent;
public static void CallAfterSceneLoadedEvent()
{
AfterSceneLoadedEvent?.Invoke();
}
//传送到所在位置
public static event Action<Vector3> MoveToPosition;
public static void CallMoveToPosition(Vector3 targetPosition)
{
MoveToPosition?.Invoke(targetPosition);
}
修改SwitchBounds.cs
public class SwitchBounds : MonoBehaviour
{
//注册事件
private void OnEnable()
{
EventHandler.AfterSceneLoadedEvent += SwitchConfinerShape;
}
private void OnDisable()
{
EventHandler.AfterSceneLoadedEvent -= SwitchConfinerShape;
}
private void SwitchConfinerShape()
{
PolygonCollider2D confinerShape = GameObject.FindGameObjectWithTag("BoundsConfiner").GetComponent<PolygonCollider2D>();
CinemachineConfiner confiner = GetComponent<CinemachineConfiner>();
confiner.m_BoundingShape2D = confinerShape;
//Call this if the bounding shape's points change at runtime
confiner.InvalidatePathCache();
}
}
修改ItemManager.cs
public class ItemManager : MonoBehaviour
{
public Item itemPrefab;
private Transform itemParent;
private void OnEnable()
{
EventHandler.InstantiateItemInScene += OnInstantiateItemInScene;
EventHandler.AfterSceneLoadedEvent += OnAfterSceneLoadedEvent;
}
private void OnDisable()
{
EventHandler.InstantiateItemInScene -= OnInstantiateItemInScene;
EventHandler.AfterSceneLoadedEvent -= OnAfterSceneLoadedEvent;
}
private void OnAfterSceneLoadedEvent()
{
itemParent = GameObject.FindWithTag("ItemParent").transform;
}
private void OnInstantiateItemInScene(int ID, Vector3 pos)
{
var item = Instantiate(itemPrefab, pos, Quaternion.identity, itemParent);
item.itemID = ID;
}
}
新增Player.cs中的函数以及变量,并修改Update
private bool inputDisable;
private void OnEnable()
{
EventHandler.BeforeSceneUnloadEvent += OnBeforeSceneUnloadEventd;
EventHandler.AfterSceneLoadedEvent += OnAfterSceneLoadedEvent;
EventHandler.MoveToPosition += OnMoveToPosition;
}
private void OnDisable()
{
EventHandler.BeforeSceneUnloadEvent -= OnBeforeSceneUnloadEventd;
EventHandler.AfterSceneLoadedEvent -= OnAfterSceneLoadedEvent;
EventHandler.MoveToPosition -= OnMoveToPosition;
}
private void OnMoveToPosition(Vector3 targetPosition)
{
transform.position = targetPosition;
}
private void OnAfterSceneLoadedEvent()
{
inputDisable = false;
}
private void OnBeforeSceneUnloadEventd()
{
inputDisable = true;
}
private void Update()
{
if(inputDisable == false)
PlayerInput();
SwitchAnimation();
}
AnimatorOverride.cs新增注册事件以及具体实现
private void OnEnable()
{
EventHandler.ItemSelectedEvent += OnItemSelectedEvent;
EventHandler.BeforeSceneUnloadEvent += OnBeforeSceneUnloadEvent;
}
private void OnDisable()
{
EventHandler.ItemSelectedEvent -= OnItemSelectedEvent;
EventHandler.BeforeSceneUnloadEvent -= OnBeforeSceneUnloadEvent;
}
private void OnBeforeSceneUnloadEvent()
{
holdItem.enabled = false;
SwitchAnimator(PartType.None);
}
新增InventoryUI.cs注册事件以及实现
private void OnEnable()
{
EventHandler.UpdateInventoryUI += OnUpdateInventoryUI;
EventHandler.BeforeSceneUnloadEvent += OnBeforeSceneUnloadEvent;
}
private void OnDisable()
{
EventHandler.UpdateInventoryUI -= OnUpdateInventoryUI;
EventHandler.BeforeSceneUnloadEvent -= OnBeforeSceneUnloadEvent;
}
private void OnBeforeSceneUnloadEvent()
{
UpdateSlotHightlight(-1);
}
最终效果
可以通过门来回切换场景,在举着东西的状态下,切换场景后,人物动画以及UI的选中高亮将会被重置