跳转至

资源句柄与分组预热

资源句柄

当资源会被多个短生命周期对象持有时,可以用 GFAssetHandle 表达所有权。句柄会增加路径引用计数并锁定缓存,release() 后才允许 LRU 淘汰。

如果传入 owner,release_owner(owner) 或 Node 退出树时会释放该 owner 的引用。

assets.load_handle_async(
    "res://ui/inventory_panel.tscn",
    func(handle: GFAssetHandle) -> void:
        if handle == null:
            return
        var scene := handle.get_resource() as PackedScene
        add_child(scene.instantiate())
        handle.release(),
    "PackedScene",
    self,
    &"inventory_ui"
)

分组预热

资源分组适合 UI 包、关卡包或主题包这类“成组预热、成组卸载”的通用流程,不要求项目把业务语义写进工具层。

assets.preload_group_async(
    &"battle_ui",
    [
        { "path": "res://ui/battle_hud.tscn", "type_hint": "PackedScene" },
        { "path": "res://ui/skill_icon_atlas.tres", "type_hint": "Resource" },
    ],
    func(report: Dictionary) -> void:
        print(report["ok"])
)

加载约束

分组预热也可以使用加载通道选项:

assets.preload_group_async(
    &"battle_ui",
    battle_ui_paths,
    _on_battle_ui_ready,
    {
        "max_concurrent_loads": 1,
    }
)

未显式指定 lane_id 时,分组 ID 会作为通道名,因此同一组内部可以串行或限流加载,而不同组仍可独立调度。分组只表达资源集合和加载约束,不表达 UI 包、关卡包或主题包的业务含义。

可保存的预热计划

当预热清单需要放进 .tres、编辑器配置或项目级 manifest 时,用 GFAssetPreloadPlan 保存计划,再委托 preload_plan_async() 执行。计划会保留禁用条目并提供 validate() 报告;实际加载仍复用分组预热、缓存 pin 和 lane 限流机制。

var plan := GFAssetPreloadPlan.new()
plan.configure(
    &"battle_ui",
    [
        { "path": "res://ui/battle_hud.tscn", "type_hint": "PackedScene" },
        { "path": "res://ui/skill_icon_atlas.tres", "type_hint": "Resource", "enabled": true },
    ],
    {
        "plan_id": &"boot.battle_ui",
        "lane_id": &"ui",
        "max_concurrent_loads": 2,
    }
)

assets.preload_plan_async(plan, func(report: Dictionary) -> void:
    if not report["ok"]:
        push_warning("资源预热计划未完全成功。")
)

如果项目只是临时传入路径数组,继续使用 preload_group_async() 更直接;不要为了使用计划对象而把一次性加载流程资源化。