在主线程中load一个资源(比如材质),将会导致一个停顿,令人很不爽有没有什么办法异步加载呢?我琢磨了一会,利用ResourceLoader API,搞了个异步资源管理器,封装了它原始的调用。
首先我们先来看一下,ResourceLoader提供了什么样的功能:
Error load_threaded_request(path: String, type_hint: String = "", use_sub_threads: bool = false)
请求一个多线程加载。
ThreadLoadStatus load_threaded_get_status(path: String, progress: Array = [])
查看加载进度。
Resource load_threaded_get(path: String)
获得加载的资源。
可以看到,想要从ResourceLoader中多线程加载,是需要轮询的。很遗憾他没有提供信号机制,那我们只能自己封装一个了。
首先先创建一个LoadAsync.gd
脚本,设为自动加载:
extends Node
var loading = {}
var force_cache = true # 用于保持资源的引用,让资源不会释放
var _cache = {}
func loadAsync(path: String):
ResourceLoader.load_threaded_request(path)
var r = LoadAsyncRes.new()
loading[path] = r
return r # 返回用于await的信号
func _process(delta):
var del = []
for k in loading:
var stat = ResourceLoader.load_threaded_get_status(k)
if stat == ResourceLoader.THREAD_LOAD_LOADED:
var res = ResourceLoader.load_threaded_get(k)
loading[k].completed.emit(res) # 发送完成信号
del.append(k)
if force_cache:
_cache[k] = res
elif stat != ResourceLoader.THREAD_LOAD_IN_PROGRESS:
printerr("load error: " + k)
loading[k].completed.emit(null)
del.append(k)
for k in del:
loading.erase(k)
class LoadAsyncRes:
signal completed
在代码中使用:
var texture = await LoadAsync.loadAsync(path).completed
现在在加载资源就不会有明显的卡顿啦!
PS:
保持引用是临时之计,理论上引擎应该保证重复读取没有问题,实际上却有奇怪的bug,比如材质变白……