资源的定义
我们以ImageAsset为例:
不去关心这个资源类型的细节,单从上面的配置来看,有三个元素:
1. ImageAsset: 资源类型名
2. AssetName: 资源名
3. ImageFile: 图像文件名(松散资源文件)
这里要注意的是AssetName,它是组成AssetId的重要部分,AssetId是资源的唯一编号,组成规则为: <ModuleId>:<AssetName>
比如:
我们在一个自定义个模块SceneryAsset中加载了上面的这个图像资源,那么产生的资源编号就是:"SceneryAssets:background"
具体使用的时候:
%sprite = new Sprite();
%sprite.Image = "SceneryAssets:background";
最后要说明的是,如果你试图将一个资源拷贝到另一个模块,那么它会得到一个新的唯一资源ID,其他的保持不变.
资源的使用
如上面使用的那段代码,我们创建了一个精灵,然后对Image属性赋与了一张图像资源,代码很简洁,但是我们必须对赋值的背后操作有所了解.
当我们进行赋值操作以后,精灵对象会拿这个资源编号向资源管理器请求对应的资源实例,如果资源没有加载则尝试加载并返回实例,如果已经加载了那么引用计数增加并返回实例.
一个资源同一时间可能会被很多的对象使用,不过我们不需要关心它的引用次数和释放操作,一切都是自动的.
注意:当你对一个资源属性赋值的时候,传递一个资源编号,它可能是各种类型,比如图像资源,音效资源,所属类别从编号上是看不出来的,这就存在一个问题,赋予了一个错误的资源类型,在这种情况下,引擎会拒绝赋值,跳过不执行,不过在控制台日志中会有警告提示.
资源系统的脚本导出
资源系统在引擎中会以单件的方式,以一个叫做"AssetDatabase"的对象暴露给脚本,还有相关的接口(具体接口参照源代码).
具体的使用方法如下:
// 获取申明的资源数量
%count = AssetDatabase.getDeclaredAssetCount();
资源的高级用法
资源管理器暴露给脚本很多关于资源查询的方法,具体的可以参照头文件assetManager_ScriptBinding.h中以find开头的函数.
通过这些find方法,可以快速的查询到我们想要的资源列表,比如通过名字模糊匹配,资源数量,资源的依赖信息,资源的当前引用次数等等.
不过要使用这些方法,需要先了解一个重要的对象,这个对象在这些方法中作为返回信息的存放地AssetQuery.
这个类专门负责资源的查询返回结果保存,给脚本暴露了4个操作接口,分别是:
1. getCount() // 结果数
2. getAsset() // 索引查找
3. clear() // 清空
4. set() // 设置
执行资源查找的步骤大体如下:
1. 创建一个AssetQuery对象
2. 调用一个find开头的资源系统方法
3. 资源系统方法执行填充Query对象
4. 遍历Query,访问结果
5. Query删除
具体操作代码如下:
// 创建
%query = new AssetQuery();
// 查找所有资源
AssetDatabase.findAllAssets( %query );
// 遍历并输出资源编号
for( %i = 0; %i < %query.getCount(); %i++ )
{
echo( %query.getAsset( %i ) );
}
// 删除
%query.delete();
下面看一个复杂的查询,用到了二次查找:
// Create query instance.
%query = new AssetQuery();
// Find partiallly-named assets.
AssetDatabase.findAssetName( %query, "Ninja", true );
// Refine the search to specific asset types.
AssetDatabase.findAssetType( %query, "ImageAsset", true );
// Show all the asset Ids we found.
for( %i = 0; %i < %query.getCount(); %i++ )
{
echo( %query.getAsset( %i ) );
}
// Delete query instance.
%query.delete();
上面的代码,先使用了名字精确匹配找出Ninjia的资源,然后再找出的资源中查找ImageAsset的图像资源列表.
两个方法第三个参数很重要,参照源代码:
S32 findAssetName( AssetQuery* pAssetQuery, const char* pAssetName, const bool partialName = false );
S32 findAssetType( AssetQuery* pAssetQuery, const char* pAssetType, const bool assetQueryAsSource = false );
资源元数据
和上面的资源查询方法类似,资源系统也暴露了一些获取资源信息的接口,资源系统为每一个资源提供了一组元数据集合,比如描述,类别等信息,还有一些只读的元数据,比如类型和位置信息.
参照源代码头文件,那些get和is开头,以资源编号为参数的方法是用来元数据查询的.
下面是一个例子:
assetId = "MyModule:Ninja";
echo( AssetDatabase.getAssetName(%assetId) );
echo( AssetDatabase.getAssetDescription(%assetId) );
echo( AssetDatabase.getAssetType(%assetId) );
资源的显式加载/卸载
如同前面所说的,资源会在被赋予对象的时候进行加载,并指定各自唯一的资源编号,加载和卸载时候的引用计数操作和判断这里就不在多提了,总之在大多情况下,我们不需要关心资源的加载/卸载.
几乎在所有的情况下,引擎不建议我们手动的加载/卸载资源,但是也有例外,比如资源编辑器,所以需要手动的加载/卸载资源,方法如下:
acquireAsset: 加载
releaseAsset: 卸载
这些方法,TorqueScript是提供给编辑环境使用的,除此之外,你不需要显式的执行这些操作.这两个操作是成对出现的,保证资源的正确释放.
在正常的情况,不要执行资源卸载,除非你保证手动加载过,否则虽然不会导致崩溃,但是其他用到这个资源的对象可能会无法对其进行访问.
外部资源,内部资源,私有资源
外部资源是标准资源,可以被赋值于普通的对象,外部资源引用也可以安全的安全的作为对象,比如精灵可以作为场景的一部分.
内部资源其实也是外部资源,只不过附加了一个仅内部可见的标识,在资源系统使用的时候没有什么功能上的差异,只是外部不可见.
私有资源则有很大的不同,它主要是在临时需要的时候创建并允许赋予对象.私有资源在硬盘上没有资源定义文件,也不会被保存下来,只会在内存中发挥作用.但是在资源编辑的时候却是非常有用的,可以创建临时编辑的资源实例并赋予对象使用.
最后私有资源不需要因为要给出一个唯一名称而担心命名冲突的问题,因为资源系统会在它被加入到私有资源库的时候自动分配给它一个临时的名字.
例子:
// Generate an anonymous asset.
%asset = new ImageAsset()
{
ImageFile = "Alien.png";
};
// Add my anonymous asset as a private asset.
%assetId = AssetDatabase.addPrivateAsset( %asset );
// Assign the private asset to a Sprite.
%sprite = new Sprite();
%sprite.ImageMap = %assetId;
// Dump some info to the console.
echo( %asset.getAssetId() );
输出结果为:ImageAsset_1(这是内部生成的临时编号).
正如你所见到的,私有资源可以直接创建,然后再加入为私有资源后,便可以直接使用.他不仅可以赋予对象,而且支持普通资源的所有特性,比如资源查询(这也是为什么资源查询允许通过三种资源权限的过滤操作)
S32 findAllAssets( AssetQuery* pAssetQuery, const bool ignoreInternal = true, const bool ignorePrivate = true );
与另外两种资源权限不同,私有资源不属于任何一个模块,这就意味着它永远不会因为某个模块卸载了而自动删除,所以我们需要手动的删除它.
下面的方法用来删除资源,支持任何权限的资源:
// Remove the asset.
AssetDatabase.removeSingleDeclaredAsset( %myPrivateAsset );
重要的一点,不能保存带有私有资源引用的对象,这么做没有错误,但是当对象下次读取之后,这个引用将会无效.即便是你下次创建一个新的私有资源,也不能保证它的资源编号,因为编号是资源系统自动生成的.
这种情况如果发生,会有警告信息出现在控制台日志中,你可以从他们的资源编号上很容易的认出他们,比如ImageAsset_10,SoundAsset_30等等.
如果你在控制台日志中看到这种资源编号警告,那么很可能是某个对象尝试加载一个不再有效的私有资源,或者因为这个对象保存了一个私有资源的引用.