はじめに
TPSゲームやアクション系ゲームでカメラを操作するとき、壁の中にカメラが埋まってしまった経験はありませんか?SpringArm3Dはそのような問題を自動的に解決してくれるノードです。このノードを使えば、キャラクターの背後からカメラが常に見やすい位置に自動調整されます。
SpringArm3Dとは?
SpringArm3Dは、カメラがキャラクターや障害物に埋まらないようにするTPS・アクションカメラ用のノードです。スプリングアーム(腕)が障害物を検出すると、自動的にカメラを手前に引き寄せます。
継承ツリー:
SpringArm3D ↓ Node3D ↓ Node

このノードを使うべき場面
使うべき場面:
- Third Person Shooter(TPS)・アクションゲームのカメラ制御
- アクションRPGの背後視点カメラ
- 探索ゲームで狭い屋内での移動時のカメラ調整
- キャラクターとカメラ間の距離を一定に保ちながら柔軟に対応する必要があるゲーム
- 壁や天井などの障害物に埋まるカメラの問題を解決したい場合
使わない場面:
- FPS(一人称視点)ゲーム(直接Camera3Dを配置すれば十分)
- 固定カメラまたは自動カメラパス追従
主なプロパティと機能
| プロパティ | 型 | 説明 | 使用例 |
|---|---|---|---|
spring_length |
float | アームの最大長さ(m)。カメラとキャラクターの基本距離 | spring_arm.spring_length = 5.0 |
shape |
Shape3D | 障害物判定に用いる形状(SphereShape3D、CapsuleShape3D等) | spring_arm.shape = SphereShape3D.new() |
collision_mask |
int | どのフィジクスレイヤーの障害物を判定するか | spring_arm.collision_mask = 0b0001 |
margin |
float | カメラと障害物の間隔マージン(m) | spring_arm.margin = 0.3 |
重要メソッド
| メソッド | 戻り値 | 説明 | 使用例 |
|---|---|---|---|
get_hit_length() |
float | 現在のアーム長(障害物がある場合は短縮された長さ) | var current_len = spring_arm.get_hit_length() |
GDScriptコード例1:基本的なTPSカメラセットアップ
extends Node3D
@onready var character = $Character # CharacterBody3Dなど
@onready var spring_arm = $Character/SpringArm3D
@onready var camera = $Character/SpringArm3D/Camera3D
@export var mouse_sensitivity = 0.005
@export var spring_length = 5.0
func _ready():
# SpringArm3Dの設定
spring_arm.spring_length = spring_length
# 障害物検出用の形状を設定(球形)
var sphere_shape = SphereShape3D.new()
sphere_shape.radius = 0.5
spring_arm.shape = sphere_shape
# カメラが壁との間に最小0.3m離れるよう設定
spring_arm.margin = 0.3
Input.mouse_mode = Input.MOUSE_MODE_CAPTURED
func _physics_process(delta):
# カメラの回転をマウス入力で制御
var mouse_motion = Input.get_last_mouse_velocity()
# Y軸周りの回転(上下)
spring_arm.rotate_y(-mouse_motion.x * mouse_sensitivity * delta)
# X軸周りの回転(左右)。ピッチ制限を加える
var pitch = spring_arm.rotation.x
pitch -= mouse_motion.y * mouse_sensitivity * delta
pitch = clamp(pitch, -PI / 2, PI / 2)
spring_arm.rotation.x = pitch
# 現在のアーム長を表示(デバッグ用)
var current_length = spring_arm.get_hit_length()
print("カメラ距離: %.2f m" % current_length)
GDScriptコード例2:キャラクターの移動とカメラの連携
extends CharacterBody3D
@onready var spring_arm = $SpringArm3D
@export var move_speed = 7.0
@export var spring_arm_height = 1.7
func _ready():
# SpringArm3D初期設定
spring_arm.position.y = spring_arm_height # 目の高さ
spring_arm.spring_length = 4.5
var sphere = SphereShape3D.new()
sphere.radius = 0.4
spring_arm.shape = sphere
func _physics_process(delta):
# キャラクター移動
var input_dir = Input.get_vector("ui_left", "ui_right", "ui_up", "ui_down")
var direction = (transform.basis * Vector3(input_dir.x, 0, input_dir.y)).normalized()
if direction:
velocity.x = direction.x * move_speed
velocity.z = direction.z * move_speed
else:
velocity.x = move_toward(velocity.x, 0, move_speed)
velocity.z = move_toward(velocity.z, 0, move_speed)
# キャラクターの向きをカメラ方向に合わせる
if direction:
look_at(global_position + direction, Vector3.UP)
velocity.y -= 9.8 * delta
velocity = move_and_slide(velocity)
もっと使いこなす:カスタマイズできるパラメータ
まずは基本を動かしてみてから、余裕が出たら試してみてください。
| パラメータ | 型 | 説明 | 実装例 |
|---|---|---|---|
position(継承) |
Vector3 | キャラクター相対でのアームの起点位置 | spring_arm.position = Vector3(0, 1.7, 0) |
rotation(継承) |
Vector3 | アームの向き(ラジアン) | spring_arm.rotation.x = -PI / 6 # 仰角 |
collision_group |
int | 自身が属するフィジクスグループ | spring_arm.collision_group = 0b0001 |
exclude_parent |
bool | 親ノード(キャラクター)を障害物判定から除外するか | spring_arm.exclude_parent = true(通常true) |
shape(複数形状) |
Shape3D | CapsuleShape3Dなら狭い通路でも対応 | var capsule = CapsuleShape3D.new(); capsule.radius = 0.3; capsule.height = 0.6 |
カスタマイズの実装例:複数カメラ距離のプリセット
extends Node3D
@onready var spring_arm = $Character/SpringArm3D
var camera_distances = {
"close": 2.0,
"normal": 5.0,
"far": 8.0
}
var current_distance = "normal"
func _ready():
set_camera_distance(current_distance)
func _process(delta):
# 数字キーでカメラ距離を切り替え
if Input.is_action_just_pressed("ui_1"):
set_camera_distance("close")
elif Input.is_action_just_pressed("ui_2"):
set_camera_distance("normal")
elif Input.is_action_just_pressed("ui_3"):
set_camera_distance("far")
func set_camera_distance(preset_name: String):
if preset_name in camera_distances:
current_distance = preset_name
spring_arm.spring_length = camera_distances[preset_name]
print("カメラ距離: %s (%.1f m)" % [preset_name, camera_distances[preset_name]])
まとめ
SpringArm3Dは、TPS・アクションゲームのカメラ制御を劇的に改善する必須ノードです。
- カメラが壁や障害物に埋まる問題を自動的に解決します
- spring_lengthとshapeプロパティを調整するだけで、ゲーム特性に合ったカメラ距離を実現できます
- get_hit_length()で現在のカメラ距離を取得し、UI表示やエフェクト制御に活用できます
次回は、視線判定に必須の「RayCast3D」について詳しく解説します。
シリーズ:Godot 4 ノード解説
001~040:各種ノード
041~080:
041: Marker3D | 042: Node3D | 043: Camera3D | 044: Light3D | 045: MeshInstance3D |
046: AnimationPlayer | 047: AnimationTree | 048: Skeleton3D | 049: IKSkeleton3D | 050: Skin |
051: CollisionShape3D | 052: RigidBody3D | 053: CharacterBody3D | 054: StaticBody3D | 055: Area3D |
056: PhysicsDirectSpaceState3D | 057: ShapeCast3D | 058: RayCast3D | 059: Decal | 060: GPUParticles3D |
061: CPUParticles3D | 062: WorldEnvironment | 063: OmniLight3D | 064: SpotLight3D | 065: DirectionalLight3D |
066: ReflectionProbe | 067: LightmapGI | 068: VoxelGI | 069: Occluder3D | 070: VisualInstance3D |
071: BoneAttachment3D | 072: VehicleBody3D | 073: SpringArm3D | 074: RayCast3D | 075: ShapeCast3D |
076: MultiMeshInstance3D | 077: Node | 078: CanvasLayer | 079: Control | 080: Label
この記事はGodot 4.xをもとに執筆しています。


コメント