From 95b2572e651a3bd8564ba701ff68a3fa030d897f Mon Sep 17 00:00:00 2001 From: lili Date: Thu, 18 Jun 2026 06:38:50 -0700 Subject: [PATCH] =?UTF-8?q?docs(game-runtime):=20U1=20=E7=BA=A6=E5=AE=9A?= =?UTF-8?q?=E6=AD=A3=E5=BC=8F=E5=8C=96=20runtime-api-2d.d.ts(rt=20?= =?UTF-8?q?=E6=8E=A5=E5=8F=A3=20TS=20=E5=A5=91=E7=BA=A6=20=C2=B7=20?= =?UTF-8?q?=E7=AC=AC10=E7=B1=BB=E5=A5=91=E7=BA=A6=20additive)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit plan 2026-06-18-001 U1 正式化产物(plan「1-2 轮后正式化」已满足:4 轮迭代+跨品类 9/9 实证+clickable 基元,约定已稳)。 手写 TS 契约(同 api.d.ts/game-host.d.ts 范式),与 gd-runtime.js 同形: - gameDefinition 声明式模型:Render/Physics/Clickable/Marker 组件 + EntityDef/BehaviorDef(code)/RuleDef/SceneDef。 - rt 面(behavior 侧):实体 getEntity/entities/query/spawn/destroy + Entity 实例形 + input(轮询)/time(确定性,无 nowMs)/ dt/random/score-win-lose(latch)/clamp-dist-overlap/fx/view。 - ForensicsState:固定取证键 + 逐实体 id 投影命名位(ball.x…)+ tag=target → targets[]。 - createRuntime(boot,gameDefinition)→Runtime(init/update/render/state/destroy/errors)签名。 落 game-runtime/src/host/(同 game-host.d.ts 之理:内部宿主↔behavior 接线面,非跨仓 SSOT); additive 第 10 类契约,**不动现 8 契约**(故未改 source-project.schema.json;clickable 入其 kind 枚举=additive, 留 6c6g/创始人 决,contract-first 补正)。 Co-Authored-By: Claude Opus 4.8 --- game-runtime/src/host/runtime-api-2d.d.ts | 217 ++++++++++++++++++++++ 1 file changed, 217 insertions(+) create mode 100644 game-runtime/src/host/runtime-api-2d.d.ts diff --git a/game-runtime/src/host/runtime-api-2d.d.ts b/game-runtime/src/host/runtime-api-2d.d.ts new file mode 100644 index 00000000..e959844d --- /dev/null +++ b/game-runtime/src/host/runtime-api-2d.d.ts @@ -0,0 +1,217 @@ +// runtime-api-2d.d.ts —— 运行时访问约定(2D 适配器 · behavior 侧 API)TS 契约 · core-runtime-v0 +// owner:本 session(引擎线 · plan 2026-06-18-001 U1 正式化产物) | 消费方:U2 build-from-source 装配器 + U3 GAMEDEF_SYSTEM prompt +// +// 【为什么手写 .d.ts、落 game-runtime/src/host/】 +// 与 game-host.d.ts(第 9 类契约)同理:发行版源 = ESM JS + JSDoc,对外「类型契约」手写。本约定是 game-runtime +// 内部「宿主↔游戏 behavior」接线面(behaviors 经 rt 操作世界),与 api.d.ts(插件↔引擎面)正交、与 game-host.d.ts +// (游戏工厂↔宿主面)相邻;故落 src/host/,不落 contracts/(避免跨仓 SSOT 反向 import)。是否升格 contracts/ 由 6c6g 定。 +// +// 【与实现同形】本文件与 gd-runtime.js 的 createRuntime/rt 必须同形同步;人/模型可读版见同目录 runtime-api-2d.md。 +// 【状态】已过 4 轮迭代 + 跨品类 9/9 实证(含 clickable 基元),约定稳定,正式化为契约。后续演进只增不破已冻签名。 + +import type { PluginContext } from '../core/api.d.ts'; +import type { GameHostBootContext } from './game-host.d.ts'; + +/* ────────────────────────────────────────────────────────────────────────── + * gameDefinition 声明式领域模型(source-project.schema.json#/properties/gameDefinition 的运行时消费视图) + * ────────────────────────────────────────────────────────────────────────── */ + +/** 归一化颜色:'#rgb'/'#rrggbb' 或 {r,g,b,a}(0..1)。 */ +export type Color = string | { r: number; g: number; b: number; a?: number }; + +/** 渲染组件:声明式出图(behaviors 只逻辑不画,渲染器据此画)。 */ +export interface RenderComponent { + id?: string; + kind: 'render'; + /** rect(缺省,以 transform 为中心)/ circle / fill(铺满 390×844 视口作背景)。 */ + shape?: 'rect' | 'circle' | 'fill'; + color?: Color; + w?: number; h?: number; // rect + r?: number; // circle +} + +/** 物理组件(opt-in):挂此组件的实体每帧 x+=vx*dt; y+=vy*dt(有 gravity 则先 vy+=gravity*dt)。 */ +export interface PhysicsComponent { + id?: string; + kind: 'physics'; + gravity?: number; +} + +/** + * 点击组件(plan U3 离散点击声明式基元):运行时内置——本帧点中带此组件且 occupied!==true 的实体 + * → 自动翻 occupied=true + spawn mark 标记实体(可见变化) + 加 score + fx(粒子/音效)。 + * 离散点击类(井字棋/打地鼠/翻牌)声明它即可,免写易错 tap-handler。配 tags:["target"] 让九门 driver 逐个点。 + */ +export interface ClickableComponent { + id?: string; + kind: 'clickable'; + /** 命中加分(缺省 1)。 */ + score?: number; + /** 命中时 spawn 的标记实体的 render 形态(缺省黄色小圆)。 */ + mark?: { shape?: 'rect' | 'circle'; color?: Color; r?: number; w?: number; h?: number }; + /** 命中区半尺寸来源(缺省取 render 尺寸 / 80)。 */ + hitW?: number; hitH?: number; +} + +/** 碰撞/自定义组件:声明式标记,由 behavior 自行 rt.overlap 判定 / 读取。 */ +export interface MarkerComponent { + id?: string; + kind: 'collision' | 'custom'; + [k: string]: unknown; +} + +export type Component = RenderComponent | PhysicsComponent | ClickableComponent | MarkerComponent; + +/** 实体声明(schema entity):transform.position → 运行时 x/y;可带 vx/vy/tags + 任意数值字段(idx/occupied 等)。 */ +export interface EntityDef { + id: string; + transform: { position: { x: number; y: number; z?: number }; rotation?: number; scale?: number }; + /** 组件引用(components[].id 字符串)或内联组件对象(spawn 用)。 */ + components?: Array; + vx?: number; vy?: number; + tags?: string[]; + [k: string]: unknown; // 运行时可用的自定义数值/布尔字段(idx/occupied/…) +} + +/** 行为模块:code 是一段 JS 逻辑串,运行期编译为 function(rt,self,dt)。init 跑一次,其余每帧。 */ +export interface BehaviorDef { + id: string; + trigger: 'init' | 'update' | 'input' | 'collision' | 'timer'; + /** 逻辑代码(规范字段 code;js 为兼容别名)。受校验边界静态扫描(禁 Math.random/Date/process/while(true)…)。 */ + code?: string; + js?: string; +} + +/** 规则:condition 是无副作用 JS 布尔表达式(rt/self 在作用域),为真按 outcome。 */ +export interface RuleDef { + id: string; + condition: string; + outcome: 'win' | 'lose' | 'score' | 'advance'; +} + +/** 场景:scenes[0].entityRefs 决定初始实例化哪些实体(缺省全量)。 */ +export interface SceneDef { + id: string; + entityRefs: string[]; +} + +export interface GameDefinition { + entities: EntityDef[]; + components?: Component[]; + behaviors?: BehaviorDef[]; + scenes?: SceneDef[]; + rules?: RuleDef[]; +} + +/* ────────────────────────────────────────────────────────────────────────── + * rt —— behavior 侧 API(注入 new Function('rt','self','dt',code) 的那个 rt) + * 受控面铁律:时间/随机走 boot.ctx 受控种子(确定性,禁 Math.random/Date.now);引擎能力经 ctx.getEngine()(满 F 门)。 + * ────────────────────────────────────────────────────────────────────────── */ + +/** 运行时实体实例(rt.getEntity/entities/query/spawn 返回)。 */ +export interface Entity { + id: string; + x: number; y: number; vx: number; vy: number; + alive: boolean; + tags: Set; + /** 已解析的组件对象数组。 */ + components: Component[]; + get(k: string): unknown; + set(k: string, v: unknown): unknown; + destroy(): void; + [k: string]: unknown; // behaviors 可直接读写自定义属性(e.hp=3、e.occupied 等) +} + +/** 受控输入轮询面(包 ctx.getInput() 受控事件为 behaviors 友好的轮询)。 */ +export interface RtInput { + isDown(key: string): boolean; + justPressed(key: string): boolean; + justTapped(): boolean; + /** 当前指针(副本,写它不腐蚀内部态)。 */ + readonly pointer: { x: number; y: number; down: boolean }; +} + +/** 受控时间面(now=相对游戏时间秒,从 0;不暴露墙钟 nowMs,保确定性)。 */ +export interface RtTime { + now(): number; +} + +export interface RtFx { + /** 经 ctx.getEngine().particles 真喷粒子(满 F 门;无引擎优雅 no-op)。 */ + burst(x: number, y: number, color?: Color): void; + /** 经 ctx.getEngine().audio.synth 真合成音效(kind ∈ score/hit/lose/win/default)。 */ + beep(kind?: string): void; +} + +/** behavior/rule 注入的运行时访问面(全部能力的唯一入口;其纯 API 面被 Object.freeze 防改写)。 */ +export interface Rt { + // 实体 + getEntity(id: string): Entity | null; + entities(): Entity[]; + /** 按 tag 或组件 id/kind 查询活实体(gameplay 主用 tag)。 */ + query(name: string): Entity[]; + spawn(spec: Partial & { x?: number; y?: number; vx?: number; vy?: number; tags?: string[]; components?: Array }): Entity; + destroy(e: Entity): void; + // 输入 / 时间 / 随机(确定性) + input: RtInput; + time: RtTime; + readonly dt: number; + random(): number; + randRange(a: number, b: number): number; + randInt(a: number, b: number): number; + // 分数胜负(win/lose 置不可逆 latch 终态) + readonly score: number; + addScore(n?: number): number; + setScore(n: number): number; + win(): void; + lose(): void; + // 工具 / 特效 / 视口 + clamp(v: number, lo: number, hi: number): number; + dist(ax: number, ay: number, bx: number, by: number): number; + /** AABB 重叠({x,y,w?,h?},缺省全尺寸 16;显式 0 被尊重)。 */ + overlap(a: { x: number; y: number; w?: number; h?: number }, b: { x: number; y: number; w?: number; h?: number }): boolean; + fx: RtFx; + view: { w: number; h: number }; +} + +/* ────────────────────────────────────────────────────────────────────────── + * 取证快照(_forensicsView().state();九门据此判进展 + 派生 driver 命名路径) + * ────────────────────────────────────────────────────────────────────────── */ + +/** state() 快照:固定取证键 + 逐实体按 id 投影命名位(ball.x/paddle.x…)+ tag='target' → targets[]。 */ +export interface ForensicsState { + phase: 'booting' | 'playing' | 'gameover'; + result: 'win' | 'lose' | null; + score: number; + elapsed: number; + remaining: number; + progress: number | null; + errors: string[]; + entities: Array<{ id: string; x: number; y: number; tags: string[] }>; + /** tap-targets driver 读:tag='target' 实体派生。 */ + targets?: Array<{ x: number; y: number; idx: number; occupied: boolean; safe: boolean }>; + /** 逐实体 id 投影位(如 ball:{x,y,vx,vy,w?,h?,r?,angle?}),供 gatespec 命名路径解析。 */ + [entityId: string]: unknown; +} + +/* ────────────────────────────────────────────────────────────────────────── + * createRuntime —— 建可变世界 + 产 rt(U2 装配器产出的工厂 init 调它;GameInstance 五法委托其 init/update/render/state/destroy) + * ────────────────────────────────────────────────────────────────────────── */ + +export interface Runtime { + rt: Rt; + init(): void; + update(dt: number): void; + render(g: CanvasRenderingContext2D): void; + state(): ForensicsState; + destroy(): void; + errors(): string[]; +} + +/** + * 建运行时:实例化 entities、编译 behaviors(new Function)/rules、内置 clickable 点击派发 + 声明式渲染器,产 rt。 + * @param boot 宿主注入的受控启动上下文(含 ctx:PluginContext 受控面)。 + * @param gameDefinition 声明式领域模型。 + */ +export declare function createRuntime(boot: GameHostBootContext | { ctx: PluginContext; seed?: number; mainContext?: CanvasRenderingContext2D | null; canvas?: HTMLCanvasElement | null }, gameDefinition: GameDefinition): Runtime; +export default createRuntime;