はじめに
3Dゲームでプレイヤーキャラクターを操作し、走ったりジャンプしたりさせるにはどうするのでしょう?その答えがCharacterBody3Dです。この記事では、3D空間での移動、重力、ジャンプの実装から、FPS・TPS視点での操作まで解説します。
この記事を読むことで、3D移動の基本、床判定、壁の衝突判定、そして実践的なゲームの操作が身につきます。

CharacterBody3Dとは?
CharacterBody3Dは、3D空間でプレイヤーキャラクターを操作するための物理ボディノードです。2Dの CharacterBody2D に相当し、移動・重力・ジャンプの実装に特化しています。
CharacterBody3Dは「プレイヤーキャラクターの体」です。ユーザー入力を受け取り、床との接触を判定し、自然な動きを実現します。
継承ツリー:
CharacterBody3D
├── PhysicsBody3D
│ ├── CollisionObject3D
│ │ ├── Node3D
│ │ │ └── Node
│ │ └── ...
│ └── ...
└── ...
このノードを使うべき場面
CharacterBody3Dを使う場面:
- プレイヤーキャラクターの移動(WASD、アナログスティック)
- 重力の実装と床への着地判定
- ジャンプ・落下の物理演算
- FPS・TPS視点でのキャラクター操作
- 敵キャラクターの移動(AI制御)
CharacterBody3Dを使わない場面:
- 完全に静止したオブジェクト → StaticBody3D を使う
- リアルな物理演算が必要(重い木箱が落ちるなど) → RigidBody3D を使う
- 単なる衝突判定のみ → Area3D を使う
主なプロパティと機能
| プロパティ | 型 | 説明 |
|---|---|---|
velocity |
Vector3 | 現在の速度ベクトル。(x, y, z) で各軸の速度を表現 |
floor_max_angle |
float | 床と見なす傾斜角度の上限。デフォルト45度 |
floor_snap_length |
float | 床から若干浮いた状態を「着地」と見なす距離 |
floor_constant_speed |
bool | 傾斜地でも一定の速度を保つ |
up_direction |
Vector3 | 上方向。通常 Vector3.UP = (0, 1, 0) |
motion_mode |
MotionMode | GROUNDED(地面ベース)か FLOATING(浮遊ベース) |
slide_on_ceiling |
bool | 天井に触れたとき、滑るように移動 |
重要メソッド:
# 移動を実行(キャラクターのコリジョンに基づいて)
move_and_slide()
# 床に着地しているか判定
is_on_floor() -> bool
# 壁に接触しているか判定
is_on_wall() -> bool
# 天井に接触しているか判定
is_on_ceiling() -> bool
# 床との衝突情報を取得
get_floor_normal() -> Vector3
# 移動時の衝突回数を取得
get_slide_collision_count() -> int
コード例1:基本的な3D移動(WASD + 重力 + ジャンプ)
extends CharacterBody3D
@export var move_speed: float = 5.0
@export var jump_force: float = 10.0
@export var gravity: float = 20.0
func _process(delta: float) -> void:
# 入力を取得
var input_dir = Input.get_vector("ui_left", "ui_right", "ui_up", "ui_down")
# キャラクターの前方を基準に移動方向を計算
var forward = -global_transform.basis.z # 前方(Z軸負方向)
var right = global_transform.basis.x # 右方向
var move_dir = (forward * input_dir.y + right * input_dir.x).normalized()
# 水平方向の速度を設定
velocity.x = move_dir.x * move_speed
velocity.z = move_dir.z * move_speed
# 重力を適用
if not is_on_floor():
velocity.y -= gravity * delta
# ジャンプ
if Input.is_action_just_pressed("ui_accept") and is_on_floor():
velocity.y = jump_force
# 実際に移動
move_and_slide()
コード例2:FPS視点での操作(マウスルック + キャラクター移動)
extends CharacterBody3D
@export var move_speed: float = 5.0
@export var jump_force: float = 10.0
@export var gravity: float = 20.0
@export var mouse_sensitivity: float = 0.005
@onready var camera = $Camera3D # Camera3D を子ノードとして配置
var camera_x_rotation: float = 0.0
func _ready() -> void:
# マウスをロック(ゲーム中は操作画面から出ない)
Input.mouse_mode = Input.MOUSE_MODE_CAPTURED
func _process(delta: float) -> void:
# 入力を取得(カメラ方向を基準)
var input_dir = Input.get_vector("ui_left", "ui_right", "ui_up", "ui_down")
var forward = -global_transform.basis.z
var right = global_transform.basis.x
var move_dir = (forward * input_dir.y + right * input_dir.x).normalized()
velocity.x = move_dir.x * move_speed
velocity.z = move_dir.z * move_speed
# 重力とジャンプ
if not is_on_floor():
velocity.y -= gravity * delta
if Input.is_action_just_pressed("ui_accept") and is_on_floor():
velocity.y = jump_force
move_and_slide()
func _input(event: InputEvent) -> void:
# マウス移動でカメラを回転
if event is InputEventMouseMotion:
var mouse_motion = event as InputEventMouseMotion
# Y軸周りに回転(左右の視点)
rotate_y(-mouse_motion.relative.x * mouse_sensitivity)
# X軸周りに回転(上下の視点)
camera_x_rotation -= mouse_motion.relative.y * mouse_sensitivity
camera_x_rotation = clamp(camera_x_rotation, -PI / 2, PI / 2)
camera.rotation.x = camera_x_rotation
# Escキーでマウスロック解除
if event.is_action_pressed("ui_cancel"):
Input.mouse_mode = Input.MOUSE_MODE_VISIBLE

もっと使いこなす:カスタマイズできるパラメータ
まずは基本を動かしてみてから、余裕が出たら試してみてください。
| パラメータ | 型 | 説明 |
|---|---|---|
velocity.y |
float | Y軸(上下)の速度。重力とジャンプで制御 |
floor_block_on_wall |
bool | 壁に沿って登りながら移動するのを防ぐ |
platform_on_leave |
PlatformOnLeave | 移動している床から離れたときの挙動 |
get_last_motion() |
Vector3 | 前フレームの実際の移動量を取得 |
get_collision_normal() |
Vector3 | 衝突面の法線ベクトルを取得 |
set_velocity() |
void | 次フレームの速度を明示的に設定 |
velocity_to_direction() |
Vector3 | 速度から移動方向を正規化して取得 |
まとめ
CharacterBody3Dは、3Dゲームのプレイヤー操作の中心となるノードであり、velocity・move_and_slide()・床判定の3つの要素で、自然で快適な移動が実現できるノードです。
- velocity で現在の速度を管理し、move_and_slide() で実際の移動を実行
- is_on_floor()・is_on_wall()・is_on_ceiling() で環境判定を行い、リアルな動きを表現
- FPS・TPS両方の視点に対応でき、キャラクターの向きを基準とした相対的な移動が可能
次回は、固定されたオブジェクト用の物理ボディ、StaticBody3Dについて解説します。

シリーズ:Godot 4 ノード解説
001〜040:各種ノード
- 001 Node2D
- 002 Sprite2D
- 003 AnimatedSprite2D
- 004 Label
- 005 Button
- 006 TextEdit
- 007 Panel
- 008 VBoxContainer / HBoxContainer
- 009 TabContainer
- 010 OptionButton
- 011 CheckBox
- 012 Slider
- 013 LineEdit
- 014 RichTextLabel
- 015 Control
- 016 NinePatchRect
- 017 TextureRect
- 018 ItemList
- 019 Tree
- 020 ColorPickerButton
- 021 Timer
- 022 AudioStreamPlayer / AudioStreamPlayer2D
- 023 Marker2D
- 024 Area2D
- 025 CharacterBody2D
- 026 RigidBody2D
- 027 StaticBody2D
- 028 TileMap
- 029 Camera2D
- 030 CollisionShape2D
- 031 Polygon2D
- 032 Line2D
- 033 ParticleSystem2D / CPUParticles2D
- 034 CanvasLayer
- 035 Sprite3D
- 036 SubViewport
- 037 MultiplayerSpawner
- 038 RemoteTransform2D
- 039 NavigationAgent2D
- 040 VisibleOnScreenNotifier2D
- 051 Node3D
- 052 MeshInstance3D
- 053 Camera3D
- 054 DirectionalLight3D
- 055 CharacterBody3D
この記事はGodot 4.xをもとに執筆しています。


コメント