Unity引擎2D游戏开发,场景管理和切换

非强专业性文章,本文仅供学习与交流使用

需要用到的工具

资源打包、远程热更新工具

Addressables工具基本操作

在Window菜单下方,会有Asset Management,选择Addressables中的Groups

会弹出相关菜单,将其拖入底部工具栏

会提示没有创建Addressables的相关配置,则点击Create Addressables Settings

这时候会在Project中,多出了一个AddressableAssetsData

由于目前需要此工具进行场景管理和打包,所以可以命名为Scenes

现在可以选中场景,在右侧的Inspector中,能够看到多出了一个可勾选项------Addressable

勾选后,就能够看到Addressable Groups中,多出了刚才勾选的场景。现在就已经加载到了Addressable中

不过在添加之后,会提示一个警告:一个场景被标记为使用可寻址资源加载程序,它当前已经从构建列表中取消

因为通常操作方式,实在Build Setting中进行构建打包,不过使用了Addressable进行构建的话,就替代了常规的构建方式。通常使用常规构建打包很多场景的话,会使包体占用空间很大。使用Addressable进行构建打包,会有更精巧的包体

预制体(Prefab)

预制体(Prefab)是用来提供跨场景调用、解决频繁复制、能够快速调用、统一修改实体参数的解决方案

在Assets目录中新建Prefabs文件夹

将敌人实体对象拖入到Prefabs文件夹中

这时候能看到敌人实体前的图标变成了蓝色,这时候就已经成为了预制体

那么这时候,无论Hierarchy窗口中的敌人对象有多少个,只要操作Prefabs目录内的对象对参数进行修改,所有被创建的同一个敌人的数据都会进行变动

加载场景和物体

当传送到下一张某个地图时,Teleport需要告诉SceneLoad Manager要加载什么场景。然后需要创建两个脚本,用于记录加载的场景和Addressable的资源

创建SceneLoadEventSO脚本

c# 复制代码
using UnityEngine;

[CreateAssetMenu(menuName = "Event/SceneLoadEventSO")]
public class SceneLoadEventSO : ScriptableObject
{

}

紧接着再创建一个GameSceneSO脚本,用于调用Addressable资源

c# 复制代码
using UnityEngine;
using UnityEngine.AddressableAssets;

[CreateAssetMenu(menuName = "Game Scene/GameSceneSO")]
public class GameSceneSO : ScriptableObject
{
    public AssetReference assetReference;
}

在Assets目录中,Data SO下创建GameSceneSO,命名为Cave

选中GameSceneSO,在右侧Inspector中,能够看到Asset Reference的选择框,这里面就是已经加载到Addressable中的资源。选中对应的场景,即可表示这个SO会加载这个场景

打开SceneLoader代码,添加GameSceneSO和SceneLoadEventSO对象全局变量

c# 复制代码
[Header("事件监听")]
public SceneLoadEventSO loadEventSO;
public GameSceneSO firstLoadScene;

然后调用Addressable命名空间,异步加载这个场景

c# 复制代码
private void Awake()
{
    // 异步加载
    Addressables.LoadSceneAsync(firstLoadScene.assetReference, UnityEngine.SceneManagement.LoadSceneMode.Additive);
}

与此同时,需要选择一个Game Scene SO,来表示需要加载什么场景

启动游戏,这时候就可以加载出需要的场景了

在枚举类中,添加一个枚举类型,用于标记加载的场景类型。因为第一次加载的不一定是一个场景,可能是主菜单页面

c# 复制代码
public enum SceneType
{
    Location, Menu
}

在GameSceneSO中,添加这个枚举类型

c# 复制代码
public class GameSceneSO : ScriptableObject
{
    public SceneType sceneType;

    public AssetReference assetReference;


}

打开TeleportPoint传送点的代码,添加一个全局变量,用于标识传送点去往的场景

c# 复制代码
public class TeleportPoint : MonoBehaviour, IInteractable
{
    // 去往的场景
    public GameSceneSO sceneToGo;

    // 坐标点
    public Vector3 positionToGo;
    
    public void PlayFXAudio()
    {
        
    }

    public void TriggerAction()
    {
        
    }
}

在Teleport Point中,Scene To Go选择框选择一个传送目的地的场景,接下来就需要把Scene To Go和Position传入到SceneLoadManager中

在SceneLoadEventSO中,编写加载目的地场景的相关代码

c# 复制代码
using UnityEngine;
using UnityEngine.Events;

[CreateAssetMenu(menuName = "Event/SceneLoadEventSO")]
public class SceneLoadEventSO : ScriptableObject
{
    public UnityAction<GameSceneSO, Vector3, bool> LoadRequestEvent;

    /// <summary>
    /// 场景加载请求
    /// </summary>
    /// <param name="gameSceneSO">要加载的场景</param>
    /// <param name="position">人物目的地坐标</param>
    /// <param name="fadeScreen">是否淡入淡出</param>
    public void RaiseLoadRequestEvent(GameSceneSO gameSceneSO, Vector3 position, bool fadeScreen)
    {
        LoadRequestEvent?.Invoke(gameSceneSO, position, fadeScreen);
    }
}

接下来,在Event目录中新建Scene Load Event SO,并在Teleport中,将该SO添加到Load Event SO中

在Teleport的TriggerAction()方法中,编写唤起加载场景的事件

c# 复制代码
public void TriggerAction()
{
    loadEventSO.RaiseLoadRequestEvent(sceneToGo, positionToGo, true);
}

在SceneLoader中,写SceneLoadEventSO的装载和卸载的代码

c# 复制代码
private void OnEnable()
{
    loadEventSO.LoadRequestEvent += OnLoadRequestEvent;
}

private void OnDisable()
{
    loadEventSO.LoadRequestEvent += OnLoadRequestEvent;
}

编写当事件唤起时需要执行的操作,创建三个全局变量,用于临时存储Teleport唤起事件时候传入的参数

c# 复制代码
private GameSceneSO targetSceneToGo;
private Vector3 targetPositionToGo;
private bool fadeScreen;

private void OnLoadRequestEvent(GameSceneSO sceneToGo, Vector3 positionToGo, bool fadeScreen)
{
    targetSceneToGo = sceneToGo;
    targetPositionToGo = positionToGo;
    this.fadeScreen = fadeScreen;
    // 卸载当前场景,装载下一个场景
    StartCoroutine(UnloadPreviousScene());
}

private IEnumerator UnloadPreviousScene()
{
    if (fadeScreen)
    {
        // TODO:实现淡入淡出
    }
    // 等待淡入淡出的指定时间
    yield return new WaitForSeconds(fadeTime);
    // 卸载场景
    yield return currentLoadScene.assetReference.UnLoadScene();
    
    LoadNewScene();
}

private void LoadNewScene()
{
    // 加载新场景
    targetSceneToGo.assetReference.LoadSceneAsync(LoadSceneMode.Additive, true);
}

解决转换场景后报空引用的问题

将Awake()方法中的代码进行调整

c# 复制代码
private void Awake()
{
    // 获取当前场景
    currentLoadScene = firstLoadScene;
    // 异步加载
    currentLoadScene.assetReference.LoadSceneAsync(LoadSceneMode.Additive);
}
相关推荐
LeeAt5 小时前
《谁杀死了比尔?》:使用Trae完成的一个推理游戏项目!!
前端·游戏开发·trae
龙智DevSecOps解决方案5 小时前
游戏开发中的CI/CD优化案例:知名游戏公司Gearbox使用TeamCity简化CI/CD流程
ci/cd·游戏开发·jetbrains·teamcity
一名用户21 小时前
unity实现自定义粒子系统
c#·unity3d·游戏开发
技术小甜甜3 天前
【Blender Texture】【游戏开发】高质感 Blender 4K 材质资源推荐合集 —— 提升场景真实感与美术表现力
blender·游戏开发·材质·texture
Thomas游戏开发3 天前
Unity3D TextMeshPro终极使用指南
前端·unity3d·游戏开发
Thomas游戏开发4 天前
Unity3D 逻辑代码性能优化策略
前端框架·unity3d·游戏开发
Thomas游戏开发5 天前
Unity3D HUD高性能优化方案
前端框架·unity3d·游戏开发
陈哥聊测试6 天前
游戏公司如何同时管好上百个游戏项目?
游戏·程序员·游戏开发
一名用户7 天前
unity随机生成未知符号教程
c#·unity3d·游戏开发
Be_Somebody12 天前
计算机图形学——Games101深度解析_第二章
游戏开发·计算机图形学·games101