はじめに
FPS視点で銃を撃つとき、照準が何を指しているかを判定したいですよね。または、キャラクターが立っている地面を検出したい、壁が目の前にあるかチェックしたい、そんな場面で活躍するのがRayCast3Dです。このノードは特定方向に光線を飛ばして、最初に当たったオブジェクトを瞬時に検出します。
RayCast3Dとは?
RayCast3Dは、特定方向に光線(レイ)を飛ばして、最初に当たったオブジェクトを検出するノードです。2DゲームのRayCast2Dの3D版で、视线判定・射撃・地面感知など、多くのゲーム機構に必要な「何が見えているか」「何に当たるか」を調べます。
継承ツリー:
RayCast3D ↓ Node3D ↓ Node

このノードを使うべき場面
使うべき場面:
- FPS・TPSゲームの銃砲撃撃時の判定(何に当たったか)
- キャラクターの足元が地面に着いているかを検出(落下判定)
- 壁や障害物がキャラクターの目の前にあるか確認(視線チェック)
- レーダーやスキャナーの敵検出機能
- インタラクション可能なオブジェクトが視野内にあるか判定(ピックアップアイテム検出)
使わない場面:
- 広い範囲の複数オブジェクト検出(ShapeCast3Dやconvex_shape_queryを使用)
- 物理ボディの常時衝突判定(PhysicsDirectSpaceState3Dのクエリ系メソッド)
主なプロパティと機能
| プロパティ | 型 | 説明 | 使用例 |
|---|---|---|---|
enabled |
bool | RayCast3Dの判定を有効にするか | raycast.enabled = true |
target_position |
Vector3 | ノード相対での光線の終点(ローカル座標) | raycast.target_position = Vector3(0, 0, -100) |
collision_mask |
int | どのフィジクスレイヤーを検出するか | raycast.collision_mask = 0b0011 |
exclude_parent |
bool | 親ノードを判定から除外するか | raycast.exclude_parent = true |
hit_from_inside |
bool | 形状の内側からの検出を許可するか | raycast.hit_from_inside = false |
重要メソッド
| メソッド | 戻り値 | 説明 | 使用例 |
|---|---|---|---|
is_colliding() |
bool | 何かに衝突しているか | if raycast.is_colliding(): |
get_collider() |
Node | 衝突したノード | var obj = raycast.get_collider() |
get_collision_point() |
Vector3 | 衝突した世界座標 | var point = raycast.get_collision_point() |
get_collision_normal() |
Vector3 | 衝突面の法線ベクトル | var normal = raycast.get_collision_normal() |
force_raycast_update() |
void | 直ちに判定を更新(同フレーム内での判定を即座に取得) | raycast.force_raycast_update() |
GDScriptコード例1:FPS射撃の実装
extends Node3D
@onready var raycast = $Camera3D/RayCast3D
@export var damage = 10.0
@export var fire_distance = 1000.0
func _ready():
# RayCast3Dを画面中央から前方へ向ける
raycast.target_position = Vector3(0, 0, -fire_distance)
raycast.enabled = true
func _process(delta):
if Input.is_action_just_pressed("ui_accept"): # スペースキー射撃
shoot()
func shoot():
print("射撃!")
# 照準が敵に当たっているか確認
if raycast.is_colliding():
var collider = raycast.get_collider()
var collision_point = raycast.get_collision_point()
print("敵に命中: %s" % collider.name)
print("命中地点: %s" % collision_point)
# ダメージ処理
if collider.has_method("take_damage"):
collider.take_damage(damage)
# ヒットエフェクト表示
create_impact_effect(collision_point)
else:
print("空に射撃")
func create_impact_effect(position: Vector3):
# ヒットエフェクトを表示(パーティクルなど)
pass
GDScriptコード例2:地面検出と落下判定
extends CharacterBody3D
@onready var ground_check = $GroundCheck # RayCast3Dを子ノードとして配置
@export var move_speed = 7.0
@export var jump_force = 20.0
@export var gravity = 30.0
var is_on_ground = false
func _ready():
# 足元を検出するRayCast3Dを設定
ground_check.target_position = Vector3(0, -0.1, 0) # 足元0.1m下
ground_check.enabled = true
func _physics_process(delta):
# 地面接触判定
ground_check.force_raycast_update()
is_on_ground = ground_check.is_colliding()
# キャラクター移動
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)
velocity.x = direction.x * move_speed
velocity.z = direction.z * move_speed
# ジャンプ
if Input.is_action_just_pressed("ui_space") and is_on_ground:
velocity.y = jump_force
print("ジャンプ!")
# 重力
if not is_on_ground:
velocity.y -= gravity * delta
velocity = move_and_slide(velocity)
# デバッグ表示
if is_on_ground:
var ground_object = ground_check.get_collider()
print("接地: %s" % ground_object.name)
else:
print("落下中")
もっと使いこなす:カスタマイズできるパラメータ
まずは基本を動かしてみてから、余裕が出たら試してみてください。
| パラメータ | 型 | 説明 | 実装例 |
|---|---|---|---|
collision_group |
int | 自身が属するフィジクスグループ | raycast.collision_group = 0b0001 |
hit_from_inside |
bool | オブジェクトの内側からのレイ衝突も検出 | raycast.hit_from_inside = true |
get_collision_shape() |
Shape3D | 衝突したコリジョン形状を取得 | var shape = raycast.get_collision_shape() |
debug_shape_custom_color |
Color | デバッグ表示時のレイの色(Debugモード) | raycast.debug_shape_custom_color = Color.RED |
カスタマイズの実装例:複数方向の視野チェック
extends Node3D
var view_raycasts = []
func _ready():
# 前方左45度、前方、前方右45度の3方向を監視
var angles = [-PI/4, 0, PI/4]
for angle in angles:
var rc = RayCast3D.new()
rc.target_position = Vector3(sin(angle) * 100, 0, -cos(angle) * 100)
rc.enabled = true
rc.collision_mask = 0b0010 # レイヤー1を検出
add_child(rc)
view_raycasts.append(rc)
func check_forward_vision():
var enemies_detected = []
for rc in view_raycasts:
rc.force_raycast_update()
if rc.is_colliding():
var collider = rc.get_collider()
if "Enemy" in collider.name:
enemies_detected.append(collider)
if enemies_detected.size() > 0:
print("敵を検出: %d体" % enemies_detected.size())
else:
print("敵なし")
return enemies_detected
まとめ
RayCast3Dは、ゲーム内での「何が見えているか」「何に当たるか」を判定する最もシンプルで高速なノードです。
- target_positionで光線の方向と距離を指定し、is_colliding()で衝突判定、get_collider()で衝突対象を取得できます
- FPS射撃、地面検出、視線チェックなど、様々なゲーム機構に応用できます
- 複数のRayCast3Dを組み合わせることで、複雑な視野判定や広域スキャンを実装できます
次回は、広い範囲を一度に判定できる「ShapeCast3D」について詳しく解説します。
シリーズ: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をもとに執筆しています。


コメント