レイキャストは現代ゲーム開発において不可欠の技術です。GodotのRayCast2D
ノードを使いこなせば、敵の探知、照準システム、地形検出など多彩な機能を実装できます。この記事では、Godot 4.4.1におけるRayCast2D
の基本から実践的な活用例まで解説します。
RayCast2D
は指定した方向にレイ(光線)を飛ばし、何かに衝突したかを検出するノードです。障害物の検知、視線の通り具合の確認、射撃の命中判定など、様々な用途に使えます。
まず、シーンにRayCast2Dノードを追加します。
インスペクタでこれらの重要なプロパティを設定します:
# コードでプロパティを設定する例
$RayCast2D.enabled = true
$RayCast2D.target_position = Vector2(100, 0) # 右方向に100ピクセル
$RayCast2D.collision_mask = 1 # 1番目のコリジョンレイヤーのみ
RayCast2D
の主要なメソッドを使った衝突検出:
func _physics_process(delta):
# レイの方向を更新(例:マウス方向)
$RayCast2D.target_position = get_local_mouse_position().normalized() * 100
# 衝突検出
if $RayCast2D.is_colliding():
# 衝突点を取得
var collision_point = $RayCast2D.get_collision_point()
# 衝突したオブジェクトを取得
var collider = $RayCast2D.get_collider()
# 衝突点の法線(面の向き)
var normal = $RayCast2D.get_collision_normal()
print("衝突検出: ", collider.name)
print("衝突点: ", collision_point)
print("法線: ", normal)
壁を通り抜けない視界システムの実装:
extends CharacterBody2D
@onready var ray_cast = $RayCast2D
@onready var vision_area = $VisionArea
func _physics_process(delta):
# プレイヤーの向きに応じてレイの方向を更新
ray_cast.target_position = Vector2(cos(rotation), sin(rotation)) * 200
# 壁との衝突をチェック
if ray_cast.is_colliding():
# 壁までの距離を計算
var distance = global_position.distance_to(ray_cast.get_collision_point())
# 視界の範囲を壁までに制限
vision_area.scale = Vector2(distance / 200, distance / 200)
else:
# 壁がなければ最大視界
vision_area.scale = Vector2(1, 1)
シンプルな射撃システムの実装:
extends Node2D
@onready var ray_cast = $RayCast2D
@onready var gun_sprite = $GunSprite
@onready var muzzle_position = $MuzzlePosition
func _process(delta):
# 銃をマウス方向に向ける
gun_sprite.look_at(get_global_mouse_position())
# レイの方向も更新
ray_cast.global_position = muzzle_position.global_position
ray_cast.target_position = get_local_mouse_position().normalized() * 1000
func _input(event):
if event is InputEventMouseButton and event.button_index == MOUSE_BUTTON_LEFT and event.pressed:
shoot()
func shoot():
if ray_cast.is_colliding():
var target = ray_cast.get_collider()
# 敵に当たったか確認
if target.is_in_group("enemies"):
target.take_damage(10)
# ヒットエフェクト
var hit_effect = preload("res://hit_effect.tscn").instantiate()
get_tree().root.add_child(hit_effect)
hit_effect.global_position = ray_cast.get_collision_point()
プレイヤーキャラクターが立っている地面の傾斜を検出:
extends CharacterBody2D
@onready var floor_ray = $FloorRayCast2D
func _physics_process(delta):
# 重力と移動の処理...
# 地面との接触を確認
if is_on_floor():
# 地面の傾斜角度を計算
var floor_normal = floor_ray.get_collision_normal()
var slope_angle = rad_to_deg(acos(floor_normal.dot(Vector2.UP)))
print("地面の傾斜: ", slope_angle, "度")
# 傾斜に応じた処理(例:急な坂では減速)
if slope_angle > 20:
velocity.x *= 0.8
プレイヤー周囲の状況を把握するためのセンサーシステム:
extends CharacterBody2D
var rays = []
var ray_count = 8
var ray_length = 100
func _ready():
# 周囲に8方向のレイを配置
for i in range(ray_count):
var ray = RayCast2D.new()
add_child(ray)
ray.enabled = true
# レイの角度を計算(円周上に均等配置)
var angle = i * 2 * PI / ray_count
ray.target_position = Vector2(cos(angle), sin(angle)) * ray_length
rays.append(ray)
func _physics_process(delta):
# 各レイの状態をチェック
for i in range(ray_count):
if rays[i].is_colliding():
var obj = rays[i].get_collider()
var dist = global_position.distance_to(rays[i].get_collision_point())
# 方向に応じた処理
if obj.is_in_group("dangers"):
# その方向に障害物があれば回避行動
avoid_danger(i, dist)
デバッグ用にレイキャストの結果を描画:
extends Node2D
@onready var ray_cast = $RayCast2D
func _draw():
if ray_cast.enabled:
var color = Color.GREEN
var target = ray_cast.target_position
# レイが何かに当たっていれば赤色に
if ray_cast.is_colliding():
color = Color.RED
# ローカル座標系に変換
var collision_point = to_local(ray_cast.get_collision_point())
target = collision_point
# レイを描画
draw_line(Vector2.ZERO, target, color, 2)
# 衝突点に円を描画
if ray_cast.is_colliding():
draw_circle(target, 5, Color.YELLOW)
func _process(delta):
# 描画を更新
queue_redraw()
Enabled プロパティの確認
enabled = true
になっているか確認するコリジョンマスクの設定
ターゲットポジションの設定
target_position = Vector2.ZERO
)物理エンジンのタイミング
_physics_process()
で確認する# パフォーマンス最適化の例
var update_interval = 0.1 # 0.1秒ごとに更新
var timer = 0
func _physics_process(delta):
timer += delta
if timer >= update_interval:
update_raycasts()
timer = 0
func update_raycasts():
# 重要な処理だけを実行
# ...
目的に応じたレイの長さ設定
適切なコリジョンマスク
ローカル・グローバル座標の理解
target_position
はローカル座標であることに注意デバッグ表示の活用
敵を探知してプレイヤーを追跡するAIの例:
extends CharacterBody2D
@export var detection_range = 300
@export var fov_angle = 60 # 視野角(度)
@export var speed = 100
@onready var ray_cast = $RayCast2D
@onready var player = get_tree().get_nodes_in_group("player")[0]
var detected = false
func _physics_process(delta):
if player:
# プレイヤーへの方向ベクトル
var to_player = player.global_position - global_position
var distance = to_player.length()
# 探知範囲内かつ視野角内にいるか確認
if distance < detection_range:
var angle_to_player = rad_to_deg(to_player.angle())
var my_angle = rad_to_deg(rotation)
var angle_diff = abs(angle_to_player - my_angle) % 360
if angle_diff > 180:
angle_diff = 360 - angle_diff
if angle_diff < fov_angle / 2:
# レイキャストでプレイヤーまでの視線が通るか確認
ray_cast.target_position = to_player
ray_cast.force_raycast_update()
if ray_cast.is_colliding() and ray_cast.get_collider() == player:
detected = true
# プレイヤー発見!追跡開始
velocity = to_player.normalized() * speed
else:
detected = false
# 視界が遮られている
velocity = Vector2.ZERO
else:
detected = false
# 視野角外
velocity = Vector2.ZERO
else:
detected = false
# 探知範囲外
velocity = Vector2.ZERO
# 状態に応じた表示の更新
$DetectionIndicator.modulate = Color.RED if detected else Color.GREEN
# 移動を適用
move_and_slide()
Godot 4.4.1のRayCast2D
ノードは、2Dゲーム開発における強力なツールです。本記事で解説した基本から応用までの技術を活用すれば、以下のようなさまざまな機能を実装できます:
効率的なレイキャストの使用は、よりリアルでインタラクティブなゲームプレイを実現する鍵となります。ぜひ自分のプロジェクトに取り入れてみてください。
本記事はGodot 4.4.1を基準としています。将来のバージョンでは一部の機能や使い方が変更される可能性があります。