横移動とジャンプまでは作れたけど、「滑空」みたいなちょっとしたアクションを入れようとすると、Player.gd がどんどん太っていきますよね。
Godot標準のチュートリアルに従うと、CharacterBody2D を継承した巨大プレイヤースクリプトを育てがちで、
- ジャンプ、ダッシュ、二段ジャンプ、滑空…全部1ファイルに詰め込みがち
- 敵や動く床にも「ちょっとだけ似たロジック」をコピペして地獄
- プレイヤー固有の機能と、汎用的な「空中制御」がごちゃ混ぜ
こうなると、ちょっと挙動を変えたいだけでも怖くて触れなくなります。
そこで今回は、プレイヤー側にほぼ手を入れず「コンポーネントを1個アタッチするだけ」で滑空を実現する 「Glider」コンポーネント を作っていきましょう。
ポイントは:
- プレイヤーは「ただの移動用スクリプト」にしておく
- 滑空の判定・物理・入力は全部
Gliderコンポーネントに閉じ込める EnemyやMovingPlatformにも、同じコンポーネントをポン付けできる
「継承より合成」で、Godotのシーンをスッキリさせていきましょう。
【Godot 4】フワッと落ちてスイスイ進む!「Glider」コンポーネント
コンポーネントの前提
このコンポーネントは、次のような「ホスト」ノードにアタッチして使う想定です:
CharacterBody2DまたはCharacterBody3Dではなく、今回は 2D専用 とします(簡潔のため)。- ホスト側(例: Player)は
velocity: Vector2を持っている(CharacterBody2D標準フィールド)。 - 横移動の入力はホスト側で行ってもOKですが、滑空中だけ横速度を上書き/補正 します。
GDScript フルコード
## Glider.gd
## 空中でボタン押しっぱなしの間、落下速度を制限しつつ横移動を強化するコンポーネント。
## CharacterBody2D にアタッチして使います。
class_name Glider
extends Node
## --- 設定パラメータ(インスペクタで調整可能) ---
@export_group("入力設定")
## 滑空に使うアクション名(InputMap で定義しておく)
@export var glide_action_name: String = "glide"
@export_group("滑空物理設定")
## 滑空中の最大落下速度(絶対値)。通常の重力よりもかなり小さめに。
@export var max_fall_speed: float = 80.0
## 滑空開始に必要な最低落下速度(これより上向きだと滑空しない)
## 例: 0 以下なら「完全に上昇が止まるまでは滑空しない」
@export var min_downward_speed_to_start: float = 0.0
## 滑空中に適用する「疑似重力」係数(0 に近いほど落ちない)
@export_range(0.0, 1.0, 0.05)
@export var glide_gravity_factor: float = 0.2
@export_group("横移動ブースト")
## 滑空中に上書きする横速度の絶対値(0以下なら「いじらない」)
@export var glide_horizontal_speed: float = 220.0
## 滑空中の横移動の加速の速さ(補間係数)
@export_range(0.0, 1.0, 0.05)
@export var glide_horizontal_lerp: float = 0.2
@export_group("その他")
## 地面に着地したら自動的に滑空を解除するか
@export var auto_cancel_on_floor: bool = true
## デバッグ用: 現在滑空中かどうかをインスペクタで確認できる
@export var debug_is_gliding: bool = false:
set(value):
debug_is_gliding = value
## --- 内部状態 ---
var _host_body: CharacterBody2D
var _is_gliding: bool = false
func _ready() -> void:
## 親が CharacterBody2D であることを確認
_host_body = get_parent() as CharacterBody2D
if _host_body == null:
push_warning("Glider コンポーネントは CharacterBody2D の子として使ってください。")
set_process(false)
return
set_process(true)
func _process(delta: float) -> void:
if _host_body == null:
return
## 地面に着地しているなら滑空終了
if auto_cancel_on_floor and _host_body.is_on_floor():
_set_gliding(false)
return
## 空中でのみ滑空を許可
if _host_body.is_on_floor():
_set_gliding(false)
return
## 入力状態
var glide_pressed := Input.is_action_pressed(glide_action_name)
if glide_pressed:
## 滑空開始条件を満たしているか?
if not _is_gliding:
_try_start_glide()
## すでに滑空中なら物理補正を行う
if _is_gliding:
_apply_glide_physics(delta)
else:
## ボタンを離したら終了
_set_gliding(false)
func _try_start_glide() -> void:
## まだ地面にいるなら滑空しない
if _host_body.is_on_floor():
return
## 上向きに強く飛んでいる間は滑空開始しない(好みで調整)
if _host_body.velocity.y < min_downward_speed_to_start:
return
_set_gliding(true)
func _apply_glide_physics(delta: float) -> void:
var v := _host_body.velocity
## --- 縦方向(落下)の制御 ---
## 通常の重力がどこか別で適用されている前提で、
## ここでは「最大落下速度を制限しつつ、疑似的に減速」させるイメージ。
## 例: v.y が 300 とかになっても、max_fall_speed 付近まで抑える。
# 落下速度を max_fall_speed までにクランプ
if v.y > max_fall_speed:
v.y = lerp(v.y, max_fall_speed, glide_gravity_factor)
## --- 横方向のブースト ---
if glide_horizontal_speed > 0.0:
## 入力方向を取得(左右キーなど)
var input_dir := Input.get_axis("move_left", "move_right")
if input_dir != 0.0:
var target_speed := glide_horizontal_speed * sign(input_dir)
v.x = lerp(v.x, target_speed, glide_horizontal_lerp)
## 入力が 0 のときは、ホスト側の処理に任せる(惰性で流れるなど)
_host_body.velocity = v
func _set_gliding(value: bool) -> void:
if _is_gliding == value:
return
_is_gliding = value
debug_is_gliding = value
## 将来的にアニメーションやSEをここでトリガーすると便利
## 例:
## if value:
## _play_glide_start_effect()
## else:
## _play_glide_end_effect()
## --- 参考: 外部から状態を参照したいとき用のAPI ---
func is_gliding() -> bool:
return _is_gliding
使い方の手順
手順①:InputMap にアクションを追加
- Godot のメニューから「Project > Project Settings」を開く。
Input Mapタブを開き、glideというアクションを追加。- キーボードなら
ShiftやSpace、ゲームパッドならButton Bなど好みのボタンを割り当て。 - すでに
move_left/move_rightがある前提で進めます。
手順②:プレイヤーシーンにコンポーネントをアタッチ
例えば、こんなプレイヤーシーンを用意します:
Player (CharacterBody2D) ├── Sprite2D ├── CollisionShape2D └── Glider (Node) ← このノードに Glider.gd をアタッチ
Player(CharacterBody2D)の子にNodeを追加し、名前をGliderに変更。- その
Gliderノードに、先ほどのGlider.gdをアタッチ。 - インスペクタでパラメータを調整:
glide_action_name = "glide"max_fall_speed = 80(ふわっと落ちる感じ)glide_horizontal_speed = 220(通常より少し速め)
手順③:Player 側は「普通の移動処理」のままでOK
プレイヤーのスクリプトは、いつも通り CharacterBody2D ベースで構いません。
滑空のロジックはすべて Glider コンポーネントが担当するので、Player 側には特別なコードは不要です。
## Player.gd(例)
extends CharacterBody2D
@export var move_speed: float = 160.0
@export var jump_speed: float = -320.0
@export var gravity: float = 900.0
func _physics_process(delta: float) -> void:
var input_dir := Input.get_axis("move_left", "move_right")
## 横移動(Glider はここに上書きで干渉してくるだけ)
velocity.x = input_dir * move_speed
## 重力
if not is_on_floor():
velocity.y += gravity * delta
else:
## ジャンプ
if Input.is_action_just_pressed("jump"):
velocity.y = jump_speed
move_and_slide()
この状態でゲームを実行すると:
- ジャンプしてから空中で
glideアクションを押しっぱなしにすると、落下がかなりゆっくりになる - 同時に左右キーを押していると、滑空中だけ横移動がスイスイ速くなる
- 地面に着地するか、ボタンを離すと滑空終了
手順④:敵や動く床にも「滑空」を付けてみる例
コンポーネントなので、プレイヤー以外にも同じものを簡単に付けられます。例えば、空中をフワフワ移動する敵:
FlyingEnemy (CharacterBody2D) ├── Sprite2D ├── CollisionShape2D └── Glider (Node)
FlyingEnemy.gd で velocity を適当に制御しつつ、Glider の glide_horizontal_speed を高めに設定すれば、
「一定高度からあまり落ちずに、横に高速で滑空する敵」などを作れます。
プレイヤー専用のロジックを一切コピペしていないのがポイントですね。
メリットと応用
この「Glider」コンポーネントを使うことで:
- Player.gd が細くなる
滑空ロジックが完全に別ファイルに分離され、プレイヤー本体は「移動」と「ジャンプ」だけに集中できます。 - シーン構造がフラットで見やすい
「Glider付きプレイヤー」「Glider付き敵」「Glider付き動く床」など、
どのノードがどんな能力を持っているか、シーンツリーを見れば一目瞭然になります。 - パラメータ違いの再利用がしやすい
プレイヤー用、敵用、ギミック用などでmax_fall_speedやglide_horizontal_speedを変えるだけで、
同じコンポーネントから多様な挙動を生み出せます。 - テストやデバッグが楽
debug_is_glidingを見れば状態が一発で分かるので、パラメータ調整もしやすいです。
「継承で PlayerGlide, PlayerDoubleJump と増やす」のではなく、
「Glider コンポーネントをアタッチするだけ」という発想に切り替えると、
プロジェクトが大きくなっても管理がかなり楽になります。
改造案:滑空開始時に縦速度を即座にリセットする
「滑空ボタンを押した瞬間に、ストンと落ちていた速度を一気に殺したい」場合は、
_try_start_glide() を次のように改造してみると分かりやすいです:
func _try_start_glide() -> void:
if _host_body.is_on_floor():
return
## 上方向に飛んでいる最中でも、即座に滑空したい場合はこの条件を外す
# if _host_body.velocity.y < min_downward_speed_to_start:
# return
_set_gliding(true)
## 縦速度を即座に「滑空用の最大値」にリセット
if _host_body.velocity.y > max_fall_speed:
_host_body.velocity.y = max_fall_speed
これで、「落ち始めてからグライドすると、ガクッと減速してふわっと落ちる」気持ちいい挙動になります。
このように、コンポーネント単体をいじるだけでゲーム全体の滑空挙動を統一して変えられるのも、合成スタイルの強みですね。




