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

需要用到的工具

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

image

Addressables工具基本操作

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

image

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

image

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

image

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

image

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

image

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

image

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

image

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

image

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

image

预制体(Prefab)

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

在Assets目录中新建Prefabs文件夹

image

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

image

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

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

image

加载场景和物体

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

image

创建SceneLoadEventSO脚本

image

using UnityEngine;

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

}

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

image

using UnityEngine;
using UnityEngine.AddressableAssets;

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

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

image

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

image

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

[Header("事件监听")]
public SceneLoadEventSO loadEventSO;
public GameSceneSO firstLoadScene;

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

private void Awake()
{
    // 异步加载
    Addressables.LoadSceneAsync(firstLoadScene.assetReference, UnityEngine.SceneManagement.LoadSceneMode.Additive);
}

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

image

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

image

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

public enum SceneType
{
    Location, Menu
}

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

public class GameSceneSO : ScriptableObject
{
    public SceneType sceneType;

    public AssetReference assetReference;


}

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

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中

image

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

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中

image

image

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

public void TriggerAction()
{
    loadEventSO.RaiseLoadRequestEvent(sceneToGo, positionToGo, true);
}

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

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

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

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

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()方法中的代码进行调整

private void Awake()
{
    // 获取当前场景
    currentLoadScene = firstLoadScene;
    // 异步加载
    currentLoadScene.assetReference.LoadSceneAsync(LoadSceneMode.Additive);
}
posted @   心霖の雨  阅读(315)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 分享4款.NET开源、免费、实用的商城系统
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了
· 上周热点回顾(2.24-3.2)
点击右上角即可分享
微信分享提示