input-handling について
Godot 4.3以降のゲーム開発向けに、GDScriptとC#の例で入力処理を解説するスキルです。イベント伝播やポーリングに加え、マウス、コントローラー、タッチ、実行時の再割り当てを扱います。
主な機能
- 01入力イベントとポーリング
- 02Input Mapのアクション設計
- 03マウスとゲームパッド入力
- 04タッチとマルチタッチ
- 05実行時のアクション再割り当て
- 06入力伝播と一時停止時の処理
活用シーン
- 01ゲームやUI入力に使うコールバックの選択
- 02キーボード、マウス、ゲームパッド操作の追加
- 03タッチ入力の実装とデスクトップでのテスト
- 04カスタムキー割り当ての保存
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ jame581/ godotprompter --skill input-handlingインストール後、Claude Code で/input-handlingを入力して読み込まれたか確認します。
同梱ファイル
SKILL.md と一緒にインストールされる参考資料やスクリプト。
references/action-rebinding.mdevent-propagation.mdgamepad.mdinput-buffering.mdmouse.mdtouch.md詳細
Godot 4.3 以降の入力処理
すべての例は、非推奨 API を使わずに Godot 4.3 以降を対象としています。まず GDScript、次に C# を示します。
関連スキル: 入力で動く移動については player-controller、UI の入力フォーカスとナビゲーションについては godot-ui、カスタムキー割り当ての保存については save-load、タッチ入力とデスクトップ入力の適応については responsive-ui、XR コントローラーとハンドトラッキング入力については xr-development、モバイルセンサーとアプリのライフサイクルについては mobile-development を参照してください。
1. 基本概念
入力の流れ
Hardware Event (key, mouse, gamepad)
↓
Engine converts to InputEvent
↓
_input() ← raw input, runs first
↓
UI Control nodes ← _gui_input: buttons, sliders consume events
↓
_shortcut_input() ← for global shortcuts
↓
_unhandled_key_input() ← unhandled key-only events
↓
_unhandled_input() ← game input (movement, actions)
入力を処理する場所
| メソッド | 用途 | 実行タイミング |
|---|---|---|
_input() | カメラ操作、グローバルホットキー | 最初 — すべての処理より前 |
_shortcut_input() | グローバルショートカット(一時停止、スクリーンショット) | UI の後、未処理イベントの前 |
_unhandled_key_input() | UI が処理しなかったキーイベントのみ | UI の後、キーのみ |
_unhandled_input() | ゲームプレイアクション(ジャンプ、攻撃、インタラクト) | 最後 — UI の処理後 |
_physics_process() 内の Input.is_action_pressed() | 継続的な移動 | 該当なし — イベント駆動ではなく、ポーリング |
経験則: 1 回限りのゲームアクション(ジャンプ、攻撃)には _unhandled_input() を使います。継続的な移動には、_physics_process() 内で Input をポーリングします。UI が入力を処理する前に入力が必要な場合(例:マウス操作)に限り、_input() を使います。
InputEvent の階層
InputEvent
├── InputEventFromWindow
│ ├── InputEventWithModifiers
│ │ ├── InputEventKey ← keyboard
│ │ ├── InputEventMouse
│ │ │ ├── InputEventMouseButton ← mouse clicks
│ │ │ └── InputEventMouseMotion ← mouse movement
│ │ └── InputEventGesture ← Magnify / Pan gestures
│ ├── InputEventScreenTouch ← touchscreen tap
│ └── InputEventScreenDrag ← touchscreen drag
├── InputEventJoypadButton ← gamepad buttons
├── InputEventJoypadMotion ← gamepad sticks/triggers
├── InputEventAction ← synthetic action events
├── InputEventMIDI ← MIDI devices
└── InputEventShortcut
2. Input Map の設定
キーコードを直接チェックする代わりに、Project > Project Settings > Input Map でアクションを定義します。これにより、ゲームロジックを特定のキーから切り離し、キー割り当ての変更が可能になります。
プロジェクトのデフォルトアクション
Godot には ui_accept、ui_cancel、ui_left、ui_right、ui_up、ui_down などの ui_* アクションが用意されています。これらは、UI コントロールでキーボードナビゲーションに使われます。ゲームプレイに使用することもできますが、競合を避けるため、カスタムアクションを作成することをおすすめします。
コードでアクションを追加する
InputMap.add_action() と InputMap.action_add_event() を使うと、実行時にアクションを作成できます。通常はオートロードの _ready() で、InputMap.has_action() による確認を挟んで作成します。アクションはエディターの Input Map で定義し、動的に生成するキー割り当てや MOD のサポートが必要な場合に限り、コードで追加してください。
GDScript と C# のコード例については、references/action-rebinding.md を参照してください。
推奨するアクション名
キー名ではなく、内容がわかるゲーム固有の名前を使います。
| 良い例 | 悪い例 | 理由 |
|---|---|---|
move_left | press_a | 物理キーから切り離せます |
attack | left_click | マウスとゲームパッドの両方で動作します |
interact | press_e | ロジックを変更せずにキー割り当てを変更できます |
sprint | hold_shift | 入力デバイスに依存しません |
pause | press_escape | ゲームパッドの Start ボタンにも割り当てられます |
3. 入力の読み取り — イベントとポーリング
イベント駆動(1 回限りのアクション)
ジャンプ、攻撃、インタラクト、一時停止など、1 回限りのアクションには _unhandled_input() を使います。
GDScript
func _unhandled_input(event: InputEvent) -> void:
if event.is_action_pressed("jump"):
_jump()
get_viewport().set_input_as_handled() # prevent further propagation
if event.is_action_pressed("interact"):
_interact()
if event.is_action_pressed("pause"):
get_tree().paused = not get_tree().paused
get_viewport().set_input_as_handled()
C#
public override void _UnhandledInput(InputEvent @event)
{
if (@event.IsActionPressed("jump"))
{
Jump();
GetViewport().SetInputAsHandled();
}
if (@event.IsActionPressed("interact"))
Interact();
if (@event.IsActionPressed("pause"))
{
GetTree().Paused = !GetTree().Paused;
GetViewport().SetInputAsHandled();
}
}
ポーリング(継続的な入力)
押し続けるボタンやアナログ軸には、_physics_process() 内で Input シングルトンを使います。
GDScript
func _physics_process(delta: float) -> void:
# Movement vector from 4 directional actions
var direction := Input.get_vector("move_left", "move_right", "move_up", "move_down")
velocity = direction * speed
# Check if a button is held
if Input.is_action_pressed("sprint"):
velocity *= 1.5
move_and_slide()
C#
public override void _PhysicsProcess(double delta)
{
Vector2 direction = Input.GetVector("move_left", "move_right", "move_up", "move_down");
Velocity = direction * Speed;
if (Input.IsActionPressed("sprint"))
Velocity *= 1.5f;
MoveAndSlide();
}
主要な入力メソッド
| メソッド | 戻り値 | 用途 |
|---|---|---|
Input.is_action_pressed() | bool | 押し続けるボタン(ダッシュ、しゃがむ、射撃) |
Input.is_action_just_pressed() | bool | 1回だけ実行するトリガー(ジャンプ、インタラクト) |
Input.is_action_just_released() | bool | 離したときのトリガー(ジャンプの可変カット) |
Input.get_action_strength() | float | アナログ入力の強度(0.0–1.0) |
Input.get_axis() | float | 単一軸(-1.0~1.0) |
Input.get_vector() | Vector2 | 2D 方向。長さは 1 に制限されます |
event.is_action_pressed() | bool | _unhandled_input コールバック内で確認 |
event.is_action_released() | bool | _unhandled_input コールバック内で確認 |
_physics_process()内のInput.is_action_just_pressed()は、キーがすでに離されていても、次の物理ティックで押されたことを報告します。ティックレートが低くてもタップが取りこぼされることはありませんが、1 ティック内に複数回押しても 1 回としてカウントされます。押すたびに処理する必要がある場合は、_unhandled_input()で検知してフラグを設定してください。
入力バッファリング
離散的なアクションをバッファリングすると、実行可能になる直前に行った入力(着地直前のジャンプなど)も有効になります。_unhandled_input() でアクションを検知し、短いタイマー(通常は 0.1 秒)とともにフラグを設定して、_physics_process() 内でそのフラグを消費してください。
GDScript と C# によるジャンプバッファの完全な実装については、references/input-buffering.md を参照してください。
4. マウス入力
カメラ操作には InputEventMouseMotion.relative(Input.MOUSE_MODE_CAPTURED 使用時)、クリックには InputEventMouseButton を使用します。マウスモードは VISIBLE、HIDDEN、CAPTURED、CONFINED です。Input.set_custom_mouse_cursor(texture, shape, hotspot) でカスタムカーソルを設定できます。
感度と反転切り替えを備えたカメラ操作、マウスモードの切り替え、ボタンイベント、形状のバリエーションを備えたカスタムカーソルなど、GDScript と C# の完全な手順については、references/mouse.md を参照してください。
5. コントローラー/ゲームパッドのサポート
実行時の検出には Input.get_connected_joypads()、ホットプラグには Input.joy_connection_changed シグナルを使用します。移植性を高めるには、ジョイパッドのボタンイベントを使った Input Map アクションを使用してください。アナログスティックでは、Input.get_vector("left", "right", "up", "down", deadzone) が、長さを制限した Vector2 を返します。デッドゾーンは組み込みです。
コントローラーの検出、デッドゾーンを考慮したアナログ入力の読み取り、
start_joy_vibrationによる振動、モーションセンサー、UI プロンプトの切り替えに使用する最後の入力デバイスの検出など、GDScript と C# の手順については、references/gamepad.md を参照してください。
Godot 4.7 以降: ジョイパッドのモーションセンサー —
Input.get_joy_accelerometer(device)/get_joy_gyroscope(device)(どちらもVector3)は、has_joy_motion_sensors()で利用可能か確認し、set_joy_motion_sensors_enabled()で有効にします。手順は references/gamepad.md を参照してください。振動の状態を照会できるようになりました —Input.has_joy_vibration(device)に加え、get_joy_vibration_strength/duration/remaining_duration()を使用できます。JoyButtonにJOY_BUTTON_MISC2(21)からJOY_BUTTON_MISC6(25)が追加されます(C#:JoyButton.Misc2…)。新しいプロジェクト設定input_devices/joypads/ignore_joypad_on_unfocused_application(デフォルトはfalse)を有効にすると、アプリのフォーカスが外れている間、ジョイパッド入力(モーションセンサーを含む)と LED の変更が無視され、振動が停止します。
6. タッチ入力
タップ/リリースには InputEventScreenTouch、指でのドラッグには InputEventScreenDrag を使用します。マルチタッチは event.index で追跡します。デスクトップでテストするには、プロジェクト設定 → 入力デバイス → ポインティング → マウスからタッチをエミュレートを有効にします。タッチスクリーンで UI が動作するように、タッチからマウスをエミュレートはデフォルトで有効です。
GDScript と C# によるタッチイベントの手順、および画面上のスティック
VirtualJoystick(Godot 4.7 以降)については、references/touch.md を参照してください。
7. 実行時のアクション再割り当て
手順は3つです。(1)「再割り当て」モード中に _input を使ってユーザーが選択したキーを取得します。(2)InputMap.action_erase_events(action) を呼び出した後、InputMap.action_add_event(action, new_event) を呼び出します。(3)ConfigFile を使って保存し、起動時に読み込みます。
ConfigFileの保存/読み込みや、一般的な「キーを押してください」という入力取得 UI を含む、GDScript と C# による再割り当ての一連の流れについては、references/action-rebinding.md をご覧ください。
8. 入力の消費と伝播
入力はシーンツリーの逆順(Scene ドックで一番下にあるノードが最初で、ルートが最後)に伝播します。イベントを消費した後に get_viewport().set_input_as_handled() を呼び出すと、ほかのノードへの伝播を止められます。一時停止中は、process_mode が PROCESS_MODE_ALWAYS または PROCESS_MODE_WHEN_PAUSED のノードだけが入力を受け取ります。
伝播の停止、ノードの処理順序、一時停止中の入力受信についての GDScript と C# の手順は、references/event-propagation.md をご覧ください。
9. よくある問題
| 症状 | 原因 | 解決方法 |
|---|---|---|
| アクションが認識されない | Input Map にアクション名が定義されていない | Project > Project Settings > Input Map でアクションを追加します |
| 短時間に連続して押しても1回としてカウントされる | _physics_process で is_action_just_pressed() をポーリングしているため、複数の押下が同じティックにまとめられる | 離散的なアクションは _unhandled_input() で取得します |
| UI を開いても入力が反応する | _unhandled_input() ではなく _input() を使っている | UI が先にイベントを消費するよう、_unhandled_input() に切り替えます |
| メニューの上からマウスルックが反応する | モードを確認せずに _input() でマウスの動きを処理している | if Input.mouse_mode == Input.MOUSE_MODE_CAPTURED で処理を制御します |
| ゲームパッドのスティックがドリフトする | デッドゾーンが低すぎる、または設定されていない | Input Map でアクションごとにデッドゾーンを設定します(0.2 が適切な初期値です) |
| コントローラーが検出されない | ゲーム開始前に接続されていない | joy_connection_changed シグナルに接続し、ホットプラグを処理します |
| キーの再割り当てで修飾キーが取得される | Shift/Ctrl/Alt 単独の入力を除外していない | キーコードが修飾キーであるイベントをスキップします |
| デスクトップでタッチ入力が機能しない | 「Emulate Touch From Mouse」が無効になっている | Project Settings > Input Devices > Pointing で有効にします |
| 一時停止中にポーズメニューが入力を無視する | ノードの process_mode が INHERIT(親とともに一時停止)になっている | ポーズメニューを PROCESS_MODE_ALWAYS に設定します |
| 1回押すとアクションが2回実行される | 同じアクションを _input と _unhandled_input の両方で確認している | アクションごとにコールバックを1つ選びます |
⚠️ Godot 4.7 で変更されました: マウスとキーボードのデバイス ID が
0からInputEvent.DEVICE_ID_MOUSE(32)およびInputEvent.DEVICE_ID_KEYBOARD(16)に変更されました。これは、一部のジョイパッドがデバイス ID として0を使用するためです。キーボード/マウス入力を検出するためにevent.device == 0を確認するコードは、気付かないうちに動作しなくなります。定数と比較するか、イベントの型(代わりにevent is InputEventKey)を確認してください。4.7 移行ガイドをご覧ください。
10. 実装チェックリスト
- すべてのゲームプレイ操作が Input Map で定義されています。ゲームロジックに生のキーコードは使用しません
- 離散的な操作(ジャンプ、攻撃)には
_physics_process()でのポーリングではなく、_unhandled_input()を使用します - 継続的な入力(移動、スプリント)には
_physics_process()内でInput.get_vector()/Input.is_action_pressed()を使用します - メニュー表示中に視点が回転しないよう、マウス視点操作では
Input.mouse_mode == MOUSE_MODE_CAPTUREDを条件にします - コントローラーに対応するため、各 Input Map アクションにキーボードとゲームパッドの両方の割り当てがあります
- ゲームパッドのデッドゾーンは Input Map でアクションごとに設定します(新しいアクションの場合、4.3 では 0.5、4.4 以降では 0.2)
- ポーズメニューのノードは
process_mode = PROCESS_MODE_ALWAYSに設定され、ポーズ中も入力を受け取ります - 伝播させないイベントを消費した後に
get_viewport().set_input_as_handled()を呼び出します - キーボードとゲームパッドの UI プロンプトを切り替えて表示する場合は、入力デバイスの検出機能があります
- キー割り当ての変更は、ゲーム起動時に
user://から読み込まれ、そこに保存されます