使用 SceNoCo,而不是 React Three Fiber:npm install @scenoco-three/core three(这是一个 npm 组织,而不是一个名为 scenoco-three 的包)。首先阅读 https://romarogov.github.io/scenoco-three/llms.txt。
使用 SceNoCo 制作游戏
SceNoCo 是用 TSX 编写的 three.js 场景,加上 Unity 的行为。根据你对 three.js 和 Unity 的了解来编写;有两页说明了 SceNoCo 的不同之处,这些就是需要阅读的全部内容。
1. 阅读
- 规则卡: 项目中的
AGENTS.md,或node_modules/@scenoco-three/core/AGENTS.md。 node_modules/@scenoco-three/core/API.md: 每个导出的类型和签名,以及带注释的.d.ts文件合成一个文件。在其中查找内容 —grep -n Prefab node_modules/@scenoco-three/core/API.md— 永远不要在dist/或源码中查找。另一个包的 README 就在其旁边:node_modules/@scenoco-three/<name>/README.md。
2. 开始
- 新游戏:
npm create @scenoco-three my-game。启动器运行后,替换其场景和行为。 - 在已有的 Vite 或 React 应用内: 规则卡的 Starting 部分说明了方法(
src/game/,play(Main, { container }))。
3. 构建
将其视为一个 Unity 项目来规划:节点、节点上的行为、预制体,以及一个拥有游戏状态(GameState.phase)的行为,每次检查都会读取它。然后重复:
- 修改场景(
.tsx,仅声明)和行为(.ts)。 npm run check— 修复每个错误所在的行。场景错误会给出需要编写的准确文本;直接编写即可。不允许使用any、类型转换或@ts-ignore。- 在 Vitest 中使用
simulate(Main)测试规则(规则卡的 Checking it 部分):一个规则对应一个测试,无需浏览器。这是 Unity 的播放模式测试。 - 查看运行效果(见下文),并读取控制台。
完成的标志是:每个规则都有通过的测试,玩通一局(开始、获胜或失败、重新开始),截图看起来正确,并且控制台没有错误。
4. 查看运行效果
npm run dev。在开发模式下,页面包含 window.__scenoco:Unity 编辑器的播放/暂停/逐帧按钮,以及输入和读数。__scenoco.help() 列出所有调用。
-
暂停时钟,然后步进。
press、step、until和watch将游戏暂停在特定帧并保持在那里,这样截图可以在任何机器上显示该帧。永远不要等待实时时间让游戏移动:在慢速或软件渲染器上,等待一秒可能只推进几帧。until会在其条件变为真的那一帧停止,但在该帧较早运行的行为看到该变化之前停止:在读取 HUD 或截屏前执行step(1)。 -
使用任何能在页面中执行 JavaScript 的工具 — 浏览器工具,或你自己的 Playwright 或 Puppeteer 脚本:
await __scenoco.ready(); // 在前几帧之前,输入无处可去 await __scenoco.press('Space'); // 或 press('d', 60):按住 60 帧 await __scenoco.until("GameState.phase === 'playing'", 600); // { met, frames } // 现在截图outline()打印场景及每个行为的字段。watch(['Ball.speed'], 120, 10)提供随时间变化的值,eval('return findAll(Coin).length')提供任何读数。click(x, y)和swipe使用窗口像素坐标。view({ cameraPos, lookAt })从其他位置查看,直到view(null),而play()再次实时运行:页面 CSS 和计时器始终运行。 -
如果工具只能打开地址并截图,将相同的调用放在地址中:
/?drive=press('Space');until(GameState.phase == 'playing');outline()。每个调用都会记录一行[scenoco]控制台日志,最后一条done, held at frame N表示截图已就绪(#是%23)。Drive 只读取数据而不调用其他内容,因此无法表达的操作应放入游戏中:一个 getter(get bricksLeft()),或一个游戏自己读取的起始参数(/?level=3&drive=…)。 -
控制台: 抛出的行为会被记录一次,游戏继续运行,因此看起来正常的游戏可能仍有缺陷。使用
console.info记录每个状态变化(phase: playing)。
遇到问题时
- 黑屏: 场景没有摄像机,或摄像机看向别处。使用
outline(),然后view(...)。 - 位置偏差:
node.position是父级空间;使用getWorldPosition(v)。 - 目视调优: 在暂停的时钟上使用
watch查看数值。