Godot 4のコンポーネント指向開発シリーズ、**「WallClimber (壁登り)」**です。
通常のアクションゲームでは壁にぶつかると落ちてしまいますが、このコンポーネントをつけると壁に張り付いて上下に移動できる(ロックマンXや忍者ゲームのような)挙動を追加できます。
このコンポーネントは、親ノードが「壁に接触している」ことを検知すると、重力による落下を強制的に無効化し、代わりに上下入力による移動を適用します。
1. コンポーネントのコード (Full Code)
以下のコードをコピーして、WallClimber.gd という名前で保存してください。
class_name WallClimber
extends Node
## 壁に接触中、重力を無効化して上下移動を可能にするコンポーネント
## 動作前提: 親ノードが CharacterBody2D であること。
## 注意: 重力コンポーネントよりも「後」に処理されることが望ましいです。
# --- 設定パラメータ ---
@export_group("Climb Settings")
@export var climb_speed: float = 150.0 ## 壁を登る/降りる速度
@export var action_up: String = "ui_up" ## 上移動キー
@export var action_down: String = "ui_down" ## 下移動キー
# --- 内部変数 ---
var _parent: CharacterBody2D
func _ready() -> void:
_parent = get_parent() as CharacterBody2D
if not _parent:
push_error("WallClimber: 親ノードがCharacterBody2Dではありません。")
set_physics_process(false)
func _physics_process(_delta: float) -> void:
# 壁に接触していなければ何もしない(重力に任せる)
if not _parent.is_on_wall():
return
# 入力を取得 (-1: 上, 1: 下, 0: なし)
var input_axis = Input.get_axis(action_up, action_down)
if input_axis != 0:
# 入力がある場合:上下に移動させる
_parent.velocity.y = input_axis * climb_speed
else:
# 入力がない場合:その場に留まる(重力を打ち消して静止)
# ※少しだけ滑り落ちたい場合は = 10.0 などに設定してください
_parent.velocity.y = 0
2. 使い方チュートリアル
このコンポーネントは、「重力コンポーネント」と喧嘩(競合)しないように配置するのがコツです。
手順①:プレイヤーとステージの準備
CharacterBody2Dのプレイヤーを用意します。CollisionShape2D(四角形など)を設定します。- 壁(StaticBody2D) をシーン内に配置し、プレイヤーが横からぶつかれるようにします。
手順②:コンポーネントの配置順序(重要!)
Godotのノード処理は「上から下」へ順番に行われます。
「重力で落とす処理」のあとに「壁登りで支える処理」を行いたいので、WallClimberはGravityComponentより下に配置してください。
推奨されるシーン構成:
Plaintext
Player (CharacterBody2D)
├── Sprite2D
├── CollisionShape2D
├── KeyboardMover (横移動)
├── GravityComponent (重力) <-- 先に「落とす」計算をする
└── WallClimber (壁登り) <-- 後から「壁なら落ちない!」と上書きする
※このように配置することで、壁にいる間だけ重力をキャンセルできます。
手順③:実行と操作
ゲームを実行し、以下の操作を行ってください。
KeyboardMover(左右キー)を使って壁に向かって押し付けます。- 重要: Godotの仕様上、「壁の方へ移動入力」をしていないと
is_on_wall()が判定外れることがあります。
- 重要: Godotの仕様上、「壁の方へ移動入力」をしていないと
- 壁にぶつかっている状態で、上下キーを押します。
- 重力に逆らってスルスルと壁を登れば成功です!
3. 挙動の調整テクニック
壁キック(三角飛び)の実装ヒント
このコンポーネントは「登る」ことだけを担当していますが、壁キックを実装したい場合は、以前紹介した JumpController と組み合わせることができます。
JumpController のコードを少し改造し、「床にいる時」だけでなく**「壁にいる時」**もジャンプ許可を出せば、それがそのまま壁キックになります。
GDScript
# JumpControllerの改造案
func _physics_process(delta):
# 床 または 壁 に接触しているならジャンプ可能
if Input.is_action_just_pressed(jump_action):
if _parent.is_on_floor() or _parent.is_on_wall():
_parent.velocity.y = jump_velocity
# 壁キックのときは横方向にも跳ね返らせるとカッコいい
if _parent.is_on_wall():
var wall_normal = _parent.get_wall_normal()
_parent.velocity.x = wall_normal.x * 300 # 壁と逆に弾く
アニメーションとの連携
壁登り中に「しがみつく画像」を表示したい場合、スプライト管理スクリプト(またはAnimationTree)で以下のようにチェックします。
if is_on_wall() and not is_on_floor():
play_animation("Climb")
このように、移動ロジック(WallClimber)と見た目のロジックを分離しておくことで、コードの見通しが非常に良くなります。
