Tuanjie InstantAsset

InstantAsset

InstantAsset 是一套全新的资产解决方案,旨在提升开发者的开发和运行时效率,简化资产管理流程,特点是支持资产免构建、导入即用、具有更细粒度的内存周期管理和更方便快捷的管理方式。当前仅支持在 Tuanjie 1.7.0及以上版本使用InstantAsset功能。

本文档可能更新不及时(当前Tuanjie1.7.6),如果版本差距过大,请关注官方文档:https://docs.unity.cn/cn/tuanjiemanual/Manual/InstantAssetIntro.html.

解决的问题

使用Instant Asset可以解决:

  • 资产构建时间过长
  • 不合理的分包导致运行时冗余问题
  • 资产生命周期管理问题

未来展望

  • 提供多线程资产加载接口
  • 持续改进InstantAsset中资产的内存管理和加载效率
  • 免构建模式下,扩展资源类型范围包含脚本类型资产的新增和改动等

Instant Asset 准备工作

资产管理方式

InstantAsset 默认是以文件夹为单位对资产进行管理。每个文件夹对应一个 InstantAssetTable,用于存储和管理该文件夹内的资产信息, 为了方便开发者使用我们同时也支持用户自定义资产列表分组到同一个InstantAssetTable中。

分组策略

Instant Assets的分组策略参考了 AssetBundle 的设计理念,主要包括以下几种方式:

  • 逻辑实体分组:根据资产的逻辑关系或功能进行分组,确保相关资产被组织在一起。
  • 类型分组:按照资产的类型(如图片、音频、视频等)进行分类,便于管理和检索。
  • 并发内容分组:针对需要同时加载或处理的内容进行分组,以优化性能和资源利用率。

处理要求

在实际处理过程中,Instant Asset 要求将属于同一分组的资产放置在同一个文件夹内,以保证资产按文件夹进行构建并管理


Instant Asset工作流程

要开始使用Instant Asset,要按照以下步骤操作。

切换到支持平台

目前支持Windows、Android、iOS、WebGL和WeixinMiniGame平台。

具体架构和后端参考官方文档:https://docs.unity.cn/cn/tuanjiemanual/Manual/InstantAsset-Workflow.html

开启Instant Asset功能

在ProjectSetting/Editor/Instant Player 勾选Instant Asset按钮。(会提示Restart Editor)

构建Instant Asset

在 Assets 文件夹下创建名为 Editor 的文件夹,在 Editor 文件夹下创建脚本CreateInstantAsset:

using UnityEditor;
using System.IO;

public class CreateInstantAsset
{
    [MenuItem("Assets/Build InstantAsset")]
    static void BuildAllAssetPacker()
    {

        // 设置构建输出路径
        string outputPath = Application.streamingAssetsPath;
    
        if (!System.IO.Directory.Exists(outputPath))
        {
            System.IO.Directory.CreateDirectory(outputPath);
        }
        
        // 定义资源别名表
        InstantAssetAliasTable[] aliasTables = new InstantAssetAliasTable[]
        {
            // 资源列表方式指定 示范代码
            new InstantAssetAliasTable
            {
                aliasTableName = "Prefabs_table",
                assetNames = new string[] 
                { 
                    "Assets/Prefabs/Player.prefab",
                    "Assets/Prefabs/Enemy.prefab",
                    "Assets/Prefabs/TestScene.scene"
                }
            },

            // 目录方式指定资源 示范代码
            new InstantAssetAliasTable
            {
                aliasTableName = "Materials_table",
                buildDirectoryPath = "Assets/Materials", // 包含目录下所有资源
                assetNames = null 
            }
        };
        
        // 设置构建选项
        InstantAssetOptions options = InstantAssetOptions.CompressionLz4HC | 
                                     InstantAssetOptions.ForceRebuild;
        
        // 调用构建方法
        bool success = InstantAssetEditorUtility.BuildAssetPacker(
            outputPath,           // 输出文件路径
            aliasTables,          // 资源表
            options,              // 构建选项
            1024,                 // 大小限制
            EditorUserBuildSettings.activeBuildTarget  // 目标平台
        );
        
        if (success)
        {
            Debug.Log("资源包构建成功!文件已保存到: " + outputPath);
        }
        else
        {
            Debug.LogError("资源包构建失败!");
        }
    }
}

此脚本在团结编辑器的 Assets 菜单底部添加一个名为 Build InstantAsset 的菜单项。点击该菜单项将触发关联函数中的代码。执行时,脚本会根据 InstantAssetAliasTable 收集所有指定资源,并将它们打包到由 outputPath 定义的文件夹中。每个资源包的大小由 size 参数指定,目标平台由 targetPlatform 参数确定。此外,脚本会在 outputPath 中生成与 aliasTables 数量一致的 InstantAssetTable 文件。如果包含场景文件,还会额外生成一份以所在分组的 InstantAssetTable 名称后缀加 ‘-scene’ 命名的 InstantAssetTable 文件。

加载 InstantAssetTable 和资源

InstantAssetTable 中包含了特定文件夹下资产及其依赖的信息。用户首先需要通过指定 InstantAssetTable 文件路径来加载 InstantAssetTable 对象,再利用 InstantAssetTable 加载资产, 如果指定资产中包含了场景文件,会额外生成场景文件的表,命名规则是在指定表名的基础上加“-scene”, 如果需要加载场景文件则也需要提前加载其场景文件的 InstantAssetTable。
同步的方式加载资源,具体代码如下所示:

public class LoadInstantAsset : MonoBehaviour
{
    void Start() 
    {
        // 设置资源的根路径文件夹, 这里我们假定资源存放在 streamingAssets 目录下,所以直接设置为Application.streamingAssetsPath
        InstantAsset.SetInstantAssetRootPath(Application.streamingAssetsPath);

        // 加载包含目标资源对应的 InstantAssetTable, 假定我们需要加载名为Prefabs_table的表
        var tablePath = System.IO.Path.Combine(Application.streamingAssetsPath, "Prefabs_table");
        var myLoadedInstantAssetTable = InstantAsset.ReadAssetTable(tablePath) as InstantAssetTable;
        if (myLoadedInstantAssetTable == null) 
        {
            Debug.Log("Failed to load InstantAssetTable");
            return;
        }

        // 同时如果我们需要加载Player.prefab,则需要填入相对路径,参考如下
        var prefab = myLoadedInstantAssetTable.LoadAsset<GameObject>("Assets/Prefabs/Player.prefab") as GameObject;
        Instantiate(prefab);

        // 卸载资源接口 参考如下
        myLoadedInstantAssetTable.UnloadAsset(prefab);
    }

    void OnDestroy()
    {
       // 卸载资源表 参考如下
       var tablePath = System.IO.Path.Combine(Application.streamingAssetsPath, "Prefabs_table");
       InstantAsset.UnloadAssetTable(tablePath)
    }
}

异步的方式加载资源,代码如下所示:

public class LoadInstantAsset : MonoBehaviour
{
    IEnumerator Start()
    {
        // 设置资源的根路径文件夹, 这里我们假定资源存放在 streamingAssets 目录下,所以直接设置为Application.streamingAssetsPath
        InstantAsset.SetInstantAssetRootPath(Application.streamingAssetsPath);

        // 加载包含目标资源对应的 InstantAssetTable, 假定我们需要加载名为Prefabs_table的表
        var tablePath = System.IO.Path.Combine(Application.streamingAssetsPath, "Prefabs_table");
        var myLoadedInstantAssetTable = InstantAsset.ReadAssetTable(tablePath) as InstantAssetTable;

        InstantAssetRequest request = myLoadedInstantAssetTable.LoadAssetAsync<GameObject>("Assets/Prefabs/Player.prefab");

        while (!request.isDone)
        {
            Debug.Log("Loading progress: " + request.progress);
            yield return null;
        }

        if (request.asset != null)
        {
            var prefab = request.asset as GameObject;
            if (prefab != null)
            {
                Instantiate(prefab);
            }
        }
    }
}

当前InstantAsset还不支持同步方式加载场景,只能通过异步的方式加载场景资源。此外,场景加载还不支持编辑器模拟,编辑器可以先通过添加场景到Build Setting 的方式临时测试加载逻辑,具体代码如下所示:

public class LoadInstantAsset : MonoBehaviour
{
    IEnumerator Start() 
    {
        // 设置资源的根路径文件夹, 这里我们假定资源存放在 streamingAssets 目录下,所以直接设置为Application.streamingAssetsPath
        InstantAsset.SetInstantAssetRootPath(Application.streamingAssetsPath);

        //如果指定目录或者指定的资源中包含场景资产,会额外生成一个场景表来记录,命名是用户设置的表名加上"-scene"来区分普通资源表和场景表
        //这里普通资源表名为 Prefabs_table,则场景表名是:Prefabs_table-scene
        var tablePath = Application.streamingAssetsPath + "/Prefabs_table" + "-scene";
        var myLoadedInstantAssetTable = InstantAsset.ReadAssetTable(tablePath) as InstantAssetTable;

        // 同时如果我们需要加载 Assets/Prefabs/TestScene.scene,则需要填入相对路径,参考如下
        AsyncOperation sceneOperation = SceneManager.LoadSceneAsync( "Assets/Prefabs/TestScene.scene");

        yield return sceneOperation;
    }
}
posted @ 2025-12-04 18:20  马林林林  阅读(9)  评论(4)    收藏  举报