Overworld

快速开始

从安装到第一个可运行的任务闭环,理解 Overworld Engine 的跨平台装配方式

Overworld Engine 是一个面向生产的跨平台 3D RPG TypeScript 框架。它把世界 渲染、玩家控制、无头玩法引擎、AI、联机、UI 和多端适配拆成 27 个独立包。你只 安装需要的能力,并在应用层决定它们如何协作;同一套领域系统可以运行在 Web、 桌面、移动端、小游戏与 Node.js 服务端。

这篇指南有两条路径:

你的目标从哪里开始
先确认框架实际能做什么运行仓库里的 Starter,约 3 分钟看到完整垂直切片
接入已有 TypeScript 应用完成一个最小闭环:移动 → 任务 → 奖励 → UI 事件

下面的接入示例不要求 three.js,也不要求任务包依赖场景、背包或 UI。完成后你会 得到一个可以用日志直接验收的运行时闭环。

0. 先体验完整 Starter(推荐)

如果你还没决定是否采用 Overworld,先运行真实示例,不必先理解所有包:

git clone https://github.com/luzhenqian/overworld.git
cd overworld
corepack enable
pnpm install
pnpm build
pnpm --filter starter dev

打开终端显示的地址,按 Starter 验收路线 依次体验移动、对话、任务、背包、AI、联机与编辑器。准备接入自己的应用时,再从 下一节开始。

前置要求

项目当前支持范围
JavaScript 运行时现代浏览器;仓库 CI 使用 Node.js 22
模块ESM
TypeScriptstrict 项目;仓库使用 TypeScript 5.6
React 3D 栈React 18、three.js ≥ 0.160、React Three Fiber 8、drei 9
状态zustand 5

发布包不依赖 pnpm。npm、yarn 与 pnpm 都可以使用;本文命令默认采用 pnpm。 完整的 peer 依赖矩阵与多包管理器命令见兼容性与支持范围

1. 安装最小组合

先安装 core 和需要的系统。下面的闭环使用 quest;加入 scene 才需要 React 3D peer:

pnpm add @overworld-engine/core @overworld-engine/quest react zustand

如果要渲染 3D 世界:

pnpm add @overworld-engine/scene react react-dom three \
  @react-three/fiber @react-three/drei zustand

Overworld 没有“全家桶”入口。显式安装所需包能让依赖、包体和系统边界保持清楚。 不知道如何选择时,先看包选择指南

2. 定义纯内容

任务标题、目标、触发事件和奖励都是可序列化数据。type 字符串只是对应用代码 中处理器的引用,不会把业务逻辑塞进内容:

game/content.ts
import type { QuestDefinition } from '@overworld-engine/quest'

export const QUESTS: QuestDefinition[] = [
  {
    id: 'first-steps',
    title: '迈出第一步',
    description: '在村庄里走 20 米。',
    autoStart: true,
    objectives: [
      {
        id: 'walk',
        description: '探索村庄',
        target: 20,
        trigger: {
          event: 'player:moved',
          amountFrom: 'distance',
        },
      },
    ],
    rewards: [
      { type: 'wallet.addGold', params: { amount: 50 } },
    ],
  },
]

在真实项目里,titledescription 通常保存 i18n key;参考 i18n 内容组织

3. 在一个装配点创建引擎

注册表是声明式内容与游戏代码唯一需要相遇的地方。任务引擎只认识 wallet.addGold 这个名字,不认识你的钱包 store:

game/engines.ts
import {
  createConditionRegistry,
  createEffectRegistry,
  gameEvents,
} from '@overworld-engine/core'
import { createQuestEngine } from '@overworld-engine/quest'
import { QUESTS } from './content'

export const conditions = createConditionRegistry()
export const effects = createEffectRegistry()

let gold = 0

effects.register('wallet.addGold', (params) => {
  gold += Number(params.amount)
})

export const quests = createQuestEngine({
  quests: QUESTS,
  conditions,
  effects,
  events: gameEvents,
  persist: false,
})

export function getGold() {
  return gold
}

persist: false 适合第一个原型。准备保存进度时显式改成 true 或传入带 nameversionmigratestorage 的配置;见 持久化互操作

4. 发出领域事件

先订阅任务完成事件,再让移动系统发出类型安全的领域事件:

import { gameEvents } from '@overworld-engine/core'
import { getGold, quests } from './game/engines'

const stop = gameEvents.on('quest:completed', ({ questId }) => {
  console.log(`任务完成:${questId},当前金币:${getGold()}`)
})

gameEvents.emit('player:moved', {
  position: [20, 0, 0],
  distance: 20,
})

// 控制台:任务完成:first-steps,当前金币:50

stop()
quests.dispose()

quest 订阅了内容中声明的 player:moved,会按 amountFrom: 'distance' 累计目标。达到 20 后,它按顺序执行奖励,并发出 quest:objective-completedquest:completed。这里显式清理监听器和引擎;在 React 应用中应在所属 runtime 或组件卸载时做同样的清理。

渲染世界时,scene<Player> 会替你发出真实移动事件:

import { Canvas } from '@react-three/fiber'
import { Player, SceneShell } from '@overworld-engine/scene'

export function World() {
  return (
    <Canvas shadows>
      <ambientLight intensity={1.2} />
      <SceneShell
        npcs={[]}
        buildings={[]}
        player={<Player />}
      />
    </Canvas>
  )
}

5. 让 UI 响应,而不是反向耦合

UI 可以订阅事件,也可以直接订阅引擎的 zustand store:一次性反馈(Toast、 音效、埋点)适合事件,长期状态(任务列表、当前进度)适合 store。不要靠重放 历史事件恢复页面状态。

如果使用 @overworld-engine/ui,引擎绑定组件通过结构类型接入真实引擎,不会 让 UI 包反向依赖任务包:

import '@overworld-engine/ui/styles.css'
import '@overworld-engine/ui/themes/hextech.css'
import { QuestTracker } from '@overworld-engine/ui'
import { quests } from './game/engines'

<QuestTracker engine={quests} />

6. 验证内容和接线

开发构建中,让 devtools 在内容进入运行时前检查引用、循环与未注册的条件/效果:

pnpm add -D @overworld-engine/devtools @overworld-engine/test-kit
if (import.meta.env.DEV) {
  const { assertValidContent } = await import('@overworld-engine/devtools')

  assertValidContent(
    { quests: QUESTS },
    {
      effectTypes: effects.types(),
      conditionTypes: conditions.types(),
    },
  )
}

应用层测试可用 @overworld-engine/test-kit 录制真实事件流,证明装配没有漏接:

import { createEventRecorder } from '@overworld-engine/test-kit'

const recorder = createEventRecorder(gameEvents)
// 驱动真实 action 或事件……
expect(recorder.events.at(-1)?.event).toBe('quest:completed')
recorder.stop()

完成标准

继续叠加系统前,先确认这个最小运行时满足:

  • 触发一次 20 米移动后,控制台只出现一次任务完成日志。
  • 日志中的金币为 50,说明效果先于 quest:completed 事件执行。
  • 调用 dispose() 后继续发移动事件,不再改变任务状态。
  • 内容文件没有 import wallet、UI 或 React 组件。
  • 开发构建的内容校验没有未知条件、未知效果或悬空引用。

如果任一项不成立,先看排障手册,不要继续接入更多包。

下一步

如果你要……接下来阅读
跑一个完整可玩项目Starter 示例
建立 EventBus、store、注册表的心智模型核心概念
理解包边界与事件协作架构说明
选择第一批依赖包选择指南
构建密集 3D 世界密集世界指南
接入 WebSocket / 权威服权威多人
面向 Web、桌面、移动端或微信交付多端支持
遇到安装、存档、输入或联机问题排障手册

也可以直接阅读全部 27 个包的参考文档。每个参考页都以当前 packages/*/src/index.ts 的公开导出为边界。

本页目录