feat: add Nebula and Asteroid Field arenas

Introduce arena_02 (Nebula) and arena_03 (Asteroid Field) alongside
arena_01, listed in a new ArenaRegistry (scripts/arena_registry.gd) as
the single source of truth for available arenas. Free Play lets the
player pick an arena from the main menu; Match/Spectate each pick one
at random per session; Training keeps its own fixed arena_01.

Nebula gets an RL-style visual treatment: a near-invisible glass
boundary material shared by all arenas, a baked equirect nebula sky
texture, a drifting-dust particle system, and a Blender-modeled
station/debris/planet decoration set. GameMode gains a
_get_arena_scene_path() hook so modes can instantiate their arena in
code instead of hardcoding it in the scene.
This commit is contained in:
Josh Creek
2026-08-03 19:09:16 +01:00
parent 1af3e0410d
commit 171cd4a840
35 changed files with 683 additions and 12 deletions
+17
View File
@@ -18,6 +18,7 @@ const DIFFICULTIES := [
]
@onready var difficulty_dropdown: OptionButton = %DifficultyDropdown
@onready var arena_dropdown: OptionButton = %ArenaDropdown
@onready var dev_section: Control = %DevSection
@onready var dev_bot_dropdown: OptionButton = %DevBotDropdown
@onready var bot_a_dropdown: OptionButton = %BotADropdown
@@ -26,6 +27,7 @@ const DIFFICULTIES := [
func _ready() -> void:
_populate_difficulty_dropdown()
_populate_arena_dropdown()
dev_section.visible = OS.is_debug_build()
if dev_section.visible:
var bots := _list_bots()
@@ -47,6 +49,19 @@ func _populate_difficulty_dropdown() -> void:
difficulty_dropdown.select(selected)
# Free Play only — Match/Spectate pick a random arena in code instead.
func _populate_arena_dropdown() -> void:
arena_dropdown.clear()
for tier in ArenaRegistry.ARENAS:
arena_dropdown.add_item(tier["name"])
var selected := 0
for i in ArenaRegistry.ARENAS.size():
if ArenaRegistry.ARENAS[i]["path"] == GameSettings.selected_arena_path:
selected = i
break
arena_dropdown.select(selected)
# Lists bot checkpoints as paths relative to BOTS_DIR, including the
# top-level curriculum checkpoints and anything under promoted/.
func _list_bots() -> Array[String]:
@@ -93,6 +108,8 @@ func _selected_path(dropdown: OptionButton) -> String:
func _on_free_play_pressed() -> void:
var chosen: Dictionary = ArenaRegistry.ARENAS[0] if arena_dropdown.selected < 0 else ArenaRegistry.ARENAS[arena_dropdown.selected]
GameSettings.selected_arena_path = chosen["path"]
get_tree().change_scene_to_file("res://scenes/free_play.tscn")