Godotで作るFPSの移動とジャンプ:牛肉・豚肉・鶏肉・ジビエ情報
Godot Engine を用いて FPS(ファーストパーソン・シューター) ゲームを開発する上で、プレイヤーキャラクターの移動とジャンプはゲームプレイの根幹をなす要素です。これらのメカニクスをいかに自然かつ応答性良く実装できるかが、プレイヤーの没入感や操作感を大きく左右します。本稿では、Godot における FPS キャラクターの移動とジャンプの実装について、主要な概念から具体的なコード例、さらには応用的なテクニックまでを網羅的に解説します。
プレイヤーキャラクターのセットアップ
Godot で FPS キャラクターを実装する際の最も一般的なアプローチは、CharacterBody3D ノードを使用することです。これは、物理演算に基づいたキャラクターの移動と衝突判定を容易にするためのノードです。
CharacterBody3D ノードの基本
CharacterBody3D ノードは、その名前の通り、キャラクターの挙動を表現するために設計されています。移動の計算は、物理エンジンの影響を受けつつも、開発者がより直接的に制御できるように作られています。
- CollisionShape3D: キャラクターの当たり判定を定義します。CapsuleShape3D や BoxShape3D などがよく使用されます。
- Camera3D: プレイヤーの視点を担当します。通常、CharacterBody3D の子ノードとして配置され、キャラクターの頭部にあたる位置に設置します。
- MeshInstance3D (オプション): キャラクターの見た目を表します。FPS ではプレイヤー自身は見えない場合も多いですが、影や他のプレイヤーのためには必要になることがあります。
これらのノードを適切に階層化し、CharacterBody3D がルートノードとなるように構成します。
移動の実装
FPS の移動は、主にキーボード入力によって制御されます。ここでは、前後左右の移動と、マウスによる視点操作を組み合わせた実装方法を解説します。
入力処理
Godot の Input Map 機能を使用して、キーボードやマウスの入力を抽象化することが推奨されます。これにより、後からキーバインドを変更するのが容易になります。
- ui_up, ui_down, ui_left, ui_right: 前後左右の移動
- mouse_motion: マウスの移動(視点操作)
これらのアクションを Project Settings > Input Map で設定し、スクリプトから呼び出せるようにします。
移動ロジック
CharacterBody3D の move_and_slide() メソッドが、移動と衝突判定の核となります。このメソッドは、指定された速度ベクトルに基づいてキャラクターを移動させ、壁などに衝突した際には自動的にスライドさせます。
移動方向の計算は、入力されたキーの状態に応じて行われます。
# GDScript 例
extends CharacterBody3D
@export var speed = 5.0
@export var sensitivity = 0.002
var direction = Vector3.ZERO
var mouse_delta = Vector2.ZERO
func _physics_process(delta):
# 入力取得
var input_vector = Vector2.ZERO
if Input.is_action_pressed("ui_up"):
input_vector.y -= 1
if Input.is_action_pressed("ui_down"):
input_vector.y += 1
if Input.is_action_pressed("ui_left"):
input_vector.x -= 1
if Input.is_action_pressed("ui_right"):
input_vector.x += 1
# カメラの方向を基準に移動方向を計算
var camera_transform = get_viewport().get_camera_3d().get_global_transform()
direction = camera_transform.basis.x.normalized() * input_vector.x + camera_transform.basis.z.normalized() * input_vector.y
direction = direction.normalized()
# velocity の設定
velocity.x = direction.x * speed
velocity.z = direction.z * speed
velocity.y = move_and_slide().y # 重力とジャンプを考慮
上記のコードでは、camera_transform.basis を使用して、カメラの向いている方向を基準にした移動ベクトルを計算しています。これにより、プレイヤーは常にカメラが向いている方向に対して直感的に移動できます。
視点操作
マウスの移動をカメラの回転に反映させます。
func _input(event):
if event is InputEventMouseMotion:
mouse_delta = event.relative
# 水平方向の回転 (キャラクター全体)
rotate_y(-mouse_delta.x * sensitivity)
# 垂直方向の回転 (カメラのみ)
var camera = get_viewport().get_camera_3d()
camera.rotate_x(-mouse_delta.y * sensitivity)
# カメラの垂直方向の回転制限
camera.rotation.x = clamp(camera.rotation.x, deg_to_rad(-80), deg_to_rad(80))
水平方向の回転は CharacterBody3D 自体を回転させ、垂直方向の回転はカメラノードのみに適用します。これにより、FPS で一般的な、キャラクターは左右に曲がり、カメラは上下に視点を動かす操作が実現できます。回転角度に制限を設けることで、カメラが過度に上や下を向いてしまうのを防ぎます。
ジャンプの実装
ジャンプは、FPS における移動の多様性を高める重要な要素です。ここでは、単純なジャンプと、より物理に基づいたジャンプについて説明します。
ジャンプの基本
ジャンプは、キャラクターの垂直方向の速度(velocity.y)に上向きの力を加えることで実現します。
- jump_velocity: ジャンプの初速を設定する変数。
- is_on_floor(): キャラクターが地面に接地しているかを判定する CharacterBody3D のメソッド。
# 上記の _physics_process 関数に追加
# ジャンプ処理
if Input.is_action_just_pressed("jump") and is_on_floor():
velocity.y = jump_velocity
「jump」というアクションは、Project Settings > Input Map でスペースキーなどに割り当ててください。is_on_floor() を使用することで、空中で何度でもジャンプできてしまうのを防ぎます。
重力の実装
Godot の CharacterBody3D は、デフォルトで重力を適用する機能を持っています。しかし、より細かく制御したい場合は、明示的に重力を velocity.y に加算することも可能です。
# 上記の _physics_process 関数に追加 (velocity.y の更新部分)
if not is_on_floor():
velocity.y -= gravity * delta # gravity は Project Settings で定義するか、ここで直接指定
# velocity の設定 (ジャンプ処理の後に)
velocity.x = direction.x * speed
velocity.z = direction.z * speed
# velocity.y はジャンプ処理と重力処理で更新される
move_and_slide() # move_and_slide() を呼び出す前に velocity.y を確定させる
gravity は、Project Settings > Physics > 3D で設定されているグローバルな重力値を使用するか、あるいはキャラクターごとに独自の重力値を設定します。
応用的なテクニック
基本的な移動とジャンプを実装したら、さらにゲームプレイを豊かにするための応用的なテクニックを導入できます。
エアコントロール
空中で移動方向キーへの反応を一部許可することで、プレイヤーは空中での軌道修正が可能になります。これは、ジャンプ中の操作感を向上させます。
# _physics_process 関数内
if not is_on_floor():
# 空中での移動制限 (例: 地上速度の30%まで)
velocity.x = lerp(velocity.x, direction.x * speed, air_control * delta)
velocity.z = lerp(velocity.z, direction.z * speed, air_control * delta)
air_control は 0 から 1 の間の値で、空中での制御のしやすさを調整します。1 に近づくほど空中での操作性が向上します。
二段ジャンプ
一度ジャンプした後、空中で再度ジャンプボタンを押すと、さらに高くジャンプできる機能です。
# 新しい変数
var can_double_jump = false
# _physics_process 関数内 (ジャンプ処理部分)
if Input.is_action_just_pressed("jump"):
if is_on_floor():
velocity.y = jump_velocity
can_double_jump = true # 地面にいるときに二段ジャンプ可能にする
elif can_double_jump:
velocity.y = jump_velocity * 1.5 # 二段ジャンプは初速を少し増やすなど
can_double_jump = false # 二段ジャンプ後は不可にする
# is_on_floor() が true になったら can_double_jump をリセット
if is_on_floor():
can_double_jump = false
この例では、can_double_jump というフラグ変数を使用して、一度目のジャンプ後に二段ジャンプが可能になり、二段ジャンプ後はそれが無効になるように制御しています。地面に接地すると、再び二段ジャンプが可能になります。
ダッシュ
一定時間、移動速度を増加させるダッシュ機能は、FPS における移動のダイナミズムを増します。
@export var dash_speed_multiplier = 2.0
@export var dash_duration = 0.5
@export var dash_cooldown = 1.0
var is_dashing = false
var dash_timer = 0.0
var dash_cooldown_timer = 0.0
# _physics_process 関数内 (移動処理部分)
var current_speed = speed
if is_dashing:
current_speed = speed * dash_speed_multiplier
dash_timer -= delta
if dash_timer <= 0:
is_dashing = false
# ダッシュ入力
if Input.is_action_just_pressed("dash") and dash_cooldown_timer 0:
dash_cooldown_timer -= delta
# velocity の設定 (current_speed を使用)
velocity.x = direction.x * current_speed
velocity.z = direction.z * current_speed
velocity.y = move_and_slide().y
「dash」アクションを定義し、ボタンが押されたらダッシュ状態にし、タイマーで持続時間とクールダウンを管理します。ダッシュ中は移動速度を一時的に増加させます。
まとめ
Godot Engine を使用した FPS キャラクターの移動とジャンプの実装は、CharacterBody3D ノードを中心に行われます。move_and_slide() メソッドを理解し、入力処理と物理演算を適切に組み合わせることが重要です。視点操作では、カメラとキャラクターの回転を分離し、没入感のある操作感を目指します。ジャンプ、エアコントロール、二段ジャンプ、ダッシュなどの応用的なテクニックを導入することで、ゲームプレイの幅が大きく広がります。これらの要素を丁寧に実装することで、プレイヤーが快適に操作でき、ゲームの世界に没入できる FPS 体験を提供できるでしょう。
