前言:最近逛某站,发现了一个宝藏老师~麦扣老师(M_Studio),然后呢~又又又在他主页看到了这个迷失岛教程,于是又开始了这个学习记录~学习永无止境~
一、场景创建
创建素材中的场景
SetActiveScene: 设置获得场景
UnloadScene:设置卸载场景
注:Persistent场景呢,我们用来放UI,数据管理物体(用来挂载数据管理的脚本),这样呢,方便我们更好地组织代码和逻辑~这样可以使代码更易于理解、维护和扩展~
然后,例如在H1场景下,创建一个GameObject物体,并加入碰撞体,用来实现鼠标检测碰撞,从而转移场景功能,同时,我们设置一个标签,后续用来判断是什么物体,执行什么功能
之后,我们打开File-Building Setting,把全部场景都载入
二、脚本部分
首先呢~我们创建一个场景枚举类
/// <summary>
/// 场景的枚举类型
/// </summary>
public enum SceneEnums
{
H1,H2,H2A,H3,H4
}
接着创建场景转换类SceneTransititon
public class SceneTransition : MonoBehaviour
{
public SceneEnums currentScene; // 当前场景
public SceneEnums targetScene; // 目标场景
public void MoveScene()
{
// 获取场景管理器
ScenesManager.Instance.Transition(currentScene, targetScene);
}
}
接着,我们创建一个统一管理场景转换类SceneManager~
注:采用单例模式~单例模式可以确保一个类只有一个实例,提供一个全局访问点,多个场景可以统一使用这个类~
先实现一个泛型单例的父类
using UnityEngine;
/// <summary>
/// 泛型单例
/// </summary>
public class Singleton<T> : MonoBehaviour where T: Singleton<T>
{
private static T instance; // 唯一实例
// 向外提供
public static T Instance
{
get { return instance; }
}
// 是否创建
public static bool IsInitialized
{
get { return instance != null; }
}
protected virtual void Awake()
{
// 要是不为空,表示已经存在一个单例 销毁
if(instance != null)
{
Destroy(instance);
}else
{
// 强转单例
instance = (T)this;
}
}
protected virtual void OnDestroy()
{
// 销毁当前单例
if(instance == this)
{
instance = null;
}
}
}
接着实现一个SceneManager类,继承刚刚的单例父类,并挂载到Persistent场景中
using System;
using System.Collections;
using System.Collections.Generic;
using Unity.VisualScripting;
using UnityEngine;
using UnityEngine.SceneManagement;
/// <summary>
/// 场景转换管理脚本
/// </summary>
public class ScenesManager : Singleton<ScenesManager>
{
public CanvasGroup fadePanel; // 淡出画布
private bool isFade; // 判断是否淡出
private float duration = 0.5f; // 淡出持续时间
/// <summary>
/// 场景转换
/// </summary>
/// <param name="currentScene"></param>
/// <param name="targetScene"></param>
public void Transition(SceneEnums currentScene, SceneEnums targetScene)
{
// 没有淡出时
if (!isFade)
{
StartCoroutine(TransitionToScene(currentScene, targetScene));
}
}
/// <summary>
/// 场景转换协程
/// </summary>
/// <param name="currentScene"></param>
/// <param name="targetScene"></param>
/// <returns></returns>
private IEnumerator TransitionToScene(SceneEnums currentScene, SceneEnums targetScene)
{
// 开始淡出
yield return FadeAction(1);
// 卸载当前场景 当前场景此时有persistent H1 0 1
yield return SceneManager.UnloadSceneAsync(currentScene.ToString());
// 加载新场景 场景:persistent 0
yield return SceneManager.LoadSceneAsync(targetScene.ToString(), LoadSceneMode.Additive);
// 获取新场景 场景: persitent H2 索引 0 1
Scene newScene = SceneManager.GetSceneAt(SceneManager.sceneCount - 1);
// 激活场景
SceneManager.SetActiveScene(newScene);
// 结束淡出
yield return FadeAction(0);
}
/// <summary>
/// 淡出动画
/// </summary>
/// <param name="alpha"></param>
/// <returns></returns>
private IEnumerator FadeAction(float alpha)
{
isFade = true; // 正在淡出
fadePanel.blocksRaycasts = true; // 隐藏鼠标点击
// 淡出速度
float speed = Mathf.Abs(fadePanel.alpha - alpha) / duration;
// 当非常接近时
while (!Mathf.Approximately(fadePanel.alpha, alpha))
{
// alpha值过渡
fadePanel.alpha = Mathf.MoveTowards(fadePanel.alpha,alpha,speed * Time.deltaTime);
yield return null;
}
fadePanel.blocksRaycasts = false;
isFade = false;
}
}
上面代码中关于淡出的操作:我们在Persistent场景中,创建一个UI——Canvas——Panel,Canvas如下设置
注:Scale with Screen Size 可以在不同屏幕分辨率下自动调整 UI 元素的缩放比例
Reference Resolution是它的基准
接着设置Panel
紧接着,我们创建一个CurSorManager脚本,用来检测我们鼠标是否与场景碰撞体是否方式碰撞,同时挂载到persistent场景上面的cursorManager物体上面
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
/// <summary>
/// 鼠标事件管理脚本
/// </summary>
public class CursorManager : MonoBehaviour
{
// 更换鼠标坐标 => C# 6 引入的属性表达式体语法 默认只读
private Vector3 mouseWorldPos => Camera.main.ScreenToWorldPoint(new Vector3(Input.mousePosition.x, Input.mousePosition.y, 0));
// 判断是否可以点击
private bool canClick;
private void Update()
{
// 判断是否有场景转移碰撞体
canClick = MouseCollider();
if(canClick && Input.GetMouseButtonDown(0))
{
// 执行鼠标碰撞处理函数
ClickAction(MouseCollider().gameObject); // MouseCollider().gameObject 函数返回的碰撞体
}
}
/// <summary>
/// 返回鼠标碰撞 该点是否存在碰撞体
/// </summary>
/// <returns></returns>
private Collider2D MouseCollider()
{
return Physics2D.OverlapPoint(mouseWorldPos);
}
/// <summary>
/// 鼠标碰撞处理
/// </summary>
/// <param name="clickObj">检测到的碰撞体</param>
private void ClickAction(GameObject clickObj)
{
// 碰撞体上面的标签
switch (clickObj.tag)
{
case "Scene":
// 获取身上的脚本代码 var 声明变量而不显式指定变量的数据类型
var scene = clickObj.GetComponent<SceneTransition>();
// 执行函数
scene.MoveScene();
break;
}
}
}