ゲーム開発において、プレイヤーの入力を適切に処理することは最も基本的かつ重要な要素の一つです。Godotエンジンでは、柔軟で強力な入力システムが提供されており、キーボード、マウス、ゲームパッドなどさまざまな入力デバイスからの操作を簡単に処理できます。
この記事では、Godot 4の入力システムの基礎から応用まで、実例を交えながら解説します。この記事を読むことで、以下のことができるようになります:
Godotでは、入力処理の方法として主に2つのアプローチがあります:
_input
や _unhandled_input
関数を使用)Input.is_action_pressed
などの関数を使用)まずは基本となる入力イベントの処理方法から見ていきましょう。
Godotでは、_input
関数をオーバーライドすることで、あらゆる入力イベントをキャッチできます。
func _input(event):
# キー入力イベントを処理
if event is InputEventKey and event.pressed and not event.echo:
var keycode = event.keycode
print("押されたキー: ", OS.get_keycode_string(keycode))
このコードでは、キーが押されたときにそのキーの文字列表現をコンソールに出力します。event.echo
をチェックすることで、キーの長押しによる連続入力を無視しています。
実際のゲーム開発では、特定のキーコードに直接依存するよりも、InputMapを使ったアクション名でのマッピングがより柔軟です。これにより、プラットフォーム間の違いを吸収したり、プレイヤーによるキー設定のカスタマイズが容易になります。
以下は、現在押されたキーに対応するアクションを確認するコードです:
func _input(event):
if event is InputEventKey and event.pressed and not event.echo:
var keycode = event.keycode
print("押されたキー: ", OS.get_keycode_string(keycode))
# すべてのアクションを確認
var actions = InputMap.get_actions()
var matching_actions = []
for action in actions:
if Input.is_action_just_pressed(action):
matching_actions.append(action)
if matching_actions.size() > 0:
print("このキーに対応するアクション: ", matching_actions)
else:
print("このキーに対応するアクションはありません")
このコードは、キーが押されたときに以下の情報を提供します:
開発中のゲームで入力関連の問題をトラブルシューティングする場合、上記のコードは非常に役立ちます。ここでは、さらに実践的なデバッグテクニックを紹介します。
開発中は、現在の入力状態を画面上に表示すると便利です。以下は簡単なオーバーレイ表示の実装例です:
extends CanvasLayer
var active_actions = []
func _process(_delta):
# 更新のたびにアクティブなアクションをクリア
active_actions.clear()
# すべてのアクションを確認
var actions = InputMap.get_actions()
for action in actions:
if Input.is_action_pressed(action):
active_actions.append(action)
# 表示更新
$Label.text = "アクティブなアクション: " + str(active_actions)
このスクリプトをCanvasLayerノードにアタッチし、子ノードとしてLabelを追加することで、現在アクティブなアクションをリアルタイムで表示できます。
より詳細な入力情報が必要な場合は、イベントオブジェクトから追加情報を取得できます:
func _input(event):
if event is InputEventKey and event.pressed:
var info = {
"keycode": event.keycode,
"scancode": event.physical_keycode,
"unicode": event.unicode,
"echo": event.echo,
"alt": event.alt_pressed,
"shift": event.shift_pressed,
"ctrl": event.ctrl_pressed
}
print("キー詳細情報: ", info)
これにより、修飾キー(Alt、Shift、Ctrl)の状態や、物理キーコードなどの追加情報も取得できます。
Godotのプロジェクト設定からInputMapを設定することもできますが、大規模なプロジェクトでは、コードでプログラム的に設定することも有効です。
func setup_input_mapping():
# 既存のマッピングをクリア
InputMap.action_erase_events("move_right")
# 新しいキーボード入力イベントを作成
var event = InputEventKey.new()
event.keycode = KEY_D
# アクションに追加
InputMap.action_add_event("move_right", event)
# ゲームパッド入力も追加
var pad_event = InputEventJoypadMotion.new()
pad_event.axis = JOY_AXIS_0
pad_event.axis_value = 1.0
InputMap.action_add_event("move_right", pad_event)
このアプローチを使用すると、ゲーム開始時に動的にキー設定を行ったり、プレイヤーが好みに合わせてカスタマイズできる設定画面を実装したりすることが可能です。
複数のプラットフォームで一貫した体験を提供するために、以下のような命名規則を採用するとよいでしょう:
# 移動系
"move_up", "move_down", "move_left", "move_right"
# アクション系
"action_primary", "action_secondary", "action_dodge"
# UI操作系
"ui_accept", "ui_cancel", "ui_menu"
このようなアクション名を使用することで、実際のキー割り当てに依存せず、意図を明確にしたコードが書けます。
Godotは複数のプラットフォームに対応していますが、入力処理においてはいくつかの考慮点があります。
func _ready():
# 初期化時にデバイスタイプを検出
update_input_device_type()
func _input(event):
# 入力デバイスの種類を検出
if event is InputEventKey or event is InputEventMouse:
if current_device_type != "keyboard_mouse":
current_device_type = "keyboard_mouse"
update_ui_for_device()
elif event is InputEventJoypadButton or event is InputEventJoypadMotion:
if current_device_type != "gamepad":
current_device_type = "gamepad"
update_ui_for_device()
func update_ui_for_device():
# 現在のデバイスに基づいてUIのプロンプトを更新
if current_device_type == "keyboard_mouse":
$Prompts.texture = keyboard_prompts
else:
$Prompts.texture = gamepad_prompts
このコードは、プレイヤーが途中でキーボードからゲームパッドに切り替えた場合など、現在使用している入力デバイスを検出し、それに合わせてUIを更新します。
モバイルデバイス向けにタッチ入力を処理する例:
func _input(event):
if event is InputEventScreenTouch:
if event.pressed:
print("タッチ開始位置: ", event.position)
else:
print("タッチ終了位置: ", event.position)
elif event is InputEventScreenDrag:
print("ドラッグ位置: ", event.position)
print("相対移動量: ", event.relative)
タッチ入力では、従来のキーボードやゲームパッドとは異なる設計アプローチが必要です。オンスクリーンコントロールを実装するか、スワイプやジェスチャーを活用するかを検討しましょう。
複数のシステムで同じキーを使用している場合、意図しない動作が発生することがあります。
# 優先順位を付けて処理する例
func _unhandled_input(event):
if is_in_menu:
handle_menu_input(event)
elif is_in_dialog:
handle_dialog_input(event)
else:
handle_gameplay_input(event)
_input
ではなく_unhandled_input
を使用することで、UIなどの優先度の高いシステムがイベントを処理した後の残りの入力のみを処理できます。
アクションゲームなどでは、入力の正確なタイミングが重要です。以下はシンプルな入力バッファリングの実装例です:
var input_buffer = []
var buffer_timeout = 0.2 # 秒
func _input(event):
if event is InputEventKey and event.pressed and not event.echo:
# 入力をバッファに追加
input_buffer.append({
"action": get_action_for_key(event.keycode),
"time": Time.get_ticks_msec() / 1000.0
})
func _process(delta):
var current_time = Time.get_ticks_msec() / 1000.0
# 古い入力を削除
while input_buffer.size() > 0 and current_time - input_buffer[0].time > buffer_timeout:
input_buffer.pop_front()
# バッファ内の入力を処理
process_buffered_inputs()
このテクニックを使用すると、プレイヤーの入力をより寛容に処理できます。たとえば、ジャンプ直前に走るアクションを入力した場合でも、短時間であればジャンプ中に走り始めるなどの処理が可能になります。
典型的なプレイヤー移動制御の例:
func _physics_process(delta):
var direction = Vector2.ZERO
if Input.is_action_pressed("move_right"):
direction.x += 1
if Input.is_action_pressed("move_left"):
direction.x -= 1
if Input.is_action_pressed("move_down"):
direction.y += 1
if Input.is_action_pressed("move_up"):
direction.y -= 1
# 方向を正規化して斜め移動が速くなりすぎないようにする
if direction.length() > 0:
direction = direction.normalized()
# 移動速度を適用
velocity = direction * speed
# 実際の移動を適用
move_and_slide()
より複雑なゲームでは、カスタム入力システムを実装するとよいでしょう:
class_name InputManager
extends Node
signal action_pressed(action_name)
signal action_released(action_name)
var active_actions = {}
var previous_actions = {}
func _process(_delta):
previous_actions = active_actions.duplicate()
active_actions.clear()
for action in InputMap.get_actions():
if Input.is_action_pressed(action):
active_actions[action] = true
# 新たに押されたアクション
if not previous_actions.has(action):
emit_signal("action_pressed", action)
elif previous_actions.has(action):
# 離されたアクション
emit_signal("action_released", action)
このようなマネージャークラスを使用すると、入力の変化をシグナルとして他のシステムに通知できるため、コードの分離と再利用性が向上します。
Godot 4の入力システムは非常に柔軟で強力です。この記事で紹介した基本的な入力処理から、デバッグテクニック、マルチプラットフォーム対応、そして実践的なユースケースまでを理解することで、よりレスポンシブでユーザーフレンドリーなゲームを開発することができます。
ポイントをまとめると:
_input
や_unhandled_input
関数を活用するこれらの知識とテクニックを活用して、プレイヤーにとって直感的で快適な操作感を実現しましょう!
Godot 4 以上を前提とした記事です。記載されているコードは、Godot 4 で動作確認済みです。