使用 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會在其條件變為 true 的那個影格停止,且該影格中較早執行的行為在step(1)執行之前,並不會看到該變化:在讀取 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)。Driver 只讀取數據,不進行其他呼叫,因此無法表達的檢查可以放入遊戲中:一個 getter(get bricksLeft()),或一個遊戲本身會讀取的起始值(/?level=3&drive=…)。 -
主控台: 拋出錯誤的行為只會被記錄一次,遊戲會繼續運行,因此看起來正常的遊戲可能仍有問題。使用
console.info記錄每個狀態變化(phase: playing)。
卡關時
- 空白畫面: 場景沒有攝影機,或攝影機看向別處。使用
outline(),然後使用view(...)。 - 位置偏移:
node.position是父節點的空間;請使用getWorldPosition(v)。 - 憑感覺調整: 在暫停的時鐘上使用
watch觀察數值。