跳到主要内容

使用资源注册表

信息

点击以获取焦点,按住或松开空格键可在 A、B 两个模型之间切换。按 L 键加载 C 模型,按住 C 键显示它。

对于简单游戏和产品,可以在编辑器中配置所有资源,让它们在应用启动前预加载,应用即可正常运行。

对于更复杂的产品,可能需要在代码中访问资源、更改引用、修改属性,并按需加载数据,使应用更快启动。为此需要使用 AssetRegistry。

本教程将构建一个小场景,按键时替换渲染组件的模型,并动态加载第三个未预加载的模型。完整项目在此。

配置​

项目配置如下:

  • 上传三个模型资源:A 为字母 A 的模型,B 为字母 B 的模型,C 为字母 C 的模型。
  • 将 C 渲染资源设置为不预加载。
  • 向场景添加一个渲染实体,并将模型 A 分配给其渲染组件。
  • 向渲染实体添加脚本组件,并创建名为 update_asset.js 的新脚本。

下载 A 模型、B 模型和 C 模型,上传到项目中。请确保文件名分别为 A.dae、B.dae 和 C.dae,因为这会影响资源名称。

资源注册表​

所有脚本均可通过 this.app.assets 访问 pc.AssetRegistry。注册表记录项目中所有运行时资源的详细信息,无论它们是否已加载。使用资源注册表可以查找应用所需的资源。

这里声明了 a、b、c 三个脚本属性,并在编辑器中为其指定资源,随后便可直接在脚本中使用。

使用预加载资源​

if (app.keyboard.isPressed(pc.KEY_SPACE)) {
if (this.entity.render.asset !== this.b.id) {
// update the render component to the new Render Asset
console.log('Changed to B Render Asset');
this.entity.render.asset = this.b;
}
} else {
// ...
if (this.entity.render.asset !== this.a.id) {
// restore original Render Asset
console.log('Changed to A Render Asset');
this.entity.render.asset = this.a;
}
// ...
}

本项目中的 A 和 B 资源标记为 preload(预加载)。这意味着资源会在加载界面显示期间下载,并在应用启动时即可使用。资源加载完成后,可通过 asset.resource 访问加载的运行时资源,并将资源指定给渲染组件的 asset 属性。若 asset.loaded 为 false,则表示尚未加载。

由于 A 和 B 模型已预加载,可以确定它们在应用运行时已经就绪。这段代码检查空格键是否按下,并相应切换渲染组件使用的资源。这里的 asset.resource 是 pc.Render 对象。对于音频、纹理等其他资源类型,asset.resource 则为对应类型。

在运行时加载资源​

if (app.keyboard.isPressed(pc.KEY_C)) {
if (this.c.loaded) {
if (this.entity.render.asset !== this.c.id) {
console.log('Changed to C Render Asset');
this.entity.render.asset = this.c;
}
}
} else {
if (this.entity.render.asset !== this.a.id) {
// restore original Render Asset
console.log('Changed to A Render Asset');
this.entity.render.asset = this.a;
}
}

C 渲染资源未标记为 preload,所以上面的代码会在使用前检查其是否加载。如果 asset.loaded 为 false,就不能切换到该渲染资源。加载完成后,this.c.resource 为 pc.Render,asset.loaded 为 true,此时即可进行分配。

if (this.app.keyboard.isPressed(pc.KEY_L)) {
this.app.assets.load(this.c);
}

按 L 键会加载 C 模型,方法是将尚未加载的资源传入 this.app.assets.load()。如果资源已经加载,该方法不会执行任何操作。

加载完成后,asset.resource 是 pc.Render 实例,按 C 键即可将该资源分配给渲染组件。

完整脚本​

var UpdateAsset = pc.createScript('updateAsset');

UpdateAsset.attributes.add('a', {
type: 'asset',
assetType: 'render'
});

UpdateAsset.attributes.add('b', {
type: 'asset',
assetType: 'render'
});

UpdateAsset.attributes.add('c', {
type: 'asset',
assetType: 'render'
});

// initialize code called once per entity
UpdateAsset.prototype.initialize = function() {
this.app.keyboard.preventDefault = true;
};

// update code called every frame
UpdateAsset.prototype.update = function(dt) {
var app = this.app;

if (app.keyboard.isPressed(pc.KEY_SPACE)) {
if (this.entity.render.asset !== this.b.id) {
// update the render component to the new Render Asset
console.log('Changed to B Render Asset');
this.entity.render.asset = this.b;
}
} else {
if (app.keyboard.isPressed(pc.KEY_C)) {
if (this.c.loaded) {
if (this.entity.render.asset !== this.c.id) {
console.log('Changed to C Render Asset');
this.entity.render.asset = this.c;
}
}
} else {
if (this.entity.render.asset !== this.a.id) {
// restore original Render Asset
console.log('Changed to A Render Asset');
this.entity.render.asset = this.a;
}
}
}

if (app.keyboard.isPressed(pc.KEY_L)) {
app.assets.load(this.c);
}
};

AssetRegistry 事件​

上面的示例没有演示如何获知资源何时完成加载。为此可以监听 pc.AssetRegistry 的事件,例如 "load"。示例代码如下:

// find the asset by name in the registry
var asset = this.app.assets.find("A");
// set up a one-off event listener for the load event
this.app.assets.once("load", function (asset) {
// asset.resource is now ready
}, this);

"load" 事件的范围较广,每个资源加载后都会触发。如果其他地方也在加载资源,就无法确认是不是目标资源。可以改用 "load:id" 事件缩小监听范围。

// find the asset in the registry
var asset = this.app.assets.find("A");
// set up a one-off event listener for the load event
this.app.assets.once("load:" + asset.id, function (asset) {
// asset.resource is now ready
}, this);

上述事件只会为指定资源触发,因此更加实用。

最后还有一种经常出现的代码模式,我们为此提供了便捷方法。

var asset = this.app.assets.find("A");
if (!asset.loaded) {
this.app.assets.once("load:" + asset.id, function (asset) {
// do something with asset.resource
});
this.app.assets.load(asset);
} else {
// do something with asset.resource
}

这段代码在需要时加载资源,但写起来稍显冗长。可以改用 asset.ready(),下面的代码与上面的功能相同:

var asset = this.app.assets.find("A");
asset.ready(function (asset) {
// do something with asset.resource
});
this.app.assets.load(asset);

asset.ready() 在资源完成加载后立即调用回调;如果资源已经加载,则马上调用。资源已加载时,app.assets.load() 不执行任何操作。