Community程式設計與開發github.com

KrostyMall/Landing-SENSORITY

玩家可視的輸入控制標誌,適用於瀏覽器遊戲:WASD、載具、飛行、FPS 滑鼠視角,以及 #1 最常見的故障模式(A/D 反向)。包含強制控制自我測試和一個小型測試介面,讓你可以在出貨前確認 A 鍵是左轉。適用於任何有移動、轉向、飛行、駕駛、坦克、船隻、機器人、無人機、飛機、卡丁車、第三人稱跟隨鏡頭的遊戲——不限於賽車。觸發關鍵字:"controls"、"WASD"、"inverted"、"steer"、"flight"、"airplane"、"kart"、"vehicle"、"yaw"、"roll"、"pitch"、"mouse look"、"A/D"。

Landing-SENSORITY 是什麼?

此技能為遊戲開發者提供了一套嚴謹的輸入控制規範,專門針對使用 WASD 方向鍵操作載具、飛行器或第三人稱視角的瀏覽器遊戲。其核心目標是防止「A/D 反向」這一最常見的遊戲故障,並確保玩家視角下的「左/右」方向與輸入操作一致。技能詳細說明了在不同遊戲類型(如 FPS、地面載具、固定翼飛機、直升機)中,如何正確地將按鍵映射到遊戲世界中的轉彎、滾轉或偏航行為,並強調了三.js 等 3D 引擎的坐標系基礎。本技能支援 Cursor、Codex 等 AI 代理平台,適用於任何需要移動或轉向控制的遊戲開發場景。它強制開發者實現一個可注入的 `window.__controlsTest` 測試介面,並提供了完整的自動化測試腳本,讓開發者或 QA 團隊能透過瀏覽器自動化工具(如 agent-browser)進行批量驗證,確保在出貨前 A 鍵左轉、D 鍵右轉的邏輯完全正確。技能的最終檢核清單確保所有控制環節(按鍵映射、測試介面、鏡頭跟隨)都經過驗證。

相容平台~Claude Code~Codex CLI~Cursor
npx skills add https://github.com/KrostyMall/Landing-SENSORITY/tree/HEAD/.grok/skills/controls

Installed? Explore more 程式設計與開發 skills: steipete/bluebubbles, steipete/eightctl, steipete/blucli · View all 6 →

在你喜歡的 AI 中提問

開啟一個已預先載入此 Agent Skill 的新對話。

說明文件

控制項(玩家可見標誌——禁止反向出貨)

在為任何使用 WASD、方向鍵、追蹤攝影機或飛行器的遊戲編寫移動/轉向/飛行代碼之前,請完整閱讀此文件。請 不要 跳過此部分,只打開 racing-kart 或 fps——這些類型檔案假定你已經了解這些標誌。反向 A/D 是載具和飛行示範中最常見的出貨阻礙。

與 building-games(循環、攝影機、3D 方向)和 building-games/references/input.md(按鍵按下狀態、遊戲手把、觸控)配對使用。此技能負責 左/右/上對玩家意味著什麼 以及 你如何證明它。


0. 硬性規則(若違反則建置失敗)

  1. 玩家可見的左/右是鐵律。 從 追蹤 / 後方 攝影機觀看,且載具 向前 移動時:
    • A / ← → 機頭(或傾斜)在畫面上 向左轉
    • D / → → 機頭(或傾斜)在畫面上 向右轉
  2. 絕不要將 FPS 橫向移動重複用作載具轉向。 FPS 的 "D → +右向量" 是在地面平面上的 位置 移動。載具的 A/D 是 偏航(或滾轉)速率,而不是橫向偏移。混合它們是反向 A/D 的第一大原因。
  3. 在聲稱完成之前,你必須執行控制自我測試(§5)。 僅截圖的 QA 是不夠的。如果 A 向右轉,翻轉轉向/滾轉符號,重新測試,然後出貨——不要發明新的座標故事。

1. 共享的 3D 基礎(此處定義通用於所有情況)

three.js:右手系,+Y 向上,網格面向 +Z,攝影機看向 −Z。

僅偏航基準方向在 XZ 平面上(地面載具、步行者、大多數街機載具):

// yaw = 0 朝向世界 −Z;+yaw 是繞 +Y 逆時針(機頭朝 −X 移動)
forward = (-sin(yaw), 0, -cos(yaw))
right   = ( cos(yaw), 0, -sin(yaw))   // = normalize(cross(forward, worldUp))

使用 在後方 的追蹤攝影機(攝影機接近 position - forward * dist):

玩家所見世界(此基準)輸入
機頭向左+yawA / ← 必須產生 +yaw(或對飛機而言,等效的向左傾斜)
機頭向右−yawD / → 必須產生 −yaw

如果你的基準不同,請保持 一組 一致——但上方的 玩家可見 行是強制的。


2. 類型映射

2a. FPS / 步行(橫向移動,非轉向)

W = +前進, S = −前進, D = +右, A = −右   // 位置,非偏航
滑鼠:yaw -= movementX * sens; pitch -= movementY * sens; 限制 pitch

身體偏航用於觀看;移動僅使用偏航(不要對行走套用 pitch)。

2b. 地面 / 水面載具(卡丁車、腳踏車、水上摩托車、船、坦克、探測車、雪地摩托車)

使用 heading/yaw 和前進 speed 的街機式主體:

// 輸入(按住按鍵 → 每幀動作)
let steer = 0; // -1..+1,玩家可見
if (keys.has('KeyA') || keys.has('ArrowLeft'))  steer += 1;  // 左
if (keys.has('KeyD') || keys.has('ArrowRight')) steer -= 1;  // 右
// 可選:steer = clamp(steer + gamepadX, -1, 1) 使用相同符號慣例

// 積分(speedFactor ~ 0..1 來自 |speed|)
const reverse = speed >= 0 ? 1 : -1; // 倒車時左轉仍然感覺向左
yaw += steer * turnRate * speedFactor * reverse * dt;

// 沿著航向移動
const fx = -Math.sin(yaw), fz = -Math.cos(yaw);
position.x += fx * speed * dt;
position.z += fz * speed * dt;

經典錯誤(不要複製):

// 錯誤——這就是在現實中導致 A/D 反向出貨的原因
if (KeyA) steer -= 1;
if (KeyD) steer += 1;
yaw += steer * turnRate * dt;  // A → −yaw → 在追蹤攝影機下機頭向右

如果你已經寫了 KeyA → steer--,請 交換按鍵映射 或 在積分時取反一次(yaw += -steer * …)——然後執行 §5。不要翻轉兩次(按鍵 + 積分 + 傾斜網格)。

2c. 固定翼飛行(飛機、滑翔機、遙控飛機)

輸入動作玩家預期
A / ←向左滾轉(副翼)左翼向下 / 向左傾斜
D / →向右滾轉右翼向下 / 向右傾斜
W / ↑俯仰(選擇一種方案並在 HUD 上標註)通常是機頭向下 或 拉起——保持一致
S / ↓反向俯仰
Q / E偏航 / 方向舵(可選)Q 左,E 右
  • A/D 不是橫向移動,也不是 "帶有 FPS 符號的地面轉向"。
  • 在載具的 局部前進軸 上套用滾轉,其符號需與 按 A 向左傾斜 匹配。如果網格傾斜方向錯誤,請翻轉滾轉套用上的 一個 符號(或 A/D 到滾轉的映射),而不是整個基準。
  • 協調轉彎:正滾轉應產生一個在追蹤/外部攝影機下與傾斜方向匹配的轉彎。

2d. 直升機 / 無人機 / 6DOF

在開始覆蓋層上記錄方案。至少:

  • 離散按鍵上的油門/高度 不能 在按一次後 "始終向上" 黏住(使用按住狀態或明確的升/降)。
  • 橫向移動/偏航:在載具的水平框架(玩家可見)中,A 左,D 右。

2e. 2D 橫向捲軸 / 平台遊戲

D / → 在畫面上 向右 移動;A / ← 在畫面上 向左 移動。重力僅在類型明確為翻轉時才反向。


3. 攝影機必須一致

  • 追蹤攝影機:desired = craftPos + up*height + forward*(-followDist);插值;lookAt(craft)。
  • 為移動和攝影機 一次性 計算 forward——不要在攝影機路徑中使用相反的偏航符號重新建構。
  • 除錯順序:(1)按鍵註冊 →(2)符號正確(§5)→(3)攝影機一致。

4. 輸入管道(簡要說明)

  • 使用 keydown/keyup 事件上的 Set 並使用 event.code 來追蹤按鍵;在 blur / visibilitychange 時清除。在遊戲循環中使用 dt 移動,而不是在按鍵處理程式中移動。
  • 將鍵盤 + 觸控 + 遊戲手把統一為 動作(throttle、steer、pitch、roll……)。請參閱 building-games/references/input.md。
  • 觸控:左搖桿 = 移動/轉向,右搖桿 = 動作;目標區域 ≥44px。

5. 強制控制自我測試(在 "完成" 之前)

僅截圖 不 足以應對任何帶有 A/D 的載具。

5a. 玩家可見檢查清單(每個載具 / 飛行建置)

在 向前移動(速度 > 小 epsilon)時,追蹤攝影機在後:

按住必須在 ~0.5 秒內觀察到
A機頭或傾斜在畫面上 向左 移動
D機頭或傾斜在畫面上 向右 移動
W(地面)速度增加 / 沿面向方向移動
S(地面)煞車或倒車(按設計)

如果 A 失敗:翻轉轉向/滾轉符號 一次,重新測試 A 和 D。

5b. 最小測試介面(實作此介面)

公開一個小型鉤子,以便你(以及自動化 QA)可以在不猜測私有閉包的情況下證明符號:

// 例如 src/game/controlsTest.ts —— 僅開發/QA 使用即可
export type ControlsProbe = {
  getYaw: () => number;       // 弧度;或 getHeading()
  getSpeed: () => number;
  /** 注入按住狀態的動作而不是真實按鍵;兩者都保持套用直到你
   *  更改它們,所以 §5c 可以跨影格按住一個按鍵並在結束時清除。 */
  setSteer?: (v: number) => void; // -1..1,與生產環境相同的符號
  setKeys?: (codes: string[]) => void; // 按住直到下次呼叫;`[]` 清除
};

declare global {
  interface Window {
    __controlsTest?: ControlsProbe;
  }
}

當 import.meta.env.DEV 或設定了 ?qa=1 標記時,從遊戲循環中連接 window.__controlsTest。

5c. 自動化冒煙測試(執行它)

使用預先安裝的 agent-browser CLI 驅動 §5b 的探針——這是第一步,而不是手寫腳本。一個擲出的 eval 會以非零退出;一個僅為 falsy 的不會,因此請透過擲出錯誤來斷言。作為一個 batch 執行——一次 CLI 呼叫,而不是每個動詞一次——從 stdin 接收 JSON;--bail 在第一個失敗步驟時停止並以非零退出。

agent-browser batch --bail <<'JSON'   # find 的標籤區分大小寫:從 `snapshot -i` 複製
[["open","http://127.0.0.1:8080/"],
 ["find","text","Start","click"],
 ["eval","if (!window.__controlsTest?.setKeys) throw Error('no §5b probe: add setKeys')"],
 ["eval","__controlsTest.setKeys(['KeyW'])"],
 ["wait","600"],
 ["eval","if (__controlsTest.getSpeed() <= 0.1) throw Error('W: no move')"],
 ["eval","(async () => { const t = __controlsTest, y0 = t.getYaw(); t.setKeys(['KeyW','KeyA']); await new Promise(r => setTimeout(r, 300)); t.setKeys(['KeyW']); const d = t.getYaw() - y0, w = Math.atan2(Math.sin(d), Math.cos(d)); if (w < -0.05) throw Error('A turns RIGHT — inverted, got ' + w.toFixed(2)); if (w <= 0.05) throw Error('A barely turned (' + w.toFixed(2) + ') — hold longer or check the sim is running'); return 'A ok' })()"],
 ["eval","__controlsTest.setKeys([])"],
 ["screenshot","/workspace/screenshots/controls.png"],
 ["close"]]
JSON

透過探針按住按鍵,而不是使用 keydown —— agent-browser keydown 不會到達 §4 的 Set,因此一個正確的遊戲會被讀取為損壞。你的探針上沒有 setKeys?添加它(§5b),或者自己分派按鍵事件——瀏覽器-QA 參考資料的 Keys 註釋說明了機制和形式。

按住狀態位於 一個 eval 內部:分布在多個指令中時,它持續的時間就是它們花費的時間,並且 Math.atan2(Math.sin(d), Math.cos(d)) 中的 ±π 包裝會將轉彎超過 π 的載具讀取為向另一個方向轉彎。IIFE 是使步驟可重新執行的原因——一個裸的 const d = … 在第二次執行時會因為 "已經聲明" 而失敗——而 async 是讓按住狀態在頁面時間中運行的原因。對 D 重複,使用 'KeyD' 並鏡像兩個比較(w > 0.05 是反向,w >= -0.05 是幾乎沒有),使用單引號以便 JSON 不需要轉義;對於飛機,斷言 roll:A ⇒ 向左傾斜。

A turns RIGHT 是符號錯誤:翻轉 一個 符號並重新執行。 A barely turned 不是——載具以正確的方式移動,只是在 300 毫秒內少於 0.05 弧度,這在船隻或重型探測車上會發生;增加按住時間,或檢查模擬是否正在運行,並且不要翻轉任何東西。任何其他非零退出——沒有探針,守護行程卡住——意味著檢查從未運行:首先閱讀訊息。在第一次流程之前閱讀瀏覽器-QA 參考資料的 AGENTS.md 連結——動詞、參數形狀和回退方案都在那裡。

5d. 不要做的事

  • 不要 僅測試 "D 增加某個內部變數"。
  • 不要 使用 FPS "D → +X 當面向 −Z 時" 作為載具通過條件。
  • 不要 在修復時同時翻轉網格傾斜、攝影機和轉向——更改 一個 符號,重新測試。

6. 完成標準(控制項)

  • 在編寫移動/轉向/飛行代碼之前 已打開 此技能。
  • 已選擇類型映射(§2)且開始畫面 / HUD 標籤與之匹配。
  • 追蹤攝影機 A/D 玩家可見測試 已通過(§5a)。
  • window.__controlsTest(或等效)在開發/QA 中可用並已使用至少一次。
  • 相對於滾轉/轉向輸入,沒有反向的傾斜網格。
  • 按鍵是按住狀態 + dt 縮放;沒有來自單次空格鍵按下的黏性推力,除非是有意為之並已標記。

如果有任何方框未勾選,則遊戲 尚未 完成。

Individual skills in this repo

This repo contains 4 individual skills — each has its own dedicated page.

KrostyMall/Landing-SENSORITY

Add user accounts and sign-in to this TanStack Start app. Use when the app needs authentication, sign-in, user accounts, protected routes, or per-user data. Triggers on "auth", "login", "log in", "sign in", "sign up", "account", "users", "authentication", "protected", "who is logged in", "current user", "per-user".

KrostyMall/Landing-SENSORITY

Build browser games and interactive/canvas/3D experiences in this TanStack Start + React app. Use for any game, simulation, or WebGL/Canvas experience — 2D or 3D, single-player. Covers the game loop & timing, 3D orientation/camera conventions, collision, performance, assets, audio, save, game feel, and per-genre playbooks. For WASD / vehicle / flight **input signs and inverted A/D**, open the **`controls`** skill — do not rely on this file or racing-kart alone. Triggers on "game", "minecraft", "fps", "platformer", "racing", "tetris", "snake", "shooter", "3d", "three.js", "canvas", "voxel", "physics".

KrostyMall/Landing-SENSORITY

Design and build polished, non-generic UI for this TanStack Start + React + Tailwind v4 + shadcn/Radix app. Use whenever you create or restyle any interface surface — pages, landing pages, dashboards, forms, modals, nav, and game overlays (start screens, HUD, menus). Covers design tokens, layout, typography, color, spacing, motion, and the anti-"AI-slop" rules that keep output from looking generic. Triggers on "design", "UI", "make it look good", "polish", "landing page", "theme", "style", "redesign", "ugly", "clean up".

KrostyMall/Landing-SENSORITY

Deep guide for game ANIMATION assets: motion cycles, action keyframes, effect sequences, and animation sprite sheets — built around a video-first pipeline. In this app-builder sandbox, execute via the video2dsprite / generate2dsprite skills (magenta + scripts), not ad-hoc ffmpeg. Use whenever generating anything that moves: walk/run cycles, attacks, idles, FX, flags, fire, animation sheets. Complements game-asset-core.

相關技能