Claude Media
Claude CodeでUnityのInput Systemを設定する — .inputactionsをJSONで管理

Claude CodeでUnityのInput Systemを設定する — .inputactionsをJSONで管理

.inputactionsはJSON形式のテキストなので、Claude Codeが読み書きできます。パス指定ルールとフックで壊れた編集を止め、Cinemachineの入力配線はEditorに残す分担を示します。

.inputactionsはJSONなのでClaude Codeが直接編集できる

Input Systemの.inputactionsファイル(Input Action Asset)は、プレーンなJSON形式で保存されます。Unityのマニュアルにそう書かれています。テキストなので、Claude Codeは他のソースコードと同じように読み、差分を出し、書き換えられます。

ただし書き換えを任せるなら、壊れた編集をその場で止める仕組みが要ります。キーボードのWASDを足すだけの変更でも、カンマ1つの欠落でEditorがアセットを読めなくなるためです。本記事は次の3点を、Unity 6系とInput System 1.11のマニュアルを前提に組み立てます。

  • .inputactionsを触るときだけ読み込まれるルールの置き方
  • 編集のたびにJSONの整合を検査するフック
  • Cinemachineの入力配線のうち、Claude Codeに任せない部分
分担

作業ごとの担当

  • Claude Codeに任せる

    アクションマップの追加、バインディングの追加・修正、命名の統一、生成されるC#クラスを使う側のスクリプト。

  • Unity Editorに残す

    新規アセットの作成、Generate C# Classの設定とReimport、CinemachineのInput Action参照の割り当て。

  • フックで機械に任せる

    JSONの構文、ID重複、存在しないアクション名への参照の検出。

Unity Editorを開かずに検証を回す一般的な方法はClaude CodeでUnityゲーム開発を進める手順で扱っています。Editorの操作そのものを自動化したい場合はUnity公式MCPサーバーの接続手順が別の選択肢です。

書かせる前に押さえるInput Systemの前提

Claude Codeに規約を書く前に、Input Systemがどこで入力を扱うかを確定させます。ここが食い違うと、きれいなJSONを書いても入力が届きません。

Unityは標準でレガシーのInput Manager(UnityEngine.Input)が有効で、新しいInput Systemは無効です。パッケージを入れると新バックエンドを有効にするか尋ねられ、設定はEdit > Project Settings > Player > Other Settings > Active Input Handlingにあります。変更後はEditorの再起動が必要です。新旧を同時に使うBothも選べます。

もう1つの前提がプロジェクトワイドアクションです。Edit > Project Settings > Input System Packageで1つのアクションアセットを割り当てると、コードからInputSystem.actions.FindAction("Move")のように参照でき、起動時に有効化されます。新規作成するとInputSystem_Actionsという名前のアセットができ、MoveやJumpなどの既定アクションが入っています。

マニュアルは、多くのプロジェクトでは1つのアクションアセットで足りるとしています。1つのアセットに複数のアクションマップを入れられるので、Claude Codeに渡す対象もこのファイル1つで済みます。

.claude/rulesでパスを絞ってルールを置く

.inputactionsの編集規約は、全セッションで読み込まれるCLAUDE.mdに書くより、パス指定ルールに置くほうが合います。CLAUDE.mdは1ファイル200行未満が目安で、長くなるほど遵守率が落ちると説明されています。ゲーム全体の規約にアクションマップの細則まで混ぜると、そこに届かなくなります。

.claude/rules/のMarkdownは、pathsフロントマターを付けると、Claudeが一致するファイルをRead・Write・Editしたときに初めて読み込まれます。

---
paths:
  - "Assets/**/*.inputactions"
---
# .inputactions編集ルール
 
- ファイルはJSON。コメントや末尾カンマを書かない
- 既存のid(GUID形式)を書き換えない。新規要素のidは新しい値にする
- アクション名はマップ内で一意にする。バインディングのactionは存在するアクション名を指す
- 編集後は検証フックの結果を読み、エラーが出たら直してから報告する
- Unity Editorで作り直せる設定(Generate C# Class、Control Schemeの追加)はJSONで済ませず依頼者に伝える

idを書き換えない理由はマニュアルの説明にあります。各アクションにはユニークなIDがあり、アクション名を変えてもIDは変わらず、IDで参照できるとされています。新しく作る要素のidを既存の値と重複させないことも同じ理由で大切です。

落とし穴

新規ファイルを作る依頼ではルールが読み込まれないことがある

パス指定ルールは、一致するファイルをClaudeが読んだときに読み込まれます。存在しないファイルをWriteで新規に作る場面での挙動は、Claude Codeのrulesが新規ファイルで読まれない問題で扱っています。新しいアクションアセットはEditorのAssets > Create > Input Actionsで作ってからClaude Codeに渡すと、ルールが読まれる状態で始められます。

編集のたびにJSONを検査するフック

規約は文章なので、守られない可能性が残ります。Claude Codeの公式ドキュメントも、CLAUDE.mdは強制される設定ではなく文脈として扱われると説明しています。必ず走らせたい検査はフックに移します。

PostToolUseは、ツール呼び出しが成功した後に発火します。ここで終了コード2を返すと、標準エラー出力がClaudeに渡されます。ツールはすでに実行済みなので、編集自体は取り消されず、Claudeが読んで直す流れになります。

検査スクリプトは次のとおりです。JSONの構文、ID重複、バインディングが指すアクション名の存在を調べます。

#!/usr/bin/env python3
"""Check .inputactions JSON: parse, unique ids, binding->action references."""
import json, sys, collections
 
def check(path):
    errors = []
    try:
        with open(path, encoding="utf-8") as f:
            data = json.load(f)
    except json.JSONDecodeError as e:
        return [f"{path}: JSON parse error line {e.lineno} col {e.colno}: {e.msg}"]
    ids = collections.Counter()
    for m in data.get("maps", []):
        ids[m.get("id")] += 1
        names = set()
        for a in m.get("actions", []):
            ids[a.get("id")] += 1
            names.add(a["name"])
        for b in m.get("bindings", []):
            ids[b.get("id")] += 1
            if b.get("action") not in names:
                errors.append(f"{path}: map '{m['name']}' binding '{b.get('path')}' "
                              f"refers to unknown action '{b.get('action')}'")
    for i, n in ids.items():
        if n > 1:
            errors.append(f"{path}: duplicate id {i} ({n} times)")
    return errors
 
if __name__ == "__main__":
    paths = sys.argv[1:]
    if not paths:  # hook mode: the hook JSON arrives on stdin
        path = json.load(sys.stdin).get("tool_input", {}).get("file_path", "")
        paths = [path] if path.endswith(".inputactions") else []
    errs = [e for p in paths for e in check(p)]
    for e in errs:
        print(e, file=sys.stderr)
    sys.exit(2 if errs else 0)

スクリプトはtools/check_inputactions.pyに置きます。.claude/settings.jsonには、Edit|Writeだけを対象にしたフックを登録します。

{
  "hooks": {
    "PostToolUse": [
      {
        "matcher": "Edit|Write",
        "hooks": [
          {
            "type": "command",
            "command": "python3 tools/check_inputactions.py"
          }
        ]
      }
    ]
  }
}

公式のPrettierの例はjqとパイプでxargsにつなぎます。この検査では、スクリプトが標準入力のフックJSONを直接読みます。xargsを挟むと、子プロセスの終了コード2がxargsの123に変わり、Claudeへ届く条件から外れるためです。

実際に走らせた結果

Python 3.12.2で、MoveとLookを持つアクションマップのサンプルに対して動かしました。バインディング1つのaction名をLoookと打ち間違えた状態では、次のように止まります(パスは省略)。

echo '{"tool_input":{"file_path":".../Assets/Player.inputactions"}}' \
  | python3 -I tools/check_inputactions.py; echo "exit=$?"
# .../Player.inputactions: map 'Gameplay' binding '<Mouse>/delta' refers to unknown action 'Loook'
# exit=2

"controlSchemes": []の後ろに余計なカンマを足した場合は、構文の段階で止まります。

python3 -I tools/check_inputactions.py Assets/Broken.inputactions; echo "exit=$?"
# Assets/Broken.inputactions: JSON parse error line 63 col 1: Expecting property name enclosed in double quotes
# exit=2

.csなど対象外のファイルでは何も出力せず終了コード0です。サンプルのキー構成(maps・actions・bindings・controlSchemes)はEditorが書き出す形式に合わせたものです。実際のプロジェクトでは、Editorで作ったアセットをClaude Codeに読ませて、そのキー構成を土台にしてください。

アクションを足す依頼の出し方

検証の網ができたら、依頼は具体的にします。次のような文面です。

Assets/Input/Player.inputactions の Gameplay マップに Jump アクションを追加して。
Type は Button、キーボードは Space、ゲームパッドは buttonSouth。
既存の id は変えず、新しい要素の id は新規に作って。編集後は検証結果を読んで。

ここで効くのは「Type」と「バインディングのパス」を指定することです。Input Systemのパスは<Keyboard>/spaceや<Gamepad>/buttonSouthのように<デバイス>/コントロールの形で書きます。Claude Codeが書いたパスがコントロール名として実在するかは、フックの検査では見ていません。Editorでアクションエディタを開き、該当バインディングが意図したデバイスのコントロールを指しているかを目で見ます。この確認は人間に残る部分です。

アクション名を変えたいときは、名前だけを変え、idは触らせません。コード側はFindAction("Move")のように文字列で引く場合、名前変更で参照が切れます。依頼には「名前を変えるなら、FindActionの呼び出し側も同じ変更で更新して」と添えておきます。

C#クラスの生成とReimportはEditorで行う

.inputactionsの取り込み設定にあるGenerate C# Classをオンにすると、アクション定義からC#のラッパークラスが生成されます。マニュアルによれば、ファイルを再生成するには、Projectウィンドウで.inputactionsを右クリックしてReimportを選びます。

JSONをClaude Codeが書き換えた後は、Editor側で生成クラスが更新されているかを見て、古ければReimportします。生成クラスの名前やインターフェース(IGameplayActionsのような名前)は、アクションマップ名から決まります。マップ名を変えると、それを実装するスクリプトの宣言も変わる点に注意してください。

Claude Codeに任せやすいのは、生成済みクラスを使う側のスクリプトです。生成されたクラスのファイルを読ませたうえで「OnMoveとOnJumpを実装するMonoBehaviourを書いて」と依頼すれば、コンパイルエラーのログを手がかりに直せます。

CinemachineのInput Action参照は配線の問題として分ける

Cinemachineのカメラは、ユーザー入力を直接は処理しません。カメラが公開する軸を、スクリプト・アニメーション・ユーザー入力が動かす設計です。入力で動かすために使うのが、CinemachineInputAxisControllerコンポーネントです。CinemachineCameraに追加すると、入力で駆動できる軸を自動検出して設定項目を出します。

Input Systemを使う場合の主な項目は次のとおりです(Cinemachine 3.1のマニュアルより)。

項目内容
Input Action内容軸を駆動するInput Actionの参照
Gain内容読み取った入力値に掛ける倍率
Auto Enable Inputs内容マップされた入力アクションを起動時に自動で有効化
Accel Time / Decel Time内容入力値が増減するまでの時間
Player Index内容既定の-1は1人用。複数人のときはプレイヤー番号を指定

Orbital Followのような位置制御は、入力コントローラーを付けるとプレイヤーが軸を動かせるようになります。

ここで役割が分かれます。.inputactionsの中身(Lookアクションの<Mouse>/deltaなど)はJSONの編集でClaude Codeが担当できます。一方で、Input Action欄にそのアクションを割り当てる作業は、シーンまたはプレハブに保存されるオブジェクト参照の設定です。JSONを直しても、この割り当ては生まれません。Editorのインスペクターで設定するか、Editorを操作できる手段(前述のMCPサーバー)に任せます。

「Lookが効かない」という症状は、JSONの誤りと、参照の未設定のどちらからでも起こります。切り分けは次の順に行います。

切り分け

Cinemachineのカメラが入力に反応しないときの切り分け

  1. Qフックの検査はエラー0で終わっているか?
    答えがいいえのとき

    まずJSONの構文・ID重複・アクション名の誤りを直します。Editorがアセットを読めていない可能性があります。

    答えがはい
  2. QActive Input Handlingが新Input SystemまたはBothか?
    答えがいいえのとき

    旧Input Managerだけが有効だとInput Systemの入力は使われません。設定を変えてEditorを再起動します。

    答えがはい
  3. QCinemachineInputAxisControllerのInput Actionに対象アクションが割り当てられているか?
    答えがいいえのとき

    インスペクターで割り当てます。Auto Enable Inputsがオフのときは、別の場所でアクションを有効化している必要があります。

    答えがはい

入力経路がつながっている

ここまで通れば、残るのはバインディングのパスやGainなどの値の調整です。

ルールを1か所に絞って運用する

最後に運用の置き場所です。Unityプロジェクト全体の規約(C#のバージョン、コンストラクタ禁止など)は、CLAUDE.mdに置きます。.inputactionsだけに関わる細則は、上で作ったパス指定ルールに置きます。ルールをCLAUDE.mdから@で取り込む方法もありますが、公式の説明どおり、インポートしたファイルは同時に読み込まれるため、コンテキストの節約にはなりません。

フックはチームで共有する前提なら、.claude/settings.jsonをリポジトリに含めます。検査スクリプトに必要なのはPythonだけで、Unity Editorの実行ファイルのパスには依存しません。Editor起動を伴う検証を足したくなったときは、前述のバッチモードの手順に追加します。

まとめ

.inputactionsはJSONテキストであり、Claude Codeの編集対象にできます。壊れた編集を防ぐ要になるのは、読み込み範囲を絞ったルールと、終了コード2でClaudeに差し戻すフックの2つです。CinemachineのInput Action割り当てのように、シーンやプレハブに保存される参照は、JSONの外にあるためEditorの作業として切り分けます。

参照した一次ソース

この記事の記述は、次の一次ソースと照合しています。更新時に参照先が変わった場合は一覧も更新します。

  1. code.claude.com/docs/en/memory
  2. code.claude.com/docs/en/hooks-guide
  3. code.claude.com/docs/en/hooks
  4. docs.unity3d.com/Packages/com.unity.inputsystem@1.11/manual/ActionAssets.ht…
  5. docs.unity3d.com/Packages/com.unity.inputsystem@1.11/manual/Actions.html
  6. docs.unity3d.com/Packages/com.unity.inputsystem@1.11/manual/Installation.ht…
  7. docs.unity3d.com/Packages/com.unity.inputsystem@1.11/manual/ProjectWideActi…
  8. docs.unity3d.com/Packages/com.unity.cinemachine@3.1/manual/CinemachineInput…
この記事を共有:XはてブLinkedIn