概要
ゲーム開発では、「敵の出現位置」「弾丸の発射位置」「エフェクトの表示位置」など、特定の「座標」を扱いたい場面が頻繁に登場します。これらの座標をスクリプト内にVector2(150, 300)のように直接書き込む(ハードコーディングする)と、後から位置を微調整するたびにコードを修正する必要があり、非常に非効率です。
この問題を解決し、座標管理を劇的に楽にしてくれるのがMarker2D ノードです。
この記事では、Marker2Dの基本的な使い方と、それがいかにゲーム開発の効率を上げるかについて、具体的な活用例と共に解説します。
Marker2Dとは? Position2Dとの違い
Marker2Dは、2D空間における「目印」として機能する、非常に軽量でシンプルなノードです。その本質はNode2Dとほぼ同じですが、決定的な違いが一つあります。それは、エディタ上で常に緑色の十字アイコンとして表示されることです。
この「常に視覚化されている」という特性が、Marker2Dを単なるNode2DやPosition2D(Node2Dの別名)と一線を画す強力なツールたらしめています。コード内の抽象的な数値ではなく、エディタ上でオブジェクトをドラッグ&ドロップするのと同じ直感的な感覚で、座標を配置・調整できるのです。
実践的な活用シナリオ
シナリオ1:柔軟性の高い敵スポーンシステムの構築
単に敵を出現させるだけでなく、より高度なスポーンシステムを構築する際にMarker2Dは真価を発揮します。
1. スポーン地点のセットアップ
まず、敵を出現させたい位置に複数のMarker2Dを配置します。そして、それらを「enemies_spawn_points」グループに追加します。
2. スポーン地点に情報を付加する
さらに一歩進んで、各Marker2Dにカスタムスクリプトをアタッチし、@export変数で追加情報を設定できるようにします。これ により、スポーン地点ごとに異なる振る舞いをさせることが可能になります。
# SpawnPoint.gd
extends Marker2D
# この地点から出現する敵の種類
@export var enemy_type: PackedScene
# この地点の優先度(高いほど選ばれやすいなど)
@export var priority: int = 1
# 有効/無効フラグ
@export var enabled: bool = true
3. 管理スクリプトからの利用
ゲームマネージャーなどの管理ノードから、これらの情報を活用して敵をスポーンさせます。
# GameManager.gd
@export var enemy_scene: PackedScene
func _ready():
spawn_initial_enemies()
func spawn_initial_enemies():
var spawn_points = get_tree().get_nodes_in_group('enemies_spawn_points')
for sp in spawn_points:
# スクリプトがアタッチされており、かつ有効な場合のみ処理
if sp.enabled and sp.enemy_type:
var enemy = sp.enemy_type.instantiate()
enemy.global_position = sp.global_position
add_child(enemy)
この設計により、レベルデザイナーはコードを一切触らずに、インスペクタ上で「どの位置」から「どの敵」を「出現させるか/させないか」を自由に設定できるようになります。
シナリオ2:キャラクターの動的なアタッチメントポイント
キャラクターの銃口、剣の先端、魔法の杖の先など、動きに追従する必要がある座標の管理はMarker2Dの得意分野です。
1. Marker2Dをキャラクターの子にする
プレイヤーキャラクターのシーン(Player.tscnなど)で、Sprite2DやAnimatedSprite2Dの子としてMarker2Dを追加します。ノード名を「Muzzle」(銃口)や「EffectOrigin」のように役割が分かる名前にします。
2. 銃口(Muzzle)からの弾丸発射
キャラクターがどの方向を向いていても、Marker2Dは常に追従します。global_positionとglobal_rotationを使えば、弾丸を常に正しい位置と角度で発射できます。
# Player.gd
@onready var muzzle = $Sprite2D/Muzzle
@export var bullet_scene: PackedScene
func _process(delta):
if Input.is_action_just_pressed('shoot'):
var bullet = bullet_scene.instantiate()
# Muzzleのグローバル座標と角度を発射位置・角度とする
bullet.global_position = muzzle.global_position
bullet.rotation = muzzle.global_rotation
# 弾を親ノードの階層に追加(プレイヤーの子にしないため)
get_tree().current_scene.add_child(bullet)
注意: スプライトを
flip_hで左右反転させている場合、global_rotationだけでは弾の向きが正しくならないことがあります。その場合は反転状態に応じて角度を調整するか、muzzle.global_transform.x(右方向ベクトル)を使って弾の進行方向を設定してください。
このテクニックは、キャラクターの足元から出る砂埃エフェクト、背中からジェットパックの炎を出すなど、あらゆる「キャラクターの特定部位」を基準点とする処理に応用できます。