TEngine 资源模块是基于 YooAsset 构建的上层资源管理框架,提供了完全自动化的资源引用管理和商业级的资源生命周期控制。相比直接使用 YooAsset,TEngine 的资源模块具有以下核心优势:
-
🔗 资源引用自动化管理
- 通过
AssetsReference组件自动管理资源生命周期 - 无需手动 Dispose 资源句柄,框架自动处理资源释放
- 支持 GameObject 和资源对象的自动引用追踪
- 通过
-
📊 上层资源管理框架
- 基于 YooAsset 构建,但提供了更高层次的抽象
- 统一的资源加载接口,屏蔽底层实现细节
- 智能的资源对象池管理,自动复用已加载资源
-
🎯 商业级内存管理
- 支持 LRU(Least Recently Used)缓存策略
- 自动释放引用计数为 0 的资源包
- 可配置的资源自动释放间隔
-
🚀 高性能异步加载
- 基于 UniTask 的零 GC 异步加载
- 支持同步/异步/回调三种加载方式
- 智能的资源加载队列管理
资源模块支持多种运行模式,覆盖全平台需求:
- EditorSimulateMode - 编辑器模拟模式(仅编辑器可用)
- OfflinePlayMode - 单机运行模式(从 StreamingAssets 加载)
- HostPlayMode - 联机运行模式(支持热更新)
- WebPlayMode - WebGL 运行模式(支持网页游戏)
WebGL 模式下支持两种资源加载方式(通过 LoadResWayWebGL 配置):
- Remote - 访问远程资源(默认)
- StreamingAssets - 跳过远程下载资源,直接访问 StreamingAssets
TEngine 资源模块特别优化了对各种小游戏平台的支持:
- 微信小游戏 - 自动适配微信小游戏的文件系统
- 其他小游戏平台 - 可通过配置适配不同的小游戏平台
注意:
- 编辑器模式下以顶部导航栏的选项卡为优先选项
- 打包后以 Scene 场景中 ResourceModule 脚本的 Enum 选项卡为优先选项(打包后不会走 EditorSimulateMode)
- WebGL 平台会根据
LoadResWayWebGL设置自动选择资源加载方式
在 Scene 窗口的 Resource 对象可以设置资源模块的常用配置:
- 打包后的资源模式(PlayMode)
- 资源校验等级
- 自动卸载资源间隔
- 资源对象池容量和过期时间
在菜单窗口 TEngineSetting 可以设置资源模块的热更新配置:
- 资源服务器地址(HostServerURL)
- 备用服务器地址(FallbackHostServerURL)
- WebGL 资源加载方式(LoadResWayWebGL)
- Remote:访问远程资源
- StreamingAssets:直接访问 StreamingAssets
- 在线参数配置
提示:
- 在
Tools/FileServer目录下有一个基于 Node 的静态文件服务器,可以把在线参数以及 AB 放入用于做热更新测试- WebGL 平台需要根据实际情况选择资源加载方式:
- 开发阶段可使用 StreamingAssets 快速测试
- 生产环境建议使用 Remote 方式,支持热更新
AssetsReference 是 TEngine 资源模块的核心特性,实现了完全自动化的资源引用管理。
- 自动绑定:加载 GameObject 时,框架自动添加
AssetsReference组件 - 引用追踪:组件自动追踪资源引用关系
- 自动释放:当 GameObject 被销毁时,自动释放关联的资源
// 方式1:同步加载 GameObject(自动添加 AssetsReference)
GameObject go = GameModule.Resource.LoadGameObject("UI/BattleMainUI");
// 无需手动管理,Destroy 时自动释放资源
// 方式2:异步加载 GameObject(自动添加 AssetsReference)
GameObject go = await GameModule.Resource.LoadGameObjectAsync("UI/BattleMainUI");
// 同样无需手动管理
// 方式3:手动绑定资源引用(用于动态加载的资源)
GameObject instance = Instantiate(prefab);
AssetsReference.Ref(prefab, instance, GameModule.Resource);
// 或者绑定其他资源对象
AssetsReference.Ref<Material>(material, instance, GameModule.Resource);- ✅ 零手动管理:开发者无需关心资源释放,框架自动处理
- ✅ 防止内存泄漏:自动追踪所有资源引用,确保正确释放
- ✅ 支持嵌套引用:可以绑定多个资源对象到一个 GameObject
- ✅ 克隆安全:自动处理 GameObject 克隆时的引用关系
TEngine 在 YooAsset 基础上构建了资源对象池系统,提供:
- 智能复用:相同资源只加载一次,后续直接复用
- 自动管理:资源对象池自动管理资源生命周期
- 可配置策略:支持 LRU 等缓存策略
虽然当前版本主要使用 AssetsReference 进行资源管理,但框架仍支持资源组概念:
- 资源分组绑定管理
- 资源生命周期托管给资源组的根节点
- 适合批量资源管理场景
TEngine 资源模块提供了 SetSprite 扩展接口,实现了完全自动化的图片设置和引用管理。
-
🔗 自动引用管理
- 自动绑定图片资源引用
- 图片更换时自动释放旧资源
- 组件销毁时自动释放资源
-
⚡ 异步加载支持
- 基于 UniTask 的异步加载
- 不阻塞主线程
- 支持取消操作
-
🎯 智能资源复用
- 相同资源自动复用
- 自动管理资源生命周期
- 防止资源泄漏
using TEngine;
using UnityEngine.UI;
public class UIIcon : MonoBehaviour
{
public Image iconImage;
void Start()
{
// 方式1:基础用法(异步加载,自动管理引用)
iconImage.SetSprite("ItemIcon");
// 方式2:设置原始分辨率
iconImage.SetSprite("ItemIcon", setNativeSize: true);
// 方式3:带回调
iconImage.SetSprite("ItemIcon", callback: (image) => {
Debug.Log($"图片加载完成: {image.sprite.name}");
});
// 方式4:支持取消操作
var cts = new CancellationTokenSource();
iconImage.SetSprite("ItemIcon", cancellationToken: cts.Token);
// 需要取消时:cts.Cancel();
}
}using TEngine;
using UnityEngine;
public class CharacterSprite : MonoBehaviour
{
public SpriteRenderer spriteRenderer;
void Start()
{
// 设置 SpriteRenderer 的图片(异步加载,自动管理引用)
spriteRenderer.SetSprite("Player");
// 带回调
spriteRenderer.SetSprite("Player", callback: (renderer) => {
Debug.Log($"角色图片加载完成: {renderer.sprite.name}");
});
}
}using TEngine;
using UnityEngine.UI;
public class UIIcon : MonoBehaviour
{
public Image iconImage;
void Start()
{
// 从图集中加载子图片
// location: 图集资源地址
// spriteName: 图集中的子图片名称
iconImage.SetSubSprite("CommonAtlas", "Icon_Item_001", setNativeSize: true);
// SpriteRenderer 也支持子图片
// spriteRenderer.SetSubSprite("Atlas", "Player_Idle");
}
}/// <summary>
/// 设置图片(UI Image)。
/// </summary>
/// <param name="image">UI Image 组件。</param>
/// <param name="location">资源定位地址。</param>
/// <param name="setNativeSize">是否使用原始分辨率。</param>
/// <param name="callback">设置完 Sprite 的回调。</param>
/// <param name="cancellationToken">取消设置资源的 Token。</param>
public static void SetSprite(
this Image image,
string location,
bool setNativeSize = false,
Action<Image> callback = null,
CancellationToken cancellationToken = default
);
/// <summary>
/// 设置图片(2D SpriteRenderer)。
/// </summary>
/// <param name="spriteRenderer">2D SpriteRenderer 组件。</param>
/// <param name="location">资源定位地址。</param>
/// <param name="callback">设置完 Sprite 的回调。</param>
/// <param name="cancellationToken">取消设置资源的 Token。</param>
public static void SetSprite(
this SpriteRenderer spriteRenderer,
string location,
Action<SpriteRenderer> callback = null,
CancellationToken cancellationToken = default
);
/// <summary>
/// 设置子图片(从图集中加载,UI Image)。
/// </summary>
/// <param name="image">UI Image 组件。</param>
/// <param name="location">图集资源定位地址。</param>
/// <param name="spriteName">图集中的子图片名称。</param>
/// <param name="setNativeSize">是否使用原始分辨率。</param>
/// <param name="cancellationToken">取消设置资源的 Token。</param>
public static void SetSubSprite(
this Image image,
string location,
string spriteName,
bool setNativeSize = false,
CancellationToken cancellationToken = default
);
/// <summary>
/// 设置子图片(从图集中加载,2D SpriteRenderer)。
/// </summary>
/// <param name="spriteRenderer">2D SpriteRenderer 组件。</param>
/// <param name="location">图集资源定位地址。</param>
/// <param name="spriteName">图集中的子图片名称。</param>
/// <param name="cancellationToken">取消设置资源的 Token。</param>
public static void SetSubSprite(
this SpriteRenderer spriteRenderer,
string location,
string spriteName,
CancellationToken cancellationToken = default
);- 自动引用追踪:SetSprite 会自动追踪图片资源引用
- 智能资源释放:当图片被更换或组件被销毁时,自动释放旧资源
- 资源复用:相同资源自动复用,避免重复加载
- 生命周期管理:与 GameObject 生命周期绑定,确保资源正确释放
// ✅ 推荐:使用 SetSprite,自动管理资源
iconImage.SetSprite("UI/Icon/ItemIcon");
// ❌ 不推荐:手动加载和管理资源
var sprite = GameModule.Resource.LoadAsset<Sprite>("UI/Icon/ItemIcon");
iconImage.sprite = sprite;
// 需要手动管理资源释放,容易造成内存泄漏// 同步加载资源(自动管理引用)
SkillDisplayData data = GameModule.Resource.LoadAsset<SkillDisplayData>("SkillData");
// 同步加载 GameObject(自动添加 AssetsReference)
GameObject go = GameModule.Resource.LoadGameObject("UI/BattleMainUI", parent);// 使用 UniTask 异步加载(推荐方式)
SkillDisplayData data = await GameModule.Resource.LoadAssetAsync<SkillDisplayData>(
"SkillData",
cancellationToken: cancellationToken
);
// 异步加载 GameObject(自动添加 AssetsReference)
GameObject go = await GameModule.Resource.LoadGameObjectAsync(
"UI/BattleMainUI",
parent: parent,
cancellationToken: cancellationToken
);// 使用回调方式异步加载
GameModule.Resource.LoadAsset<SkillDisplayData>(
"SkillData",
callback: (data) => {
// 使用资源
Debug.Log($"Loaded: {data.name}");
}
);重要提示:
- 资源模块默认使用 Addressable 可寻址定位
- 传入资源名字无需后缀(如 "UI/BattleMainUI" 而不是 "UI/BattleMainUI.prefab")
- 打包的资源不可以重名
/// <summary>
/// 同步加载资源。
/// </summary>
/// <param name="location">资源的定位地址。</param>
/// <param name="packageName">指定资源包的名称。不传使用默认资源包</param>
/// <typeparam name="T">要加载资源的类型。</typeparam>
/// <returns>资源实例。</returns>
T LoadAsset<T>(string location, string packageName = "") where T : UnityEngine.Object;
/// <summary>
/// 同步加载游戏物体并实例化(自动添加 AssetsReference)。
/// </summary>
/// <param name="location">资源的定位地址。</param>
/// <param name="parent">资源实例父节点。</param>
/// <param name="packageName">指定资源包的名称。不传使用默认资源包</param>
/// <returns>资源实例。</returns>
/// <remarks>会实例化资源到场景,无需主动UnloadAsset,Destroy时自动UnloadAsset。</remarks>
GameObject LoadGameObject(string location, Transform parent = null, string packageName = "");
/// <summary>
/// 异步加载资源(UniTask)。
/// </summary>
/// <param name="location">资源定位地址。</param>
/// <param name="cancellationToken">取消操作Token。</param>
/// <param name="packageName">指定资源包的名称。不传使用默认资源包</param>
/// <typeparam name="T">要加载资源的类型。</typeparam>
/// <returns>异步资源实例。</returns>
UniTask<T> LoadAssetAsync<T>(string location, CancellationToken cancellationToken = default, string packageName = "") where T : UnityEngine.Object;
/// <summary>
/// 异步加载游戏物体并实例化(自动添加 AssetsReference)。
/// </summary>
/// <param name="location">资源定位地址。</param>
/// <param name="parent">资源实例父节点。</param>
/// <param name="cancellationToken">取消操作Token。</param>
/// <param name="packageName">指定资源包的名称。不传使用默认资源包</param>
/// <returns>异步游戏物体实例。</returns>
/// <remarks>会实例化资源到场景,无需主动UnloadAsset,Destroy时自动UnloadAsset。</remarks>
UniTask<GameObject> LoadGameObjectAsync(string location, Transform parent = null, CancellationToken cancellationToken = default, string packageName = "");
/// <summary>
/// 异步加载资源(回调方式)。
/// </summary>
/// <param name="location">资源的定位地址。</param>
/// <param name="callback">回调函数。</param>
/// <param name="packageName">指定资源包的名称。不传使用默认资源包</param>
/// <typeparam name="T">要加载资源的类型。</typeparam>
UniTaskVoid LoadAsset<T>(string location, Action<T> callback, string packageName = "") where T : UnityEngine.Object;/// <summary>
/// 卸载资源。
/// </summary>
/// <param name="asset">要卸载的资源。</param>
void UnloadAsset(object asset);
/// <summary>
/// 资源回收(卸载引用计数为零的资源)。
/// </summary>
void UnloadUnusedAssets();
/// <summary>
/// 强制回收所有资源。
/// </summary>
void ForceUnloadAllAssets();
/// <summary>
/// 强制执行释放未被使用的资源。
/// </summary>
/// <param name="performGCCollect">是否使用垃圾回收。</param>
void ForceUnloadUnusedAssets(bool performGCCollect);
/// <summary>
/// 检查资源是否存在。
/// </summary>
/// <param name="location">资源定位地址。</param>
/// <param name="packageName">资源包名称。</param>
/// <returns>检查资源是否存在的结果。</returns>
HasAssetResult HasAsset(string location, string packageName = "");
/// <summary>
/// 检查资源定位地址是否有效。
/// </summary>
/// <param name="location">资源的定位地址</param>
/// <param name="packageName">指定资源包的名称。不传使用默认资源包</param>
bool CheckLocationValid(string location, string packageName = "");/// <summary>
/// 获取当前资源包版本。
/// </summary>
/// <param name="customPackageName">指定资源包的名称。不传使用默认资源包</param>
/// <returns>资源包版本。</returns>
string GetPackageVersion(string customPackageName = "");
/// <summary>
/// 异步更新最新包的版本。
/// </summary>
/// <param name="appendTimeTicks">请求URL是否需要带时间戳。</param>
/// <param name="timeout">超时时间。</param>
/// <param name="customPackageName">指定资源包的名称。不传使用默认资源包</param>
/// <returns>请求远端包裹的最新版本操作句柄。</returns>
RequestPackageVersionOperation RequestPackageVersionAsync(bool appendTimeTicks = false, int timeout = 60, string customPackageName = "");
/// <summary>
/// 向网络端请求并更新清单。
/// </summary>
/// <param name="packageVersion">更新的包裹版本</param>
/// <param name="timeout">超时时间(默认值:60秒)</param>
/// <param name="customPackageName">指定资源包的名称。不传使用默认资源包</param>
UpdatePackageManifestOperation UpdatePackageManifestAsync(string packageVersion, int timeout = 60, string customPackageName = "");
/// <summary>
/// 创建资源下载器,用于下载当前资源版本所有的资源包文件。
/// </summary>
/// <param name="customPackageName">指定资源包的名称。不传使用默认资源包</param>
ResourceDownloaderOperation CreateResourceDownloader(string customPackageName = "");
/// <summary>
/// 清理包裹未使用的缓存文件。
/// </summary>
/// <param name="clearMode">文件清理方式。</param>
/// <param name="customPackageName">指定资源包的名称。不传使用默认资源包</param>
ClearCacheFilesOperation ClearCacheFilesAsync(
EFileClearMode clearMode = EFileClearMode.ClearUnusedBundleFiles, string customPackageName = "");
/// <summary>
/// 清理沙盒路径。
/// </summary>
/// <param name="customPackageName">指定资源包的名称。不传使用默认资源包</param>
void ClearAllBundleFiles(string customPackageName = "");/// <summary>
/// 获取资源信息。
/// </summary>
/// <param name="location">资源的定位地址。</param>
/// <param name="packageName">指定资源包的名称。不传使用默认资源包</param>
/// <returns>资源信息。</returns>
AssetInfo GetAssetInfo(string location, string packageName = "");
/// <summary>
/// 获取资源信息列表。
/// </summary>
/// <param name="resTag">资源标签。</param>
/// <param name="packageName">指定资源包的名称。不传使用默认资源包</param>
/// <returns>资源信息列表。</returns>
AssetInfo[] GetAssetInfos(string resTag, string packageName = "");
/// <summary>
/// 获取资源信息列表。
/// </summary>
/// <param name="tags">资源标签列表。</param>
/// <param name="packageName">指定资源包的名称。不传使用默认资源包</param>
/// <returns>资源信息列表。</returns>
AssetInfo[] GetAssetInfos(string[] tags, string packageName = "");/// <summary>
/// 设置远端资源服务地址(需同时提供默认和备用地址)。
/// </summary>
/// <param name="defaultHostServer">默认服务器地址。</param>
/// <param name="fallbackHostServer">备用服务器地址。</param>
void SetRemoteServicesUrl(string defaultHostServer, string fallbackHostServer);对于 GameObject 资源,优先使用 LoadGameObject 或 LoadGameObjectAsync,框架会自动添加 AssetsReference 组件,无需手动管理。
// ✅ 推荐:自动管理资源引用
GameObject ui = await GameModule.Resource.LoadGameObjectAsync("UI/BattleMainUI", parent);
// 销毁时自动释放资源
Destroy(ui);
// ❌ 不推荐:需要手动管理
AssetHandle handle = GameModule.Resource.LoadAssetAsyncHandle<GameObject>("UI/BattleMainUI");
GameObject ui = Instantiate(handle.AssetObject as GameObject);
// 需要手动 handle.Dispose()对于动态加载的资源(如 Material、Texture 等),使用 AssetsReference 绑定引用:
GameObject instance = Instantiate(prefab);
// 绑定预制体引用
AssetsReference.Ref(prefab, instance, GameModule.Resource);
// 绑定材质引用
Material mat = GameModule.Resource.LoadAsset<Material>("Materials/MyMaterial");
AssetsReference.Ref(mat, instance, GameModule.Resource);对于大型项目,可以创建多个资源包来管理不同模块的资源:
// 初始化自定义资源包
await GameModule.Resource.InitPackage("BattlePackage", needInitMainFest: true);
// 从指定资源包加载
GameObject go = await GameModule.Resource.LoadGameObjectAsync(
"BattleUI",
packageName: "BattlePackage"
);- 资源命名:打包的资源不能重名,使用 Addressable 地址作为唯一标识
- 资源后缀:加载资源时无需添加文件后缀(如 .prefab、.png 等)
- 生命周期:资源模块的初始化生命周期已在流程模块中实现,一般无需手动调用
- 内存管理:框架会自动管理资源引用,但建议定期调用
UnloadUnusedAssets()释放未使用资源
- YooAsset 官方文档
- 流程模块文档 - 了解资源模块的初始化流程
- UI 模块文档 - UI 模块如何使用资源模块

