概要
Marker2Dは、位置情報(Transform)のみを持つ最も軽量な2Dノードです。レンダリングや物理演算の負荷がないため、ゲーム全 体を管理するスクリプトのホストとして最適です。
Unityで空のGameObjectを使っていた経験がある方には、Marker2Dはまさにそれに相当するノードです。最初は「なぜ位置情報だけのノードが必要なのか?」と疑問でしたが、GameManagerやSpawnManagerなどの管理スクリプトを整理する際に、その価値がよくわかりました。
Marker2Dの特徴
- 最小限の機能: 位置情報のみ(描画・物理なし)
- 軽量: メモリ使用量が最小
- エディタ表示: シーンエディタでアイコン表示(実行時は非表示)
- Unityの空GameObject相当: 管理用途に特化
基本的な使い方
GameManagerの実装
# GameManager.gd (Marker2Dにアタッチ)
extends Marker2D
signal game_started
signal game_over
signal score_updated(new_score)
var score: int = 0
var is_game_active: bool = false
var current_level: int = 1
func _ready():
# シーンツリーのルート近くに配置
process_mode = Node.PROCESS_MODE_ALWAYS
func start_game():
is_game_active = true
score = 0
emit_signal("game_started")
func add_score(points: int):
score += points
emit_signal("score_updated", score)
func end_game():
is_game_active = false
emit_signal("game_over")
PuzzleManagerの実装
# PuzzleManager.gd
extends Marker2D
var switches_activated: int = 0
var total_switches: int = 3
@onready var door = $"../Door"
func _ready():
# 全てのスイッチを検索して接続
for switch in get_tree().get_nodes_in_group("puzzle_switches"):
switch.activated.connect(_on_switch_activated)
func _on_switch_activated():
switches_activated += 1
if switches_activated >= total_switches:
solve_puzzle()
func solve_puzzle():
door.open()
print("パズル解決!")
実践的な活用例
SpawnManagerの実装
# SpawnManager.gd
extends Marker2D
@export var enemy_scene: PackedScene
@export var spawn_interval: float = 2.0
@export var spawn_points: Array[Marker2D] = []
var spawn_timer: Timer
func _ready():
setup_spawn_timer()
func setup_spawn_timer():
spawn_timer = Timer.new()
spawn_timer.wait_time = spawn_interval
spawn_timer.timeout.connect(spawn_enemy)
add_child(spawn_timer)
spawn_timer.start()
func spawn_enemy():
if spawn_points.is_empty():
return
var spawn_point = spawn_points.pick_random()
var enemy = enemy_scene.instantiate()
get_parent().add_child(enemy)
enemy.global_position = spawn_point.global_position
EventManagerの実装
# EventManager.gd (Autoloadとして使用)
extends Marker2D
# グローバルイベントシステム
signal player_died
signal level_completed
signal item_collected(item_type)
signal dialog_started
signal dialog_ended
var event_queue: Array = []
func trigger_event(event_name: String, data = null):
event_queue.append({
"name": event_name,
"data": data,
"timestamp": Time.get_ticks_msec()
})
# イベントに応じた処理
match event_name:
"player_death":
emit_signal("player_died")
"level_complete":
emit_signal("level_completed")
Marker2Dを使うべき場面
適している用途
- ゲーム全体の状態管理
- イベントシステム
- スポーン地点の管理
- パズルロジック
- タイマー管理
- データ集計
適さない用途
- 視覚的な要素が必要な場合 → Sprite2D
- 物理判定が必要な場合 → Area2D
- UI要素 → Control系ノード
組織化のベストプラクティス
シーン構造の例
Main (Node2D)
├── Managers (Node2D)
│ ├── GameManager (Marker2D)
│ ├── SpawnManager (Marker2D)
│ ├── AudioManager (Marker2D)
│ └── SaveManager (Marker2D)
├── World (Node2D)
│ ├── Player
│ ├── Enemies
│ └── Environment
└── UI (CanvasLayer)
マネージャー間の通信
# GameManager.gd
extends Marker2D
@onready var spawn_manager = $"../SpawnManager"
@onready var audio_manager = $"../AudioManager"
func start_game():
spawn_manager.enable_spawning()
audio_manager.play_bgm("game_theme")
func pause_game():
spawn_manager.disable_spawning()
audio_manager.pause_bgm()
パフォーマンスの比較
ノードタイプ | メモリ使用 | 処理負荷 | 用途 |
---|---|---|---|
Marker2D | 最小 | なし | 管理・ロジック |
Node2D | 小 | 小 | 基本的な2Dノード |
Sprite2D | 中 | 描画あり | 画像表示 |
CharacterBody2D | 大 | 物理演算あり | キャラクター |
デバッグのコツ
# デバッグ表示の追加
extends Marker2D
@export var debug_mode: bool = false
func _draw():
if debug_mode and Engine.is_editor_hint():
# エディタでのみ表示
draw_circle(Vector2.ZERO, 10, Color.RED)
draw_string(get_theme_default_font(),
Vector2(15, 5),
name,
HORIZONTAL_ALIGNMENT_LEFT,
-1,
16)
実装して学んだこと
Marker2Dを管理ノードとして使うようになってから、プロジェクトの構造が非常にすっきりしました。以前はNode2DやSprite2Dに管理スクリプトをアタッチしていましたが、「このスプライトは何のためにあるの?」という混乱がありました。
特に良かったのは、マネージャー系のノードを「Managers」フォルダにまとめられるようになったことです。シーンツリーが整理され、他の開発者(あるいは未来の自分)が見ても、どこに何があるかすぐに理解できるようになりました。
また、Marker2Dは本当に軽量なので、大量に使ってもパフォーマンスへの影響がほとんどありません。スポーンポイントなどにも気軽に使えるのが便利です。