【Godot】入力判定メソッドの使い分け

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

Godotのis_action_pressed、is_action_just_pressed、is_action_just_releasedを、移動、ジャンプ、可変ジャンプ、チャージ攻撃、UI操作の実例で使い分けます。

ボタンを押したらジャンプする。押している間だけ右へ走る。離した瞬間にチャージ攻撃を撃つ。

どれも「入力を見る」処理ですが、必要な判定タイミングは違います。ここを混ぜると、ジャンプボタンを押しっぱなしにしただけで着地後にまた跳ぶ、決定ボタンを長押ししてメニューが一気に進む、チャージ攻撃が押した瞬間に発射される、といった違和感につながります。

just_pressed、pressed、just_releasedの違いをボタンのタイムラインで示した図

この記事では、Godotでよく使う3つの入力判定を、ゲームの実装例に結びつけて整理します。

この記事でわかること

  • is_action_pressed()is_action_just_pressed()is_action_just_released() の違い
  • 移動、ジャンプ、可変ジャンプ、チャージ攻撃での使い分け
  • _physics_process()_unhandled_input() の使い分け
  • 入力処理で起きやすい失敗と、その避け方

Sponsored

3つの入力判定をタイムラインで理解する

Godotの Input.is_action_*() 系は、InputMapに登録したアクション名を使って入力状態を調べます。

メソッドtrueになるタイミング使う場面
Input.is_action_just_pressed("jump")押された瞬間だけジャンプ、攻撃開始、決定、メニューを開く
Input.is_action_pressed("move_right")押されている間ずっと移動、長押し、チャージ、連射
Input.is_action_just_released("jump")離された瞬間だけ可変ジャンプ、チャージ解放、ドラッグ終了

覚え方はシンプルです。

  • just_pressed: 押した瞬間の1回
  • pressed: 押している間ずっと
  • just_released: 離した瞬間の1回

たとえば、ジャンプ開始は「押した瞬間」だけで十分です。押している間ずっとジャンプ処理を実行すると、着地した瞬間にまた跳ぶような挙動になります。

一方、左右移動は「押している間ずっと」速度を与える必要があります。移動に just_pressed を使うと、キーを押した最初の瞬間だけしか反応せず、キャラクターが思うように動きません。

まずInputMapでアクション名を使う

入力は、できるだけキー名ではなく InputMapのアクション名 で扱います。

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

# よい例: InputMapのjumpアクションを見る
Input.is_action_just_pressed("jump")

"jump""move_left""attack" のような名前で扱うと、あとからキーボード、ゲームパッド、キーコンフィグに対応しやすくなります。

設定場所は「プロジェクト設定」→「Input Map」です。次の記事のInputMap管理ともつながるので、ここでは「スクリプト内にキーコードを直接書かない」ことだけ押さえてください。

Sponsored

実装例1: 移動とジャンプ

プラットフォーマーやトップダウンアクションでは、入力判定の使い分けがそのまま操作感になります。

移動はpressed、ジャンプはjust_pressed、短いジャンプはjust_releasedで扱う図

左右移動は押している間ずっと必要なので、Input.get_axis() を使います。ジャンプは押した瞬間だけなので、is_action_just_pressed() を使います。

extends CharacterBody2D

const SPEED := 260.0
const JUMP_VELOCITY := -420.0

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

func _physics_process(delta: float) -> void:
    if not is_on_floor():
        velocity.y += gravity * delta

    # ジャンプ開始は「押した瞬間」に1回だけ
    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 != 0.0:
        velocity.x = direction * SPEED
    else:
        velocity.x = move_toward(velocity.x, 0.0, SPEED)

    move_and_slide()

Input.get_axis("move_left", "move_right") は、左なら -1、右なら 1、何も押していなければ 0 を返すため、左右移動のような連続入力に向いています。

ここでジャンプに is_action_pressed("jump") を使うと、ボタンを押しっぱなしにして着地した瞬間、またジャンプが発生しやすくなります。ゲームによっては「押しっぱなし連続ジャンプ」を意図的に採用することもありますが、普通のジャンプ開始なら just_pressed が基本です。

実装例2: 可変ジャンプ

可変ジャンプは、ボタンを短く押すと低く跳び、長く押すと高く跳ぶ仕組みです。多くの2Dアクションで使われます。

考え方は次の通りです。

  1. 押した瞬間にジャンプを開始する
  2. 上昇中にボタンを離したら、上向き速度を弱める
  3. 押し続けた場合は、そのまま高く跳ぶ
extends CharacterBody2D

const SPEED := 260.0
const JUMP_VELOCITY := -420.0
const SHORT_JUMP_MULTIPLIER := 0.45

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

func _physics_process(delta: float) -> void:
    if not is_on_floor():
        velocity.y += gravity * 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.0:
        # 上昇中に離したら、上向き速度を弱めて低いジャンプにする
        velocity.y *= SHORT_JUMP_MULTIPLIER

    var direction := Input.get_axis("move_left", "move_right")
    velocity.x = direction * SPEED

    move_and_slide()

velocity.y < 0.0 を条件にしているのは、Godotの2Dでは上方向がマイナスだからです。落下中にジャンプボタンを離しても、もう上昇していないため短くする必要はありません。

この実装は小さく見えますが、操作感への影響は大きいです。プレイヤーが足場の手前で短く跳ぶ、敵を避けるために軽く跳ぶ、といった細かい調整ができるようになります。

Sponsored

実装例3: チャージ攻撃

チャージ攻撃は、3つの判定をかなり分かりやすく使います。

  • 押した瞬間: チャージ開始
  • 押している間: チャージ時間を増やす
  • 離した瞬間: 攻撃を発射する
押している間はチャージが続き、離すと発射するチャージ攻撃の入力タイムライン
extends Node2D

const MAX_CHARGE_TIME := 2.0

var is_charging := false
var charge_time := 0.0

func _process(delta: float) -> void:
    if Input.is_action_just_pressed("charge_attack"):
        # 押した瞬間にチャージ状態を初期化する
        is_charging = true
        charge_time = 0.0

    if is_charging and Input.is_action_pressed("charge_attack"):
        # 押している間だけチャージを進める
        charge_time = min(charge_time + delta, MAX_CHARGE_TIME)
        update_charge_effect(charge_time / MAX_CHARGE_TIME)

    if is_charging and Input.is_action_just_released("charge_attack"):
        # 離した瞬間に、溜めた量を使って攻撃する
        var power := charge_time / MAX_CHARGE_TIME
        fire_charge_shot(power)

        is_charging = false
        charge_time = 0.0
        update_charge_effect(0.0)

func update_charge_effect(rate: float) -> void:
    # 本番では色、拡大率、エフェクト量などを変える
    scale = Vector2.ONE * lerp(1.0, 1.4, rate)

func fire_charge_shot(power: float) -> void:
    print("fire power: %.2f" % power)

チャージ攻撃でよくある失敗は、is_action_pressed() だけで開始も発射も処理しようとすることです。押している間ずっと発射処理が走ったり、チャージ時間のリセットが毎フレーム起きたりします。

入力の状態を「開始」「継続」「終了」に分けると、コードもゲームの動きも読みやすくなります。

ポーリングとイベント駆動の使い分け

ここまで使ってきた Input.is_action_*()ポーリング です。毎フレーム「今この入力はどうなっているか」を確認します。

一方、Godotには _input(event)_unhandled_input(event) のような イベント駆動 の入力処理もあります。これは入力が発生したときにGodotから渡される InputEvent を処理する方式です。

_physics_processで毎フレーム確認するポーリングと、_unhandled_inputで入力時だけ処理するイベントの比較図
方法向いている処理
Input.is_action_*()毎フレーム状態を見たい処理移動、ジャンプ、チャージ、照準
_unhandled_input(event)入力が来た瞬間だけ扱いたい処理ポーズ、メニュー、UI外クリック

たとえばポーズメニューは、毎フレーム移動のように状態を見続ける必要はありません。入力イベントとして受け取ると自然です。

func _unhandled_input(event: InputEvent) -> void:
    if event.is_action_pressed("pause"):
        # UIに処理されなかったpause入力だけを拾う
        get_tree().paused = not get_tree().paused

_unhandled_input() は、Control系UIが先に入力を処理したあと、まだ処理されていない入力だけを受け取ります。ゲーム画面全体のキャンセルやポーズには便利です。

ただし、キャラクター移動のように「押され続けている状態」を毎フレーム使う処理は、_physics_process() でポーリングした方が分かりやすいです。

Sponsored

よくあるつまずき

決定ボタンにpressedを使ってメニューが連続で進む

UIの「決定」は、基本的に1回の入力です。is_action_pressed("ui_accept") を使うと、押しっぱなしの間ずっと決定処理が走ります。

# UIの決定は押した瞬間だけにする
if Input.is_action_just_pressed("ui_accept"):
    confirm_selected_item()

長押しで高速スクロールしたい場合は pressed を使うこともありますが、その場合は入力間隔を制御するタイマーを入れると暴走しにくくなります。

物理移動を_processに書いて挙動が揺れる

CharacterBody2Dvelocitymove_and_slide() を使う処理は、基本的に _physics_process() に書きます。物理更新と同じタイミングで動かすためです。

UI表示、チャージエフェクト、メニュー切り替えのように物理と直接関係しない処理は _process() でも構いません。

just_pressedを移動に使って一瞬しか動かない

左右移動や照準移動のように、押している間ずっと反応してほしい処理に just_pressed を使うと、入力開始の1回だけしか動きません。

「単発か、継続か」を先に決めると間違いにくいです。

操作判定
ジャンプ開始just_pressed
左右移動pressed / get_axis
チャージ中pressed
チャージ発射just_released
UI決定just_pressed
ドラッグ終了just_released

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

入力バッファやコヨーテタイムは次の段階

操作感をさらに良くするなら、ジャンプ入力を少しだけ保存する 入力バッファ や、足場から離れた直後でも少しだけジャンプを許す コヨーテタイム を使うことがあります。

ただし、これは just_pressed の代わりではありません。まず just_pressed で「押した瞬間」を正しく拾い、その入力を数フレーム保存する、という順番です。

キーボードは同時押しに限界がある

キーボードによっては、複数キーの同時押しで一部の入力が拾えないことがあります。これはコードのミスではなく、キーボード側の制約で起きる場合があります。

アクションゲームで斜め移動、ジャンプ、攻撃を同時に使う場合は、ゲームパッド対応やキー配置の見直しも考えると安全です。

入力名はゲームの意味で付ける

"space""left_click" のような物理キー名ではなく、"jump""attack""dash" のようなゲーム内の意味で名前を付けると、あとから入力方法を差し替えやすくなります。

まとめ

  • is_action_just_pressed() は、押した瞬間だけ。ジャンプ、攻撃開始、UI決定に使う
  • is_action_pressed() は、押している間ずっと。移動、長押し、チャージ中に使う
  • is_action_just_released() は、離した瞬間だけ。可変ジャンプ、チャージ解放、ドラッグ終了に使う
  • 物理移動は _physics_process()、メニューやポーズは _unhandled_input() も候補
  • 入力名はInputMapのアクション名で扱い、キーコードを直接書きすぎない

入力処理は地味ですが、ゲームの触り心地を決める重要な部分です。「押した瞬間」「押している間」「離した瞬間」を分けて考えるだけで、操作の意図がかなり読みやすくなります。

さらに学ぶために