Godot 4 | ノードの当たり判定(オーバーラップ)の実装サンプル

2023-10-07Godot 4,Godot 4 実装サンプル

Godot 4 | ノードの当たり判定(オーバーラップ)の実装サンプル
当たり判定(オーバーラップ)

ゲームエンジン「Godot 4」でゲームオブジェクトにしているノードの当たり判定についての覚え書きと実装方法の紹介です。

確認環境
  • Windows11 22H2
  • Godot v4.1.1

当たり判定(オーバーラップ)の動作サンプルプロジェクト

動作サンプルページ

サンプルプロジェクト(zip)のダウンロード

当たり判定に関連した基本ノード

当たり判定からみた基本ノードをメモしています。

ノード概要
Area2D接触判定はするが衝突による物理シュミレーションの影響を受けない2D物理ボディ
・オーバーラップ検出
・アイテムやドアなど
StaticBody2D衝突判定はあるが動かせない2D物理ボディ
・木や壁、山など
RigidBody2D物理シミュレーションの影響を受ける2D物理ボディ
・動かせる岩、衝突判定のある敵、ほか
CharacterBody2Dスクリプトによって移動されるキャラクターに特化した2D物理ボディ
・プレイヤーなど
当たり判定に関連した基本ノード

いずれも「CollisionShape2D」「CollisionPolygon2D」などの衝突に対する形状を持つ子ノードが必要。

KinematicBody2DはGodot 4.1では無い

多くの解説で使われている「KinematicBody2D」はGodot 4からは無くなっているようです。

「KinematicBody2D」「RigidBody2D」「CharacterBody2D」と扱いは同等で置き換わったという認識で良さそう。

各ノードタイプ別の階層

各タイプ別オブジェクト用に最低限必要な階層をメモしています。
必要に応じてヒットエリアとする「BaseHitBox」などを組み合わせていきます。

「プレイヤー」
Player(CharacterBody2D)
┣ Image(Sprite2D)
┗ 衝突形状(CollisionShape2D)

「木や壁、山など」
Player(StaticBody2D)
┣ Image(Sprite2D)
┗ 衝突形状(CollisionShape2D)

「アイテム、弾など」
Item(Area2D)
┣ Image(Sprite2D)
┗ 衝突形状(CollisionShape2D)

「すり抜ける敵」
Item(Area2D)
┣ Image(Sprite2D)
┗ 衝突形状(CollisionShape2D)

「ぶつかる敵」
Item(RigidBody2D)
┣ Image(Sprite2D)
┗ 衝突形状(CollisionShape2D)

プレイヤーとすり抜けるノードとの当たり判定

プレイヤーとすり抜けるノードとの当たり判定です。

以下の条件を満たしている事を前提としています。

  • 移動用のインプットマップが設定されている(サンプルではトップダウン)

プレイヤーのノード

Player(CharacterBody2D)#スクリプト
┣ Image(Sprite2D)
┗ 衝突形状(CollisionShape2D)

プレイヤーノードのスクリプト

class_name Player extends CharacterBody2D
@export var speed = 500

var direction : Vector2

func _process(_delta):
	pass

func _physics_process(_delta):
	direction = Input.get_vector("move_left", "move_right", "move_up", "move_down")
	velocity = direction * speed
	move_and_slide()

# 対象と重なった時
func _on_area_2d_body_entered(_body):
	modulate = Color(1, 0.5, 0.5)

# 対象から離れた時
func _on_area_2d_body_exited(_body):
	modulate = Color(1, 1, 1)

「modulate」でカラーバランスを変更して、重なっているかどうかを確認しています。

すり抜けるノードのノード

Item(Area2D)#スクリプト
┣ Image(Sprite2D)
┗ 衝突形状(CollisionShape2D)

すり抜けるノードのスクリプト

extends Area2D

func _ready():
	# プレイヤーノードの取得
	var player = get_node("/root/Main/Player")
	# プレイヤーノードに接続(重なった時用)
	connect("body_entered", Callable(player, "_on_area_2d_body_entered"))
	# プレイヤーノードに接続(離れた時用)
	connect("body_exited", Callable(player, "_on_area_2d_body_exited"))

エディタの「ノード」タブから接続する機能がありますが、先々の処理を想定して今回はスクリプトからget_node()connect()でプレイヤーノードに接続しています。
プレイヤーノードのパスはシーンのツリー状況によって調節が必要、検索とかあるのかな。