【Godot】InputMapによるキーバインド管理

作成: 2025-06-20最終更新: 2026-07-08

GodotのInputMapで、キーボード、マウス、ゲームパッドの入力をゲーム内アクションへ対応させる方法を、8方向移動、キーコンフィグ、保存復元まで含めて解説します。

ジャンプは Space、攻撃は X、移動は WASD。最初はそれで十分に見えます。

しかし、ゲームパッドに対応したい、左利き用のキー配置を用意したい、プレイヤーがゲーム内でキーを変更できるようにしたい、となると、スクリプト内に KEY_SPACEKEY_X が散らばっている設計はすぐにつらくなります。

InputMap は、物理的なキーやボタンと、ゲーム内のアクション名を結びつける仕組みです。コードは「Spaceが押されたか」ではなく、「jumpアクションが押されたか」を見ます。

キーボード、マウス、ゲームパッドからInputMapを通してjump、attack、dash、moveへつなぐ図

この記事でわかること

  • InputMapで入力を抽象化する理由
  • エディタでアクションを登録する手順
  • Input.get_vector() で8方向移動を作る方法
  • ゲーム内キーコンフィグの基本実装
  • キー設定を ConfigFile で保存・復元する考え方

Sponsored

InputMapは入力の翻訳表

InputMapを使わない場合、コードは物理キーを直接見ます。

# 避けたい例: Spaceキーに固定される
if Input.is_key_pressed(KEY_SPACE):
    jump()

この書き方は小さい実験なら問題ありません。ただし、プレイヤーがキー設定を変えたい場合、ゲームパッドにも対応したい場合、キーボード配列が違う環境を考える場合に弱くなります。

InputMapを使うと、コードはアクション名だけを見ます。

# よい例: どのキーに割り当てられているかをコードが知らない
if Input.is_action_just_pressed("jump"):
    jump()

"jump" には、Space、ゲームパッドAボタン、別のキーなどを複数登録できます。コード側はずっと "jump" のままです。

この「物理入力」と「ゲームの意味」を分けることが、InputMapの一番大事な役割です。

エディタでアクションを登録する

まずはエディタで基本設定をします。

  1. 「プロジェクト」→「プロジェクト設定」を開く
  2. 「Input Map(入力マップ)」タブを選ぶ
  3. jumpattackmove_left のようなアクション名を追加する
  4. 各アクションの + ボタンから、キー、マウスボタン、ゲームパッド入力を登録する
Input Mapのスロットへキーを登録する様子を示すイメージ図

アクション名は、キー名ではなくゲーム内の意味で付けます。

よい名前避けたい名前理由
jumpspaceSpace以外にも割り当てる可能性がある
attackleft_clickゲームパッドボタンでも攻撃できるようにしたい
move_lefta_keyキー配置が変わっても意味は左移動のまま
ui_cancelesc_keyEsc以外のキャンセル入力も登録できる

この命名を最初に整えておくと、あとからキーコンフィグを作るときに楽になります。

Sponsored

スクリプトではアクション名を見る

アクション名は文字列で直接書いても動きますが、記事やプロジェクトが大きくなるとタイプミスが怖くなります。よく使うものは定数にしておくと読みやすいです。

const ACTION_JUMP: StringName = &"jump"
const ACTION_ATTACK: StringName = &"attack"
const ACTION_MOVE_LEFT: StringName = &"move_left"
const ACTION_MOVE_RIGHT: StringName = &"move_right"

func _physics_process(delta: float) -> void:
    if Input.is_action_just_pressed(ACTION_JUMP):
        # どのキーでjumpしたかは気にしない
        jump()

    var direction := Input.get_axis(ACTION_MOVE_LEFT, ACTION_MOVE_RIGHT)
    velocity.x = direction * 260.0
    move_and_slide()

func _process(delta: float) -> void:
    if Input.is_action_just_pressed(ACTION_ATTACK):
        attack()

定数化すると、"jump""jamp" と打ち間違えるようなミスを減らせます。チーム制作や記事数が多いプロジェクトでは、入力名をまとめた input_actions.gd のようなファイルを作るのも有効です。

実装例1: get_vectorで8方向移動を作る

トップダウンRPG、ツインスティックシューター、見下ろし型アクションでは、上下左右の入力から1つの移動ベクトルを作ります。

このとき Input.get_vector() が便利です。

move_left、move_right、move_up、move_downをInput.get_vectorでVector2に変換する図
extends CharacterBody2D

const SPEED := 220.0

const MOVE_LEFT: StringName = &"move_left"
const MOVE_RIGHT: StringName = &"move_right"
const MOVE_UP: StringName = &"move_up"
const MOVE_DOWN: StringName = &"move_down"

func _physics_process(delta: float) -> void:
    # 4方向のアクションから、移動用のVector2を作る
    var input_vector := Input.get_vector(
        MOVE_LEFT,
        MOVE_RIGHT,
        MOVE_UP,
        MOVE_DOWN
    )

    velocity = input_vector * SPEED
    move_and_slide()

get_vector() を使うと、斜め入力の長さが大きくなりすぎないように扱えます。move_leftmove_up を同時に押したとき、単純に (-1, -1) のまま動かすと斜め移動が速くなりますが、get_vector() はゲームで扱いやすい方向ベクトルとして返してくれます。

実装レシピ: トップダウンRPGの移動

トップダウンRPGなら、次のように組むと拡張しやすいです。

  1. InputMapに move_leftmove_rightmove_upmove_down を登録する
  2. それぞれに A/D/W/S、矢印キー、ゲームパッドの方向入力を登録する
  3. プレイヤー側は Input.get_vector() だけを見る
  4. ダッシュを追加する場合は dash アクションを別に登録する
  5. キー設定画面では、InputMapのアクション単位で表示する

コードが WA を知らないため、あとからゲームパッド対応を足しても移動処理を変えずに済みます。

Sponsored

実装例2: ゲーム内キーコンフィグ

ゲーム内オプションで「ジャンプキーを変更する」機能を作る場合、流れは次のようになります。

ゲーム内キーコンフィグでjumpに新しいキーを割り当てて保存する様子
  1. 変更したいアクションを選ぶ
  2. 次のキー入力を待つ
  3. 古い割り当てを消す
  4. 新しい InputEvent をInputMapへ登録する
  5. 設定を保存する

まずは、単純にキーボードの1キーを割り当て直す例です。

# key_config_screen.gd
extends Control

var waiting_for_input := false
var target_action: StringName = &""

func start_rebind(action: StringName) -> void:
    # UIボタンから「jumpを変更」などを指定して呼ぶ
    waiting_for_input = true
    target_action = action
    show_waiting_message(action)

func _unhandled_input(event: InputEvent) -> void:
    if not waiting_for_input:
        return

    if event is InputEventKey and event.pressed and not event.echo:
        # 既存キーを消して、新しいキーだけ登録する
        InputMap.action_erase_events(target_action)
        InputMap.action_add_event(target_action, event)

        waiting_for_input = false
        hide_waiting_message()

        # このキー入力がゲーム側へ伝わらないようにする
        get_viewport().set_input_as_handled()

func show_waiting_message(action: StringName) -> void:
    print("%s に割り当てるキーを押してください" % action)

func hide_waiting_message() -> void:
    print("キー設定を更新しました")

この例では、1アクションに1キーだけを登録しています。実際のゲームでは「追加」「削除」「初期設定に戻す」「ゲームパッドも受け付ける」などをUIに合わせて拡張します。

注意点は、event.echo を除外することです。キーを押しっぱなしにしたときのリピート入力まで登録処理に使うと、意図しない挙動につながります。

実装例3: キー設定を保存する

実行中にInputMapを書き換えても、そのままではゲームを再起動すると戻ります。プレイヤーの設定として残したい場合は、ConfigFile などで保存します。

ここでは分かりやすく、キーボードの keycode だけを保存する小さな例にします。

# key_config_store.gd
extends Node

const SAVE_PATH := "user://key_config.cfg"
const SECTION := "keys"

const ACTIONS: Array[StringName] = [
    &"jump",
    &"attack",
    &"dash",
]

func save_key_config() -> void:
    var config := ConfigFile.new()

    for action in ACTIONS:
        var events := InputMap.action_get_events(action)

        for event in events:
            if event is InputEventKey:
                # この記事では最初に見つけたキーだけ保存する
                config.set_value(SECTION, String(action), event.keycode)
                break

    config.save(SAVE_PATH)

読み込み側では、保存した keycode から InputEventKey を作り直します。

func load_key_config() -> void:
    var config := ConfigFile.new()

    if config.load(SAVE_PATH) != OK:
        return

    for action in ACTIONS:
        var action_name := String(action)

        if not config.has_section_key(SECTION, action_name):
            continue

        var event := InputEventKey.new()
        event.keycode = config.get_value(SECTION, action_name)

        # プロジェクト設定の割り当てを消し、保存済みキーを登録する
        InputMap.action_erase_events(action)
        InputMap.action_add_event(action, event)

このコードはあくまで最小例です。ゲームパッド、マウス、複数キー登録、修飾キー付きショートカットまで保存したい場合は、イベントの種類ごとに保存形式を増やします。

初心者のうちは、まず「アクション名」「1つのキー」「保存と読み込み」までを確実に作るのがおすすめです。最初からすべてのデバイスを完全対応しようとすると、入力処理よりUI設計の方が大きな作業になります。

Sponsored

よくあるつまずき

アクション名をキー名で付けてしまう

space_jumpx_attack のような名前は、キーを変更した瞬間に意味がずれます。

アクション名はゲーム内の意味で付けます。jumpattackinteractopen_menu のような名前にしておけば、割り当てキーが変わっても違和感がありません。

ゲームパッド用とキーボード用でアクションを分けすぎる

jump_keyboardjump_gamepad を分けると、コード側で両方を確認する必要が出ます。

# 避けたい例
if Input.is_action_just_pressed("jump_keyboard") or Input.is_action_just_pressed("jump_gamepad"):
    jump()

同じ意味の入力は、同じアクションにまとめます。

# よい例
if Input.is_action_just_pressed("jump"):
    jump()

キー変更中の入力がゲーム側にも伝わる

キーコンフィグ画面で新しいキーを押した瞬間、そのキーがゲーム側にも伝わると、キャラクターが動いたりメニューが閉じたりします。

入力を受け取ったら get_viewport().set_input_as_handled() を呼び、他の処理へ伝わらないようにします。

デフォルトへ戻す処理を用意していない

キーコンフィグでは、プレイヤーが操作不能になる設定をしてしまう可能性があります。最低限、デフォルトへ戻すボタンを用意しておくと安心です。

func reset_to_default_input_map() -> void:
    # プロジェクト設定に定義したInputMapへ戻す
    InputMap.load_from_project_settings()

おまけ: 先に知っておくと良いこと

UI操作用のui_*アクションは慎重に扱う

Godotには ui_acceptui_cancelui_left などの組み込みアクションがあります。UIナビゲーションやControlノードが使うため、ゲーム独自の操作と混ぜすぎると意図しない入力が起きることがあります。

ゲームプレイ用には jumpattackdash のような専用アクションを作り、UI用の ui_* とは役割を分けると管理しやすいです。

デッドゾーンはゲームパッド対応で重要

アナログスティックは、触っていなくてもわずかな入力値が出ることがあります。InputMap側のデッドゾーンを調整すると、キャラクターが勝手に動く問題を減らせます。

スティック入力を使うゲームでは、「入力が効かない」と「勝手に動く」の間を調整する作業が必要になります。

完全なキーコンフィグUIは別テーマ

この記事では、InputMapの基本と最小の再割り当てを扱いました。実際のキーコンフィグ画面では、重複チェック、キャンセル、初期化、ゲームパッド表示名、ローカライズなども必要になります。

ただし、それらはInputMapの上に乗るUI設計の話です。まずは「コードはアクション名を見る」「割り当てはInputMapに集める」という土台を作ることが大切です。

まとめ

  • InputMap は、物理キーやボタンをゲーム内アクション名へ変換する仕組み
  • コードでは KEY_SPACE ではなく、"jump" のようなアクション名を見る
  • 同じ意味の入力は1つのアクションにまとめる
  • 8方向移動には Input.get_vector() が便利
  • 実行中のキー変更は InputMap.action_erase_events()InputMap.action_add_event() で行う
  • 再起動後も残したい設定は ConfigFile などで保存する

InputMapを使う目的は、単にキーを登録することではありません。プレイヤーの入力方法が変わっても、ゲームロジック側のコードを変えずに済むようにすることです。

さらに学ぶために