【Godot】入力判定メソッドの使い分け|just_pressed、pressed、released

作成: 2025-06-20最終更新: 2025-12-16

Godot Engineの入力処理メソッド is_action_just_pressed, is_action_pressed, is_action_just_released の違いを解説。ジャンプ、移動、チャージ攻撃、可変ジャンプなどの実践的なコード例とベストプラクティスを紹介します。

概要

プレイヤーの操作に正確に反応するゲームを作るには、キー入力の「状態」を正しく理解することが不可欠です。「キーが押されている間ずっと」なのか、「キーが押された瞬間だけ」なのか。この違いを使い分けることで、キャラクターの動きは格段に良くなります。

「ボタンを押したらジャンプする」—単純に見えるこの操作も、実装方法を間違えるとゲームの触り心地(ゲームフィール)を大きく損ないます。例えば、ジャンプボタンを押しっぱなしにしただけでキャラクターが無限にピョンピョン跳ねてしまったり、逆に移動キーを一瞬押しただけなのに滑るように動き続けたり。こうした問題の多くは、入力の「状態」を正しく区別できていないことが原因です。

この記事では、Godotの主要な入力判定メソッドであるis_action_just_pressed, is_action_pressed, is_action_just_releasedの違いを解説します。

3つの主要な入力取得メソッド

Godotの入力処理は、主にInputシングルトン(どこからでもアクセスできるグローバルなオブジェクト)を介して行われます。ここでは、最もよく使われる3つのポーリング方式のメソッドを見ていきましょう。これらのメソッドは、_process_physics_processといった毎フレーム呼び出される関数内で使用し、その瞬間の入力状態をチェックします。

引数には、プロジェクト > プロジェクト設定 > 入力マップで定義したアクション名を文字列で指定します(例: "jump", "move_right")。

メソッド判定タイミング返り値主な用途
is_action_pressed()アクションが押されている間ずっとtrueキャラクターの継続的な移動、連射、UIの高速スクロール
is_action_just_pressed()アクションが押された最初の1フレームだけtrueジャンプ、決定、メニューを開く、単発の射撃
is_action_just_released()アクションが離された最初の1フレームだけtrueチャージ攻撃の解放、ジャンプの高さ調整、ドラッグ&ドロップの終了

実践的なコード例

理論を理解したところで、具体的なコードを見ていきましょう。ここでは2Dプラットフォーマーゲームのキャラクターを例に、各メソッドをどのように使い分けるかを示します。

1. 基本的な移動とジャンプ(pressed & just_pressed

これは最も基本的な組み合わせです。左右の移動には継続的な入力を、ジャンプには瞬間的な入力を使用します。

extends CharacterBody2D

const SPEED = 300.0
const JUMP_VELOCITY = -400.0

var gravity = ProjectSettings.get_setting("physics/2d/default_gravity")

func _physics_process(delta):
    # 重力適用
    if not is_on_floor():
        velocity.y += gravity * delta

    # ジャンプ: 押された「瞬間」に一度だけ実行
    if Input.is_action_just_pressed("jump") and is_on_floor():
        velocity.y = JUMP_VELOCITY

    # 左右移動: 押されている「間」ずっと力を加える
    var direction = Input.get_axis("move_left", "move_right")
    if direction:
        velocity.x = direction * SPEED
    else:
        velocity.x = move_toward(velocity.x, 0, SPEED)

    move_and_slide()

Input.get_axis()は内部的にis_action_pressed()と同様のチェックを行っており、キーが押されている間、-1から1の値を返します。これにより、滑らかな移動が実現できています。

2. チャージ攻撃(pressed & released

ボタンを押している間に力を溜め、離した瞬間に攻撃を放つチャージ攻撃は、pressedreleasedの組み合わせで実現できます。

extends Sprite2D

var is_charging = false
var charge_time = 0.0
const MAX_CHARGE_TIME = 2.0

func _process(delta):
    # チャージ処理: 押されている間、チャージ時間を加算
    if Input.is_action_pressed("charge_attack"):
        is_charging = true
        charge_time += delta
        # チャージレベルに応じて見た目を変える(例: 色を変える)
        modulate = Color.WHITE.lerp(Color.RED, charge_time / MAX_CHARGE_TIME)
        print("Charging... %.2fs" % charge_time)

    # 攻撃発動: 離された瞬間に実行
    if Input.is_action_just_released("charge_attack"):
        if is_charging:
            var power = clamp(charge_time, 0.5, MAX_CHARGE_TIME)
            print("Attack released with power: %.2f!" % power)
            # ここで弾を発射するなどの処理を呼ぶ
            # fire_bullet(power)

            # リセット
            is_charging = false
            charge_time = 0.0
            modulate = Color.WHITE

3. 可変ジャンプ(just_pressed & released

ボタンを押す長さでジャンプの高さを変える、いわゆる「可変ジャンプ」は、マリオのような多くのプラットフォーマーで採用されているテクニックです。これにより、操作の幅が格段に広がります。

# (CharacterBody2Dのコードに追加)

const SHORT_JUMP_MULTIPLIER = 0.5

func _physics_process(delta):
    # ... (重力と移動のコードは同じ)

    # ジャンプ開始
    if Input.is_action_just_pressed("jump") and is_on_floor():
        velocity.y = JUMP_VELOCITY

    # ジャンプボタンが離されたら、上昇を止める
    if Input.is_action_just_released("jump") and velocity.y < 0:
        velocity.y *= SHORT_JUMP_MULTIPLIER

    # ... (move_and_slide())

このコードでは、ジャンプボタンが離され、かつキャラクターがまだ上昇中(velocity.y < 0)の場合に、上昇速度にブレーキをかけています。これにより、「短く押すと低いジャンプ、長く押すと高いジャンプ」が実現できます。


よくある間違いとベストプラクティス

入力処理は間違いやすいポイントがいくつかあります。以下の表を参考に、より堅牢で意図通りのコードを目指しましょう。

カテゴリよくある間違いベストプラクティス
ジャンプ処理is_action_pressed() を使う。ボタンを押し続けると意図せず連続ジャンプしてしまう。is_action_just_pressed() を使う。押した瞬間に一度だけジャンプ処理を実行する。
UI操作is_action_pressed() を決定ボタンに使う。毎フレーム決定処理が走り、メニューが一気に進んでしまう。is_action_just_pressed() を使う。UI操作は単発のアクションとして扱うのが基本。
処理ループ物理演算に関わる入力を _process() で処理する。フレームレートの変動で物理挙動が不安定になる可能性がある。物理演算に関わる入力(移動、ジャンプなど)は _physics_process() で処理し、安定した挙動を保証する。
アクション定義スクリプト内にキーコードをハードコーディングする (Input.is_key_pressed(KEY_SPACE))。キー変更が面倒になる。InputMap でアクションを定義し、is_action_pressed("jump") のように名前で呼び出す。キーコンフィグが容易になる。

パフォーマンスと代替手法:ポーリング vs イベント駆動

これまで紹介してきたis_action_*系のメソッドは、「ポーリング」と呼ばれる方式です。これは、毎フレーム「入力はありますか?」と能動的に確認しにいく方法です。

一方で、Godotには「イベント駆動」というもう一つの主要な入力処理方法があります。これは、_input()_unhandled_input()といった仮想関数をオーバーライドし、入力があったときにGodot側から通知を受け取る方式です。

# イベント駆動方式の例
func _unhandled_input(event: InputEvent):
    if event.is_action_pressed("jump"):
        # キーが押された瞬間にイベントが発生し、この関数が呼ばれる
        # ※キーリピートが有効な場合は長押しで繰り返し呼ばれることがある
        print("Jump action event!")

    if event.is_action_released("ui_cancel"):
        get_tree().quit()

どちらを使うべきか?

  • ポーリング (is_action_*):

    • 長所: _process_physics_process内で、好きなタイミングで入力状態をチェックできる。キャラクターの移動のように「押されている状態」が重要な場合に非常に直感的。
    • 短所: 毎フレームチェック処理が走る。ただし、現代のPCではこれがボトルネックになることは稀です。
  • イベント駆動 (_input, _unhandled_input):

    • 長所: 入力があった時だけコードが実行されるため、効率が良い。マウスのクリック位置取得や、UI操作、ポーズメニューの表示など、単発のイベント処理に最適。
    • 短所: 「押され続けている」状態を管理するには、自分でフラグ変数を用意する必要があり、コードが少し複雑になることがある。

キャラクターのリアルタイムな操作にはポーリングを、UI操作や一度きりのアクションにはイベント駆動を、というように使い分けるのが効果的です。

まとめ

入力判定はゲームの触り心地(ゲームフィール)を決定づける重要な要素です。Godotが用意してくれている3つのメソッドを正しく使い分けることで、より直感的でレスポンスの良い操作性を実現できます。

  • 移動のように継続的なアクションには is_action_pressed()
  • ジャンプ決定のような単発のアクションには is_action_just_pressed()
  • 溜め解放のような特殊なアクションには is_action_just_released()

この基本を覚えて、ぜひあなたのゲームに活かしてみてください。