Unity 之 Addressable可寻址系统 -- 代码加载介绍

news2024/11/19 5:44:13

Unity 之 可寻址系统 -- 代码加载介绍 -- 进阶(一)

  • 一,可寻址系统代码加载
    • 1.1 回调形式
    • 1.2 异步等待
    • 1.3 面板赋值
    • 1.4 同步加载
  • 二,可寻址系统分标签加载
    • 2.1 场景搭建
    • 2.2 代码示例
    • 2.3 效果展示
  • 三,代码加载可寻址的解释

概述:本片文章为大家介绍可寻址系统使用代码动态加载物体的多种形式。

一,可寻址系统代码加载

准备工作,创建几个预制体分别为:Cube,Capsule,Sphere,并将预制体设置为可寻址系统的资源,然后将Cube的地址修改为Cube,如下图:

1.1 回调形式

using UnityEngine;
// 引用命名空间
using UnityEngine.AddressableAssets;
using UnityEngine.ResourceManagement.AsyncOperations;

public class LoadManager : MonoBehaviour
{
    void Start()
    {
        // 回调形式
        LoadGameObject();
        LoadGameObjectCallBack();
        InstantiateGameObject();
    }
  
    # region 回调形式
    
    /// <summary>
    /// 加载物体 
    /// 逻辑简单且不需复用,直接使用Lambda表达式的形式
    /// </summary>
    void LoadGameObject()
    {
        // 参数:"Cube" 为可寻址系统的地址
        Addressables.LoadAssetAsync<GameObject>("Cube").Completed += (obj) =>
        {
            GameObject go = obj.Result;

            Instantiate(go, Vector3.zero, Quaternion.identity);
        };
    }
    
    /// <summary>
    /// 加载物体
    /// </summary>
    void LoadGameObjectCallBack()
    {
        Addressables.LoadAssetAsync<GameObject>("Assets/Prefab/Sphere.prefab").Completed += LoadCallBack;
    }

    /// <summary>
    /// 加载物体的回调函数
    /// </summary>
    void LoadCallBack(AsyncOperationHandle<GameObject> handle)
    {
        GameObject go = handle.Result;
        Instantiate(go, Vector3.right * 2, Quaternion.identity);
    }
    
    /// <summary>
    /// 加载并实例化物体
    /// </summary>
    void InstantiateGameObject()
    {
        Addressables.InstantiateAsync("Assets/Prefab/Capsule.prefab").Completed += (obj) =>
        {
            // 已经实例化后的物体
            GameObject go = obj.Result;
            go.transform.position = Vector3.left * 2;
        };
    }
    
    #endregion   
}

运行结果如下:
成功加载三个预制


1.2 异步等待

若你不习惯回调的形式,可寻址系统也给了我们加载异步等待的形式直接去加载物体,示例代码如下:

using UnityEngine;
// 引用命名空间
using UnityEngine.AddressableAssets;
using UnityEngine.ResourceManagement.AsyncOperations;

public class LoadManager : MonoBehaviour
{
    void Start()
    {
        // 异步形式
        AsyncLoadCube();
        AsyncInstantiateCube();
    }
    
    #region 异步形式
    
    private async void AsyncLoadCube()
    {
        // 虽然这里使用了Task,但并没有使用多线程
        GameObject prefabObj = await Addressables.LoadAssetAsync<GameObject>("Assets/Prefabs/Cube.prefab").Task;
        // 实例化
        GameObject cubeObj = Instantiate(prefabObj);
        cubeObj.transform.position = Vector3.zero;
    }
    
    private async void AsyncInstantiateCube()
    {
         // 直接使用InstantiateAsync方法
         GameObject cubeObj = await Addressables.InstantiateAsync("Assets/Prefabs/Cube.prefab").Task;
         cubeObj.transform.position = Vector3.right * 2;
    }
    #endregion
}

运行结果如下:


1.3 面板赋值

在代码中声明AssetReference类型的变量,将上面准备好的Cube拖拽上来进行赋值。若此时拖拽上来的没有未加入可寻址系统的资源,他会自动变成一个可选寻址资源。

准备场景如下:

示例代码如下:

using UnityEngine;
// 引用命名空间
using UnityEngine.AddressableAssets;
using UnityEngine.ResourceManagement.AsyncOperations;

public class LoadManager : MonoBehaviour
{
    // 可寻址资源的弱引用
    public AssetReference cubeRef;
    
    void Start()
    {
        // 面板引用
        RefLoadCube();
    }  

    #region 面板形式

    void RefLoadCube()
    {
        cubeRef.LoadAssetAsync<GameObject>().Completed += (obj) =>
        {
            // 加载完成结果
            GameObject cubePrefab = obj.Result;
            // 实例化
            GameObject cubeObj = Instantiate(cubePrefab);
            // 修改位置
            cubeObj.transform.position = Vector3.zero;
        };
    }
    #endregion
}

运行结果如下:

PS:
如果我们声明的不是AssetReference类型,而是我们常用的GameObject类型,那么场景就直接依赖了Cube预制体,打包时Cube预制体就会被打到场景中。现在这里用的是AssetReference 类型,它是一个弱引用,场景并不会真的依赖Cube预制体。


1.4 同步加载

在1.17.4版本之后的可寻址系统,通过在 AsyncOperationHandleWaitForCompletion 方法来实现同步加载。 WaitForCompletion 的作用是会让系统阻拦代码执行,直到资源加载完成。

同步加载GameObject的基本用法,代码如下:

using UnityEngine;
using UnityEngine.AddressableAssets; // 引用命名空间
using UnityEngine.ResourceManagement.AsyncOperations;

public class LoadManager : MonoBehaviour
{
    // Asset的弱引用
    public AssetReference cubeRef;
    
    void Start()
    {
        Addressables.InitializeAsync();
        // 同步加载
        InstantiatePrefab();
    }

    void InstantiatePrefab()
    {
        // 实例化加载到的游戏物体
        Instantiate(LoadPrefab(), transform);
    }
    
    // 强制同步加载GameObject的基本用法
    GameObject LoadPrefab()
    {
        var op = Addressables.LoadAssetAsync<GameObject>("Cube");
        GameObject go = op.WaitForCompletion();
        return go;
    }
}

多数情况下同步加载的性能和异步加载基本一致,但偶尔也会出现更快或更慢的情况。

WaitForCompletion 运算必须在引擎的任务队列中依次完成,如果小型运算的前面有一些大型运算,则只有前面的完成,系统才能完成队列后方的运算。这种情况下会出现加载慢的现象。


二,可寻址系统分标签加载

2.1 场景搭建

创建一个RawImage和一个Button摆放位置如下图:

找两张图片将其放入到工程中,并将其设置为可寻址资源,然后把地址都修改为Logo,最后分别为其创建标签Black,White 设置如下:

PS:这里创建的地址Logo和标签Black,White是下面代码中要用到的,若有变化,则代码中的值需要对应修改。


2.2 代码示例

创建如下代码并将其挂载到上面创建的RawImage物体上,并初始化如下:

下面代码,分别使用了AssetLabelReference面板赋值的形式和寻址+标签两种形式进行了分标签加载代码的示例。根据实际情况决定使用哪一种形式即可。

using System.Collections.Generic;
using UnityEngine;
// 引用命名空间
using UnityEngine.AddressableAssets;
using UnityEngine.ResourceManagement.AsyncOperations;
using UnityEngine.UI;

public class LoadByLabelManager : MonoBehaviour
{
    // 可寻址系统标签的引用
    public AssetLabelReference prefabsLabel;

    public Button loadWhiteLogoBtn;

    private RawImage _rawImage;

    void Start()
    {
        _rawImage = GetComponent<RawImage>();
        
        loadWhiteLogoBtn.onClick.AddListener(() =>
        {
            LoadTextureByKeyLabel("Logo", "Black");
        });
        
        LoadGameObjectByLabel();
    }

    /// <summary>
    /// 根据标签加载
    /// </summary>
    void LoadGameObjectByLabel()
    {
        Addressables.LoadAssetsAsync<Texture2D>(prefabsLabel, (texture) =>
        {
            // 每加载完成一个,就回调一次。 标签下有几个就会执行几次
            Debug.Log("加载完成一个资源: " + texture.name);
            _rawImage.texture = texture;
            _rawImage.SetNativeSize();
        });
    }

    /// <summary>
    /// 根据地址和标签加载
    /// </summary>
    /// <param name="key">可寻址资源地址</param>
    /// <param name="label">资源标签</param>
    void LoadTextureByKeyLabel(string key, string label)
    {
        Addressables.LoadAssetsAsync<Texture2D>(new List<string> {key, label},
            null, Addressables.MergeMode.Intersection).Completed += TextureLoaded;        
    }

    void TextureLoaded(AsyncOperationHandle<IList<Texture2D>> texture)
    {
        _rawImage.texture = texture.Result[0];
        _rawImage.SetNativeSize();
    }
}

根据寻址和标签加载的代码中Addressables.MergeMode:用于合并请求结果 --> 可以理解为,可寻址系统依次从key和label加载两组结果,合并结果有四个枚举值:若查询结果分别为:A,B,C 和 B,C,D

  1. None和UseFirst 都会取第一组结果 --> A,B,C
  2. Union 取两组结果的并集 --> A,B,C,D
  3. Intersection 取两组结果的交集 --> B,C

2.3 效果展示

运行效果:


三,代码加载可寻址的解释

代码加载逻辑基本上这几个,写法也都在上面。逻辑和使用AB包加载逻辑基本一致,只是写法略有不同,所以稍微有经验的同学,应该可以很快上手。只需要熟悉熟悉写法即可。

上面代码加载用的都是key加载的,我们也可以使用它的绝对路径加载,比如上面的Cube,可以这样写:

Addressables.LoadAssetAsync<GameObject>("Cube")

Addressables.LoadAssetAsync<GameObject>("Assets/Prefab/Cube.prefab")

使用key的方式加载的好处在于不管我们之后如何修改路径或者是修改预制体名称,都不会影响到上面代码的加载逻辑,这就是可寻址。只要key不修改就不用修改代码,若AddressablesGroups中存在相同的key,则代码会返回列表中靠上的资源。

若资源不在本地而在服务器上,可寻址系统会帮助我们先下载等待下载完成在执行后面的加载逻辑,所以代码上也不需要有任何的修改。


除了我们常用的资源类型(预制,贴图,音频,配置文件)这些可以使用可寻址代码加载,场景也可以使用可寻址代码加载代码Addressables.LoadSceneAsync("Assets/Scenes/Game.unity");

在后面介绍资源更新的文章中会介绍一个检测更新的脚本,用以游戏开始前下载我们的需要的资源,这样就不会再等到使用时现下载,也就解决了资源过大或者网络稳定的情况下,现下载卡顿的问题。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/159774.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

算法第九期——DFS(深度优先搜索)的树上应用

树 树是一种特殊的图 。 特点&#xff1a; 若树有n个点,则有n-1条边。树有连通性但没有回路。从一个点出发可以到达任意一个&#xff0c;而且路径是唯一的。树的重心u&#xff08;最平衡的点&#xff09;: 以树上任意一个结点为根计算它的子树的结点数&#xff0c;如果结点…

二部图和匈牙利算法

1.二分图最大匹配 设G为二分图,若在G的子图M中,任意两条边都没有公共节点,那么称M为二分图G的一组匹配。在二分图中,包含边数最多的一组匹配称为二分图的最大匹配。 交替路:从一个未匹配点出发,依次经过非匹配边、匹配边、非匹配边…形成的路径叫交替路。 …

【算法】深度优先搜索 (DFS)

目录1.概述2.代码实现3.应用1.概述 &#xff08;1&#xff09;深度优先遍历 (Depth First Search, DFS)&#xff0c;是图的搜索算法之一&#xff0c;本质其实就是一个递归的过程&#xff0c;它就像是一棵树的前序遍历。 &#xff08;2&#xff09;DFS 从图中某个顶点 start 出…

游戏如何解决注入挂难题

游戏黑灰产的攻击角度除了常见的内存修改、模拟点击、破解等作弊手段&#xff0c;还有门槛相对较高的「专用插件类」。 专用插件类外挂是指针对特定游戏定制的外挂&#xff0c;其在实现方式上&#xff0c;类似插件&#xff0c;也称“定制挂”、“注入挂”。 游戏面临多样化的安…

招聘老师的最佳实践及工作交流坊

香港 — 如果你在招聘外籍老师途中遇到极大的挑战&#xff0c;你并不是孤独的。由于新冠肺炎的限制及对于外籍老师的需求增加&#xff0c;招聘及留住高质量的外籍老师对于学校来说已经越来越困难。在疫情之下&#xff0c; 许多学校展现了非凡的韧性来确保他们的教学质量及学习供…

【HCIA-openEuler】实验手册—04【openEuler用户及权限管理】

文章目录一、实验介绍1、关于本实验2、实验目的二、实验任务配置1、配置步骤&#xff08;1&#xff09;用户和用户组的管理步骤1&#xff1a;who命令是显示目前登录系统的用户信息步骤2&#xff1a;id命令用于显示用户的ID&#xff0c;以及所属群组的ID步骤3&#xff1a;以root…

Vivado 错误代码 [Place 30-574]解决思路

问题描述 最近利用手头的开发板作UDP通信的设计。准备生成比特流时&#xff0c;出现这个错误&#xff1a; 具体信息&#xff1a; [Place 30-574] Poor placement for routing between an IO pin and BUFG. If this sub optimal condition is acceptable for this design, you …

Java(105):Java通过键盘(Scanner)输入数据

Java通过键盘(Scanner)输入数据 在Java中&#xff0c;我们可以使用Scanner 类来获取用户的输入。 Java 中添加了java.util.Scanner类&#xff0c;这是一个用于扫描输入文本的新的实用程序。相比于其他获取用户输入的方式&#xff0c;Scanner是非常方便的。 如果使用Scanner&…

如何理解鲁棒性?为什么robustness会翻译为鲁棒性?

鲁棒性&#xff0c;英文为Robustness&#xff08;承受故障和干扰的能力&#xff09;&#xff0c;是许多复杂系统&#xff08;包括复杂网络&#xff09;的关键属性。复杂网络的鲁棒性研究对许多领域都非常重要。本文着重介绍了鲁棒性的基本定义、命名起源、分类区别、提升方法和…

一图读懂mybatis插件plugin原理

插件是用来改变或者扩展mybatis的原有的功能&#xff0c;mybaits的插件就是通过继承Interceptor拦截器实现的;mybatis中能使用插件进行拦截的 可以进行拦截的 接口和方法如下: Executor (update、query 、 flushStatment 、 commit 、 rollback 、 getTransaction 、 close 、…

机试_1_暴力求解_习题

暴力求解——习题 学习完第一章–暴力求解之后&#xff0c;当然要做相应地练习啦~ https://blog.csdn.net/Window_mouse/article/details/128632426 注&#xff1a;上述习题都可以在牛客进行测试。 例如&#xff0c;第9题链接&#xff1a;xxx定律_牛客题霸_牛客网 (nowcode…

近几年美赛B题分析

美赛B题概述&#xff1a; 美赛赛题类型美国大学生数学建模竞赛目前分为两种类型&#xff0c;MCM&#xff08;Mathematical Contest In Modeling&#xff09;和 ICM&#xff08;Interdisciplinary Contest In Modeling)&#xff0c;两种类型竞赛采用统一标准进行&#xff0c;竞…

金融风控04

特征工程 Filter 1&#xff09;移除低方差特征 假设某特征的特征值只有0和1&#xff0c;并且在所有输入样本中&#xff0c;95%的实例的该特征取值都是1&#xff0c;那就可以认为这个特征作用不大。如果100%都是1&#xff0c;那这个特征就没意义了。当特征值都是离散型变量的…

攻克强化学习技术难题记录

一共经过了5次迭代。 第1次迭代的设计思路&#xff1a; 强化学习demo游戏“cartpole”重述 游戏目标&#xff1a;向左/右移动小车cart&#xff0c;保证杆pole始终在小车上方&#xff0c;是大多数强化学习入门教材都会介绍的一个经典案例。 强化学习要素分析&#xff1a; 智…

【项目实战】Nacos下发路由配置实现Spring Cloud Gateway的动态路由

Spring Cloud Gateway网关的使用和Nacos下发路由配置实现Spring Cloud Gateway的动态路由 一、微服务网关概述 1.1 微服务网关诞生背景 不同的微服务一般会有不同的网络地址&#xff0c;而外部客户端可能需要调用多个服务的接口才能完成一个业务需求&#xff0c;如果让客户端…

泰凌微被暂缓审议:利润下滑遭关注,实控人王维航存在大额负债

1月12日&#xff0c;上海证券交易所披露的信息显示&#xff0c;泰凌微电子&#xff08;上海&#xff09;股份有限公司&#xff08;下称“泰凌微”&#xff09;的首发申请被科创板上市委暂缓审议。据贝多财经了解&#xff0c;上市委现场问题对该公司提出多个问题。 根据申请文件…

用详细实例说明和典型案例实现对分治法进行全面分析 | C++

第一篇 分治法 目录 第一篇 分治法 ●前言 ●一、分治法是什么&#xff1f; 1.简要介绍 2.生活实例 ●二、分治法的典型案例——硬币问题 1.具体问题 2.代码展示&#xff08;C&#xff09; 3.程序代码结果展示 ●总结 前言 简单的来说&#xff0c;算法就是用计算机程序代…

菲中工商贸投资合作签约活动在京举办

2023年1月3日至5日&#xff0c;中菲两国元首亲切会谈后&#xff0c;共同发布了成果丰硕的二十八条内容的联合声明。1月3日至9日&#xff0c;由菲律宾菲中人民友好促进会与中国联合国采购促进会在京联合举办了“菲中工商贸投资合作签约仪式”及“中菲合作项目对接洽谈周”活动。…

FPGA:逻辑函数的代数法化简

文章目录逻辑函数的最简形式逻辑函数的代数化简法并项法吸收法消去法配项法示例1示例2逻辑函数的最简形式 1&#xff0e;化简逻辑函数的意义 LABAˉBAˉBˉ(AAˉ)BAˉBˉ1⋅BAˉBˉBAˉ\begin{aligned} L & A B\bar{A} B\bar{A} \bar{B} \\ & (A\bar{A}) B\bar{A} \ba…

PELT——Per Entity Load Tracking

0. 前言&#xff1a; 今天写第一篇Linux内核调度子系统的文章&#xff0c;首先整理PELT负载追踪方法&#xff0c;之前的基础知识在后续的文章中share出来。文章的写成基本上是在几位内核大佬的文章基础之上完成的&#xff0c;有些地方的文字是直接引用的&#xff0c;但本文只用…