From c8526f1dd6aab9729ee06a9da2f1c45d26bf66f9 Mon Sep 17 00:00:00 2001 From: lili Date: Wed, 17 Jun 2026 23:11:14 -0700 Subject: [PATCH] =?UTF-8?q?docs(game-runtime):=20U1=20=E8=BF=90=E8=A1=8C?= =?UTF-8?q?=E6=97=B6=E7=BA=A6=E5=AE=9A=E6=96=87=E6=9C=AC=20runtime-api-2d.?= =?UTF-8?q?md(=E4=BA=A4=20U3=20prompt=20=E5=B5=8C=E5=85=A5)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit plan 2026-06-18-001 U1 交付物「约定文字同步喂进 prompt → 交 U3 落 SaaPrompts 新 SYSTEM」。 新增 game-runtime/src/host/runtime-api-2d.md——写 gameDefinition behavior 逻辑时能用的全部 rt 面 的人/模型可读契约:gameDefinition 结构 / behavior 代码契约(new Function('rt','self','dt',code)+ trigger 语义+四条硬约束)/ rules / rt 面全 API 参考 / 组件 / 4 原型 few-shot / 常见坑(治真实模型 漂移:禁约定外 helper、禁 Math.random、终态置 latch、behavior 不画图、关键事件挂 fx)。 U3 的 GAMEDEF_SYSTEM prompt 直接嵌入本文。状态 v0(已过 4 类原型表达力证),保留补 idiom 余量。 落点同 game-host.d.ts 之理(内部宿主↔behavior 接线面 → game-runtime/src/host/); 是否升格 contracts/ 跨仓契约由 6c6g(contracts owner)定。 Co-Authored-By: Claude Opus 4.8 --- game-runtime/src/host/runtime-api-2d.md | 120 ++++++++++++++++++++++++ 1 file changed, 120 insertions(+) create mode 100644 game-runtime/src/host/runtime-api-2d.md diff --git a/game-runtime/src/host/runtime-api-2d.md b/game-runtime/src/host/runtime-api-2d.md new file mode 100644 index 00000000..ffcab560 --- /dev/null +++ b/game-runtime/src/host/runtime-api-2d.md @@ -0,0 +1,120 @@ +# 运行时访问约定(2D 适配器 · behavior 侧 API)—— runtime-api-2d v0 + +> plan 2026-06-18-001 U1 交付物。本文件是「写 gameDefinition 的 behavior 逻辑时能用的全部 `rt` 面」的**人/模型可读契约**, +> U3 的 `GAMEDEF_SYSTEM` prompt 直接嵌入本文(+ 末尾 few-shot)。实现见 `gd-runtime.js`,类型雏形随后正式化为 `runtime-api-2d.d.ts`。 +> +> **状态 v0(plan「别冻早」)**:已过 4 类原型表达力证(见 `gd-archetypes.test.mjs`),接口稳定但保留随真实模型输出补 idiom 的余量。 +> **落点说明**:与 `game-host.d.ts`(第 9 类契约)同理,本约定是 game-runtime 内部「宿主↔游戏 behavior」接线面,故落 `game-runtime/src/host/`; +> 是否升格为 `contracts/` 跨仓契约由 6c6g(大脑线/contracts owner)定。 + +--- + +## 1. 游戏 = 声明式 gameDefinition(改源不改打包产物) + +一个游戏 = 一份 `gameDefinition` JSON(结构见 `contracts/agent-loop/source-project.schema.json`): + +| 字段 | 含义 | +|---|---| +| `entities[]` | 实体:`{id, transform:{position:{x,y}}, components:[组件id...]}`(可带 `vx/vy/tags` 供运行时用) | +| `components[]` | 组件定义:`{id, kind, ...}`,`kind ∈ render/collision/physics/custom` | +| `behaviors[]` | 行为模块:`{id, trigger, code}`——`code` 是一段 **JS 逻辑字符串**,运行期编译执行 | +| `scenes[]` | 场景:`{id, entityRefs:[实体id...]}`(v0 取 `scenes[0]` 决定初始实例化哪些实体;缺省全量) | +| `rules[]` | 胜负规则:`{id, condition, outcome}`——`condition` 是 JS 布尔表达式串,`outcome ∈ win/lose/score/advance` | + +**核心范式**:实体/组件/场景/规则是**声明式数据**;唯一的「逻辑代码」是 `behaviors[].code` 和 `rules[].condition`, +它们经受控的 `rt` 面操作世界。**behaviors 只写逻辑、不写画**(出图由声明式渲染器据 render 组件自动完成)。 + +--- + +## 2. behavior 代码契约 + +每个 behavior 的 `code` 被编译为 `new Function('rt', 'self', 'dt', code)`,每次调用注入三参: + +- **`rt`** — 运行时访问面(见 §4),操作世界的唯一入口。 +- **`self`** — 本 behavior 的**持久局部态**(普通对象 `{}`,跨帧保留)。存计时器/累加器:`self.t = (self.t||0) + dt;` +- **`dt`** — 本帧时间步(秒)。 + +**trigger 语义**: +- `init`:世界建好后**跑一次**(布初始实体/初值)。 +- `update` / `input` / `collision` / `timer`:**每帧跑一次**(输入经 `rt.input` 轮询;碰撞/计时在 behavior 内自查)。 + +**硬约束(违反 = 生成缺陷)**: +1. **确定性**:随机一律 `rt.random/rt.randRange/rt.randInt`,时间一律 `rt.time.now()`/`dt`——**禁 `Math.random` / `Date.now` / `performance.now`**。 +2. **只用 `rt` 面**:禁自造约定外 helper(如 `rt._spawnFood`)、禁 `document`/`window`/裸引擎/`requestAnimationFrame`/`addEventListener`。要生成实体用 `rt.spawn`。 +3. **终态置 latch**:胜负用 `rt.win()`/`rt.lose()`(置不可逆终态),**不要**用计分或自定义 flag 表达「游戏结束」。 +4. **特效经 `rt.fx`**:碰撞/得分等关键事件调 `rt.fx.burst(...)` / `rt.fx.beep(...)`(真接引擎粒子/音频)。 + +--- + +## 3. 规则(rules) + +`condition` 是 JS 布尔表达式串,作用域内有 `rt`(与 `self`)。每帧求值;为真时按 `outcome`: + +- `win` / `lose` → 置 latch 终态(一次性,不可逆)。 +- `score` → 上升沿 +1 分(防每帧重复加)。 +- `advance` → 场景推进(v0 占位)。 + +例:`{ "id":"win", "condition":"rt.score >= 10", "outcome":"win" }` + +--- + +## 4. `rt` 面参考(全部可用 API) + +### 实体 +- `rt.getEntity(id)` → 实体或 null(仅活实体) +- `rt.entities()` → 全部活实体数组 +- `rt.query(name)` → 按 tag 或组件 id/kind 过滤的活实体数组 +- `rt.spawn({x, y, vx?, vy?, tags?, components?})` → 新实体(`components` 可内联组件对象);返回实体引用 +- `rt.destroy(entity)` → 标记死亡(帧末回收) +- 实体字段:`.x .y .vx .vy .alive .tags(Set) .components(数组)`;方法 `.get(k)` / `.set(k,v)` / `.destroy()`;可直接读写任意属性(`e.hp = 3`) + +### 输入(轮询) +- `rt.input.isDown(key)` → 是否按住(如 `'ArrowLeft'`/`'Space'`) +- `rt.input.justPressed(key)` → 本帧是否刚按下 +- `rt.input.justTapped()` → 本帧是否发生指针按下 +- `rt.input.pointer` → `{x, y, down}` + +### 时间 / 随机(确定性) +- `rt.time.now()` → 相对游戏时间(秒,从 0 累加;**用这个**,非绝对钟) +- `rt.dt` → 本帧步长(秒,= 注入的 `dt`) +- `rt.random()` → `[0,1)`;`rt.randRange(a,b)` → `[a,b)`;`rt.randInt(a,b)` → `[a,b]` 整数 + +### 分数 / 胜负 +- `rt.score`(读)/ `rt.addScore(n=1)` / `rt.setScore(n)` +- `rt.win()` / `rt.lose()` → 置 latch 终态 + +### 工具 / 特效 +- `rt.clamp(v,lo,hi)` / `rt.dist(ax,ay,bx,by)` / `rt.overlap(a,b)`(AABB,`a/b={x,y,w?,h?}`,缺省半尺寸 16) +- `rt.fx.burst(x,y,color)` → 引擎粒子(color 接 `'#rrggbb'` 或 `{r,g,b,a}`) +- `rt.fx.beep(kind)` → 引擎音效(kind ∈ `score/hit/lose/win/default`) +- `rt.view` → `{w:390, h:844}`(视口;边界判断用) + +--- + +## 5. 组件(components) + +- **render**:`{id, kind:'render', shape, color, ...}` + - `shape:'rect'` + `w,h`(以实体 transform 为中心) + - `shape:'circle'` + `r` + - `shape:'fill'` + `color`(铺满视口,作背景) +- **physics**:`{id, kind:'physics', gravity?}`——挂此组件的实体每帧自动 `x+=vx*dt; y+=vy*dt`(有 `gravity` 则先 `vy+=gravity*dt`)。不挂则位置全由 behavior 控制。 +- **collision / custom**:声明式标记,由 behavior 自行 `rt.overlap` 判定 / 读取。 + +--- + +## 6. 原型范式(few-shot · 见 `gd-archetypes.test.mjs` 完整可跑版) + +- **paddle-intercept(打砖块/pong)**:板 entity + 球 entity(`vx/vy`);update behavior 里键/指针控板、球积分+墙反弹、`rt.overlap` 板拦截 `rt.addScore`+`rt.fx.burst`、落底 `rt.lose()`。 +- **event-clicker(点击器/放置)**:按钮 entity;input behavior 里 `if(rt.input.justTapped()) rt.addScore(1)`;rule `rt.score>=N → win`。 +- **dodge-spawn(躲避)**:玩家 entity;update behavior 里键控玩家、定时 `rt.spawn` 随机位敌人(`rt.randRange`)、遍历 `rt.query('enemy')` 下落+出界 `rt.destroy`+`rt.overlap` 撞玩家 `rt.lose()`。 +- **runner(跑酷)**:玩家挂 `physics{gravity}`;update behavior 里 `rt.input.justTapped()` 起跳(置 `vy`)、落地复位、定时 `rt.spawn` 障碍(`vx`)、`rt.overlap` 撞障碍 `rt.lose()` / 出界 `rt.addScore`。 + +--- + +## 7. 常见坑(治真实模型漂移) + +- ❌ 自造 `rt._spawnFood` 等约定外 helper → ✅ 用 `rt.spawn(...)`。 +- ❌ `Math.random()` / `Date.now()` → ✅ `rt.random()` / `rt.time.now()`(确定性,否则取证不可复现 + 静态门拒)。 +- ❌ 用分数/flag 表达「结束」 → ✅ `rt.win()`/`rt.lose()` 置 latch。 +- ❌ 在 behavior 里画图(`ctx.fillRect`)→ ✅ 给实体加 render 组件,渲染器自动出图。 +- ❌ 关键事件无特效 → ✅ 碰撞/得分调 `rt.fx.burst`/`rt.fx.beep`(满「真接线」门)。