加载与卸载
PlayCanvas 提供运行时动态加载和卸载资源的 API,可以精细控制内存占用,并按需加载内容。
加载资源
加载已注册资源
对于已经在资源注册表中的资源,例如编辑器添加的资源,使用 app.assets.load():
const asset = this.app.assets.find('My Texture');
asset.ready((asset) => {
// Asset is loaded and ready to use
const texture = asset.resource;
});
this.app.assets.load(asset);
从 URL 加载
运行时从 URL 加载资源,使用 app.assets.loadFromUrl():
this.app.assets.loadFromUrl('path/to/texture.png', 'texture', (err, asset) => {
if (err) {
console.error('Failed to load texture:', err);
return;
}
// Asset is loaded and added to the registry
const texture = asset.resource;
});
第二个参数指定资源类型,常见类型包括:
texture:图像,如 PNG、JPG、WebP。model:3D 模型,如 GLB。audio:音频文件,如 MP3、OGG、WAV。json:JSON 数据。binary:二进制数据。css:样式表。html:HTML 文档。script:JavaScript 文件。shader:着色器代码。
携带选项加载
从 URL 加载时可以传入额外选项:
this.app.assets.loadFromUrlAndFilename(
'path/to/model.glb',
'model.glb',
'container',
(err, asset) => {
if (err) {
console.error('Failed to load model:', err);
return;
}
// Create an entity from the loaded model
const entity = asset.resource.instantiateRenderEntity();
this.app.root.addChild(entity);
}
);
处理加载事件
使用 ready()
ready() 在资源加载完成时执行回调。如果资源已经加载,回调立即执行:
const asset = this.app.assets.find('My Model');
asset.ready((asset) => {
// Safe to use asset.resource here
});
// Trigger loading if not already loaded
if (!asset.loaded) {
this.app.assets.load(asset);
}
使用事件
可以在单个资源或注册表上监听加载事件:
// Listen on a specific asset
asset.on('load', (asset) => {
console.log('Asset loaded:', asset.name);
});
asset.on('error', (err, asset) => {
console.error('Load failed:', asset.name, err);
});
// Listen on the registry for any asset
this.app.assets.on('load', (asset) => {
console.log('Some asset loaded:', asset.name);
});
配置重试
资源加载失败时会自动重试,以应对 CDN 较慢、短暂断网等临时网络问题。默认情况下,每个失败请求最多重试 5 次,使用指数退避,间隔为 200、400、800、1600、3200 毫秒,上限为 5000 毫秒。
可以全局修改所有资源类型的重试设置:
// Override the default retry count
this.app.loader.enableRetry(3);
// Disable retries entirely - load failures are reported immediately
this.app.loader.disableRetry();
也可以按资源类型单独配置:
// Only retry texture loads more aggressively
this.app.loader.getHandler('texture').maxRetries = 10;
编辑器项目还可通过网络设置面板覆盖默认重试次数。
限制并发请求
应用同时加载大量资源时,如果并发请求过多,浏览器可能以 net::ERR_INSUFFICIENT_RESOURCES 拒绝请求。为此,引擎限制并发资源请求数量,超出上限的请求进入队列,在较早请求完成后再发出。
默认上限为 128,既能兼容各浏览器,又能充分利用常见 CDN 吞吐量。可以全局修改:
// Allow at most 50 asset requests to be in flight at once
this.app.loader.maxConcurrentRequests = 50;
// Disable throttling entirely - every request is sent immediately
this.app.loader.maxConcurrentRequests = 0;
此限制是进程级全局设置,应用于共享 HTTP 层,与浏览器的进程级资源限制相对应。同一页面存在多个应用时,以最后设置的值为准。它适用于所有基于 XMLHttpRequest 的加载,覆盖绝大多数资源。
编辑器项目也可通过网络设置面板配置。
携带凭据加载
资源请求默认不携带凭据。如果资源位于需要 cookie、客户端 TLS 证书或 HTTP 身份验证的跨域主机上,可以全局启用凭据:
// Send all asset requests with credentials
this.app.loader.withCredentials = true;
必须在预加载或加载任何资源之前设置,使请求采用该配置。服务器必须返回非通配符的 Access-Control-Allow-Origin,以及 Access-Control-Allow-Credentials: true,否则浏览器会阻止响应。
这也是进程级全局设置,作用于共享 HTTP 层。同一页面存在多个应用时,以最后设置的值为准。它适用于所有资源加载,包括直接获取数据而不经过 HTTP 层的高斯泼溅和资源包加载器。
卸载资源
可以卸载不再需要的资源以释放内存:
const asset = this.app.assets.find('Large Texture');
// Unload the resource but keep the asset in the registry
asset.unload();
// The asset can be loaded again later
this.app.assets.load(asset);
移除资源
要从注册表中彻底移除资源:
const asset = this.app.assets.find('Temporary Asset');
// Remove from registry (also unloads the resource)
this.app.assets.remove(asset);
加载多个资源
要加载多个资源,并等待它们全部完成:
const assetNames = ['texture1', 'texture2', 'model1'];
const assets = assetNames.map(name => this.app.assets.find(name));
let loaded = 0;
const total = assets.length;
const onAssetLoad = () => {
loaded++;
if (loaded === total) {
// All assets loaded
this.onAllAssetsReady();
}
};
for (const asset of assets) {
asset.ready(onAssetLoad);
if (!asset.loaded) {
this.app.assets.load(asset);
}
}
最佳实践
- 卸载未使用的资源:切换关卡或场景时卸载资源,释放内存。
- 使用 ready():它同时处理已经加载和尚未加载的情况。
- 处理错误:动态加载始终应提供错误处理。
- 成组加载:一起加载相关资源,避免视觉不一致。