Overworld
指南

资产组织与预加载

目录约定、资产清单与加载进度的分工

目录建议

资产放 public/ 下按类型 + 用途两级划分,URL 即路径,内容文件里直接引用:

public/
  models/
    characters/   # 玩家、NPC(guide.glb、trader.glb…)
    buildings/    # 建筑
    props/        # 道具、可交互物(crystal.glb…)
  audio/
    bgm/          # 场景背景音乐
    sfx/          # 音效(点击、拾取、完成…)
  images/         # UI 图、头像、贴图

GLB 压缩:上线前跑一遍 draco 或 meshopt(如 gltf-transform optimize), 角色/建筑模型通常能小 5–10 倍;drei 的 useGLTF 原生支持两者。

资产清单:声明、拆分、组合、预热

@overworld-engine/loading 的清单 API 把每个场景的资产声明成数据,按场景一份 manifest:

// game/assets.ts
import { defineAssetManifest, mergeManifests, preloadManifest } from '@overworld-engine/loading'

export const VILLAGE_ASSETS = defineAssetManifest({
  models: ['/models/characters/guide.glb', '/models/props/crystal.glb'],
  audio: ['/audio/bgm/village.mp3'],
})

export const DUNGEON_ASSETS = defineAssetManifest({
  models: ['/models/buildings/dungeon-gate.glb'],
  audio: ['/audio/bgm/dungeon.mp3', '/audio/sfx/door.mp3'],
})

// 启动时预热首个场景;相邻场景可在靠近传送门时再预热
preloadManifest(VILLAGE_ASSETS)
// 或一次性组合(按类别去重):
preloadManifest(mergeManifests(VILLAGE_ASSETS, DUNGEON_ASSETS))

defineAssetManifest 是恒等函数,只提供类型推断——它的价值在于把"这个场景用哪些资产" 固化成一处可检查、可组合的数据,而不是散落在组件里的字符串。

三个工具的分工

工具职责
preloadManifest(manifest)loading全类别预热(models/images/audio),游戏级/场景级,尽早调用
preloadSceneModels(config)scene便捷函数:直接吃 NPCConfig[]/BuildingConfig[],只预热模型
useSceneLoadProgress()loadingCanvas 内桥接 drei useProgress → loadingStore,真实进度来源

关键设计:预热不上报进度preloadManifest / preloadSceneModels 只是提前触发 下载并填充 GLTF 缓存,不写 loading store(预加载 API 没有细粒度进度,造假任务只会骗 加载条)。真实的模型加载进度由 three.js 加载管理器产生,场景挂载后经 useSceneLoadProgress 写入 store,加载界面读 useLoadingStoreprogress / isLoading 即可。fonts 类别仅作清单记录,预热时跳过(drei <Text> 自行加载字体)。

加载失败回退:开发期可以零资产跑通

scene 包的模型加载(useModelLoader)捕获加载失败并返回空结果,各组件渲染主题色 几何体兜底:

  • BaseNPC → 胶囊体(theme.fallbackColor);
  • BaseBuilding → 盒体(theme.fallbackBoxColor);
  • Player → 胶囊体(无模型路径或加载失败时)。

所以内容文件里可以先写好 modelPath: '/models/characters/guide.glb' 而文件根本不存在—— 游戏照常运行、碰撞与交互正常,美术资产后补,替换文件即可,不改代码。 starter 示例正是以这种"全回退"形态发布的。

本页目录