從套件建立手機網頁遊戲
web-game 範本是一個已完成的遊戲(Coin Dash),使用 Vite + React + TypeScript。你的工作是替換它的規則、畫面、文字和美術,成為使用者的遊戲。行動裝置優先:390 x 844 的直立手機,單手操作。桌機也必須能運作。
固定規則
- 在任何動作之前,先啟動即時預覽(建構順序步驟 1)。然後再寫程式碼:先用最多 10 行規劃,然後編輯。每次只編輯一個檔案或一個功能,接著執行
bun run typecheck。 - 絕不重建套件已有的功能(見下方列表)。不要加入遊戲引擎、UI 函式庫或 @react-three/fiber。
- 遊戲規則是
src/games/<game>/logic.ts中的純函數:不能使用 React、DOM、繪圖、Date.now()或Math.random()。請使用seeded(seed)。同一個種子必須產生相同的遊戲:每日與挑戰回合依賴於此。 - 沒有伺服器,沒有登入。進度儲存在
localStorage(套件已處理)。 - 說明文字中的每一項敘述都必須與遊戲實際行為相符。
- 驗證代表已實際看到運作:通過
bun run check:play並檢查其在手機尺寸下的截圖。來自即時連結的 HTTP 200 不是測試。check:play是無頭模式,不需要桌面或瀏覽器視窗。
套件已具備的功能(請勿重建)
- 固定步進迴圈、鍵盤與觸控輸入(任意拖曳、搖桿、方向鍵、轉向、動作按鈕、多點觸控、雙人遊玩、電腦上滑鼠拖曳)、攝影機、碰撞偵測、分頁隱藏時暫停。
- 在
src/ui/中統一的 2D 與 3D 遊戲 UI:選單、HUD 條(分數徽章、愛心、計時器、暫停)、暫停、結果、解鎖、「如何遊玩」與 FAQ、「請旋轉手機」提示、快訊、路由、儲存的個人資料。 - 在
src/ui/theme.ts中的主題:softCandy(預設)、glassNeon、cleanMinimal。使用?theme=glassNeon可預覽其他主題。 - 最佳分數與解鎖功能;每日挑戰(日期種子、從發布日起算的天數、連續天數);挑戰連結
?c=<seed>&s=<score>&n=<name>,包含清理過的參數以及「你贏了 / 你輸了」和「回敬一局」;使用navigator.share或複製到剪貼簿分享;Web Audio 音效,在首次點擊後啟用並可記住靜音狀態;震動功能,失敗時無聲忽略。 track(name, data)搭配game_open、game_start、game_over、play_engaged(45 秒)、share、challenge_open、daily_complete。它會在控制台記錄,並在已發布的頁面上傳送至 omg 分析。play.tsx中的useRun會自動發送這些事件;請勿重複發送。- 100dvh、安全區域、無捲動或縮放、觸控目標 48 像素、減少動畫效果。
- 根據
src/app/about.ts建立的 SEO:標題、描述、Open Graph、分享圖片、VideoGame 與 FAQPage 資料。安裝清單來自 omg Vite 插件,使用public/icons/。
選擇 2D 或 3D
預設為 2D(壓縮後約 100 KB 的腳本)。僅在遊戲概念需要深度時才使用 3D;3D 會新增 three.js(壓縮後約 137 KB),並在選單顯示時載入,且絕不會在 2D 建構中載入。在 src/app/view.ts 中用一行切換,然後刪除未使用的視圖檔案。
選擇控制方式
在 src/app/about.ts 中設定一次,包含 GAME.controls:kind、touchHint(手機選單用)和 keysHint(電腦選單用)。play.tsx 會將 GAME.controls.kind 傳遞給 <TouchControls>。這兩個提示與 howToPlay 必須描述相同的控制方式。絕不要在有按鈕的遊戲中寫「拖曳」,或在拖曳遊戲中寫「點擊箭頭」。check:ui 和 check:play 會對指向錯誤控制方式的提示回報失敗。
| 遊戲類型 | kind | 玩家動作 | 規則讀取 |
|---|---|---|---|
| 打磚塊、接物、跑酷、閃避、彈弓 | drag | 在畫面任意處拖曳 | axisX/axisY;若 mode="absolute" 則為 dragTarget,讓球拍位於手指下方 |
| 俯視、自由移動、雙搖桿 | stick | 用拇指操作左下角搖桿 | axisX/axisY |
| 網格移動:迷宮、貪食蛇、倉庫番 | dpad | 點擊四個方向箭頭 | axisX/axisY 或 wasTapped |
| 賽車、雙鍵切換車道 | steer | 按住左或右 | axisX |
| 單點擊:飛鳥、跳躍、節奏 | buttons | 點擊動作按鈕 | wasTapped(input, "p1", "a") |
可在任何 kind 上使用 buttons={[...]} 加入動作按鈕。axes="x" 會將拖曳限制為左右方向。鍵盤隨時可運作:方向鍵或 WASD、空白鍵。
建構順序
- 先啟動預覽,再編輯任何檔案: 在專案目錄中,如果缺少
node_modules,執行bun install。在背景啟動bun run dev(連接埠 5174)。呼叫omg_expose_port,連接埠為 5174,不要使用expoGo。告訴使用者:「預覽已準備好,請見下方卡片。後續每次存檔都會更新。」從此刻起,Vite 會在每次存檔時重新載入預覽。如果首次執行步驟已做過這些,或連接埠 5174 已被此專案的開發伺服器佔用,則直接跳到步驟 2。 - 規劃: 用一句話描述核心迴圈、控制方式(見上表)、勝利、失敗、分數,以及回合如何結束(計時、生命數或掉落的物品)。將這些寫入
README.md。 - 規則: 將
coin-dash/logic.ts複製到src/games/<game>/logic.ts。保留createGame(players, seed)、stepGame(game, input, dt)、finalScore、events(用於音效)、UNLOCKS、shareLine。使用axisX/axisY/wasTapped讀取輸入。 - 視圖: 複製
view-2d.ts(Canvas:drawWorld、drawShadow、loadImage)或view-3d.ts(three.js:createStage、chaseCamera、billboard、checkerTexture;共享幾何、Lambert 材質、圓形陰影、無陰影貼圖)。當設定了美術插槽圖片時繪製該圖片,否則繪製佔位形狀。 - 連接: 在
src/app/play.tsx中修改匯入、HUD 數字、FEEDBACK(每個事件的音效)、按鈕以及run.finish({...})那一行。保留<TouchControls kind={GAME.controls.kind}>、<HudScore icon={ART.scoreIcon}>、run.step和run.finish。 - 文字: 填寫
src/app/about.ts(名稱、含搜尋關鍵字的標題、描述、標語、控制方式、上線日、畫面方向、3 到 5 個步驟的教學、提示、4 到 6 個 FAQ)。 - 美術(必要): 套件附帶 Coin Dash 的範例美術,且這些美術不得出現在使用者的遊戲中。在
theme.ts中選擇預設主題,或展開一個主題並設定客戶的顏色。使用omg_generate_image以統一風格生成圖片(一張 sheet,切割為透明 PNG,遊戲總大小低於 3 MB),並替換所有項目:- 在
src/app/art.ts中的ART.hero(選單中 logo 下方的美術)和ART.scoreIcon(HUD 分數圖示)。刪除public/art/hero.svg和public/art/score.svg。 ART.items(每個解鎖項目一個)和ART.sprites。public/icons/(pwa-192x192.png、pwa-512x512.png、pwa-512x512-maskable.png、apple-touch-icon.png尺寸 180)和public/og.png(1200 x 630)。 接著檢查選單、遊玩和結果的截圖:不應出現紅色跑者、金幣或金幣徽章,除非遊戲主題就是金幣。
- 在
- 檢查: 依序執行
bun run typecheck、bun test、bun run check:ui,然後bun run check:play。check:play會在 390 x 844 的環境下使用觸控進行一回合:選單、遊玩、你的控制方式、暫停、繼續、結果、主控台錯誤、範例美術。檢查.omg/ui-check/和.omg/play-check/中的每個 PNG。修正每個 FAIL 和 WARN,然後再次執行它們。在check:play通過之前不要發布。 - 發布: 執行
omg_deploy。首次發布需要public/omg-store/1.png到3.png(390 x 844 下的選單、遊玩、結果)。等待一分鐘,然後執行bun run check:play -- --url <即時連結>並檢查其截圖。僅回報成功通過的部分。
僅在套件錯誤阻礙開發時,才編輯 src/ui/、src/game/ 和 src/render/。在你的遊戲資料夾中加入輔助函式。
手機規則
- 保留 viewport 標籤、
styles.css、page.ts。將 HUD 項目放在<Hud>內部。重要的控制項保持在畫面下半部。 - 遊戲時間不使用
setInterval、setTimeout或Date.now():應使用dt計數。 - 不使用
alert、confirm、prompt、外部字型或腳本。 - 3D:最多數百個網格,重複使用幾何與材質,無後處理,無大型紋理。
- 在手機上,omg 安裝列會位於遊戲下方,遊戲則變成它上方的一張卡片。不要隱藏或移動它。
最終報告
- 即時連結。2. 用一句話描述遊戲。3. 測試了哪些項目以及尺寸,以及在即時連結上的
check:play結果。4. 選單、遊玩和結果的截圖。5. 已知問題或後續想法(最多 5 項)。說明是否已在真實手機上檢查過 3D。
已學到的教訓
- 如果一個按鈕位於可橫向捲動的列尾端,它可能會移出螢幕,導致玩家卡住。
check:ui會對這類按鈕回報失敗;請確保關鍵按鈕在 360 像素寬度內可見。 - 過去曾在部署後立即宣稱「已驗證」,而即時網站仍在服務舊的建構版本。請在短暫等待後重新檢查。
- 遊戲的副本與原始來源產生分歧。請從同一個資料夾建構;絕不要修補副本。
- Fruit Catcher(10 月 22 日)在兩個箭頭按鈕上方說「向左或向右拖曳來移動籃子」;但拖曳沒有效果。請設定好
GAME.controls並讓check:play驅動它。 - 同一款遊戲出貨時仍帶有套件的紅色跑者、金幣、分數徽章和金幣應用圖示。步驟 7 會全部替換;如果任何範例檔案存在,
check:play會回報失敗。 - 使用者因為連接埠從未暴露而等了 5 分鐘都沒看到預覽。步驟 1 必須在任何編輯之前完成。
- 代理曾寫「桌面瀏覽器未執行」並僅用 HTTP 檢查即時連結。
check:play是無頭模式;請在即時連結上執行它。 - 為了新自訂事件(
play_engaged)最佳化的廣告被放棄了。請先以標準目標開始投放廣告,待該事件每週觸發約 50 次後再切換。