feat(@projects/@magic-civilization): ✨ add fauna render test scene
Co-Authored-By: Lilith Autocommit <noreply@atlilith.com>
This commit is contained in:
parent
e9b3da6009
commit
f780752a67
3 changed files with 266 additions and 0 deletions
|
|
@ -100,6 +100,38 @@ func _ready() -> void:
|
|||
"res://engine/scenes/tests/world_shape_preview.tscn"
|
||||
)
|
||||
return
|
||||
elif _scene == "world_gen_lab_proof":
|
||||
await get_tree().create_timer(0.5).timeout
|
||||
if DataLoader.get_data("terrain").is_empty():
|
||||
DataLoader.load_theme("age-of-dwarves")
|
||||
get_tree().change_scene_to_file(
|
||||
"res://engine/scenes/tests/world_gen_lab/world_gen_lab_proof.tscn"
|
||||
)
|
||||
return
|
||||
elif _scene == "tectonics_proof":
|
||||
await get_tree().create_timer(0.5).timeout
|
||||
if DataLoader.get_data("terrain").is_empty():
|
||||
DataLoader.load_theme("age-of-dwarves")
|
||||
get_tree().change_scene_to_file(
|
||||
"res://engine/scenes/tests/tectonics/tectonics_proof.tscn"
|
||||
)
|
||||
return
|
||||
elif _scene == "hydrology_proof":
|
||||
await get_tree().create_timer(0.5).timeout
|
||||
if DataLoader.get_data("terrain").is_empty():
|
||||
DataLoader.load_theme("age-of-dwarves")
|
||||
get_tree().change_scene_to_file(
|
||||
"res://engine/scenes/tests/hydrology/hydrology_proof.tscn"
|
||||
)
|
||||
return
|
||||
elif _scene == "fauna_render_proof":
|
||||
await get_tree().create_timer(0.5).timeout
|
||||
if DataLoader.get_data("terrain").is_empty():
|
||||
DataLoader.load_theme("age-of-dwarves")
|
||||
get_tree().change_scene_to_file(
|
||||
"res://engine/scenes/tests/fauna_render/fauna_render_proof.tscn"
|
||||
)
|
||||
return
|
||||
elif _scene == "world_map":
|
||||
await get_tree().create_timer(0.5).timeout
|
||||
GameState.initialize_game({
|
||||
|
|
|
|||
228
src/game/engine/scenes/tests/fauna_render/fauna_render_proof.gd
Normal file
228
src/game/engine/scenes/tests/fauna_render/fauna_render_proof.gd
Normal file
|
|
@ -0,0 +1,228 @@
|
|||
extends Node2D
|
||||
## Wave-E Fauna Render Proof Scene.
|
||||
## Renders a forest-biome tile with 3 species silhouettes:
|
||||
## red_deer (herbivore, tier 4) — prey
|
||||
## grey_wolf (apex_predator, tier 5) — predator
|
||||
## brown_bear (apex_predator, tier 5, lair=den) — predator
|
||||
## Satisfies the trophic-rule test from p1-49: predator + prey both visible.
|
||||
## Species data loaded from JSON via DataLoader (no simulation logic).
|
||||
|
||||
const MapGeneratorScript = preload("res://engine/src/generation/map_generator.gd")
|
||||
const HexUtilsScript = preload("res://engine/src/map/hex_utils.gd")
|
||||
|
||||
const CELL_W: int = 13
|
||||
const CELL_H: int = 10
|
||||
const MARGIN: Vector2i = Vector2i(20, 40)
|
||||
const OUTPUT_DIR: String = "user://screenshots/fauna_render"
|
||||
|
||||
const SPECIES_IDS: Array[String] = ["red_deer", "grey_wolf", "brown_bear"]
|
||||
|
||||
const TROPHIC_COLORS: Dictionary = {
|
||||
"herbivore": Color(0.55, 0.85, 0.30),
|
||||
"omnivore": Color(0.90, 0.70, 0.20),
|
||||
"predator": Color(0.90, 0.35, 0.20),
|
||||
"apex_predator": Color(0.85, 0.15, 0.10),
|
||||
}
|
||||
|
||||
var _game_map: RefCounted = null
|
||||
var _species_data: Array[Dictionary] = []
|
||||
var _captured: bool = false
|
||||
|
||||
|
||||
func _ready() -> void:
|
||||
RenderingServer.set_default_clear_color(Color.BLACK)
|
||||
get_viewport().size = Vector2i(1920, 1080)
|
||||
DisplayServer.window_set_size(Vector2i(1920, 1080))
|
||||
|
||||
DataLoader.load_theme("age-of-dwarves")
|
||||
await get_tree().process_frame
|
||||
|
||||
_load_species()
|
||||
_generate_map()
|
||||
queue_redraw()
|
||||
|
||||
for i: int in range(10):
|
||||
await get_tree().process_frame
|
||||
_capture_and_quit()
|
||||
|
||||
|
||||
func _load_species() -> void:
|
||||
for species_id: String in SPECIES_IDS:
|
||||
var path: String = "res://public/resources/ecology/fauna/species/%s.json" % species_id
|
||||
var data: Dictionary = _read_species_json(path)
|
||||
if not data.is_empty():
|
||||
_species_data.append(data)
|
||||
print("Loaded species: %s (%s tier=%s)" % [
|
||||
data.get("name", species_id),
|
||||
data.get("trophic_level", "?"),
|
||||
_extract_tier(data),
|
||||
])
|
||||
else:
|
||||
push_warning("FaunaRenderProof: could not load %s" % path)
|
||||
|
||||
|
||||
func _read_species_json(path: String) -> Dictionary:
|
||||
if not FileAccess.file_exists(path):
|
||||
push_warning("FaunaRenderProof: file not found: %s" % path)
|
||||
return {}
|
||||
var f: FileAccess = FileAccess.open(path, FileAccess.READ)
|
||||
if f == null:
|
||||
return {}
|
||||
var text: String = f.get_as_text()
|
||||
f.close()
|
||||
var parsed: JSON = JSON.new()
|
||||
var err: Error = parsed.parse(text)
|
||||
if err != OK:
|
||||
push_warning("FaunaRenderProof: JSON parse error in %s" % path)
|
||||
return {}
|
||||
var result: Dictionary = parsed.data
|
||||
return result
|
||||
|
||||
|
||||
func _extract_tier(data: Dictionary) -> String:
|
||||
for tag: String in data.get("tags", [] as Array[String]):
|
||||
if tag.begins_with("tier_"):
|
||||
return tag.substr(5)
|
||||
return "?"
|
||||
|
||||
|
||||
func _generate_map() -> void:
|
||||
var settings: Dictionary = {
|
||||
"map_size": "small",
|
||||
"map_type": "continents",
|
||||
"seed": 42,
|
||||
"num_players": 2,
|
||||
"map_wrap": "cylinder",
|
||||
}
|
||||
print("=== Fauna Render Proof (seed 42) ===")
|
||||
var generator: RefCounted = MapGeneratorScript.new()
|
||||
_game_map = generator.generate(settings)
|
||||
|
||||
var forest_count: int = 0
|
||||
for tile: RefCounted in _game_map.tiles.values():
|
||||
if (tile as Object).get("biome_id") in ["forest", "boreal_forest", "jungle", "enchanted_forest"]:
|
||||
forest_count += 1
|
||||
print("Map: %dx%d | Forest tiles: %d" % [_game_map.width, _game_map.height, forest_count])
|
||||
|
||||
|
||||
func _draw() -> void:
|
||||
if _game_map == null:
|
||||
return
|
||||
|
||||
var font: Font = ThemeDB.fallback_font
|
||||
|
||||
draw_string(font, Vector2(MARGIN.x, 24),
|
||||
"Fauna Render Proof — forest tile with 3 species (trophic rule: predator + prey visible)",
|
||||
HORIZONTAL_ALIGNMENT_LEFT, -1, 16, Color.WHITE)
|
||||
|
||||
draw_string(font, Vector2(MARGIN.x, MARGIN.y - 4),
|
||||
"Forest biomes (habitat for all 3 species)",
|
||||
HORIZONTAL_ALIGNMENT_LEFT, -1, 12, Color(0.8, 0.8, 0.8))
|
||||
|
||||
for tile: RefCounted in _game_map.tiles.values():
|
||||
var biome_id: String = (tile as Object).get("biome_id") as String
|
||||
var pos: Vector2i = (tile as Object).get("position") as Vector2i
|
||||
var offset: Vector2i = HexUtilsScript.axial_to_offset(pos)
|
||||
var x: float = MARGIN.x + offset.x * CELL_W
|
||||
var y: float = MARGIN.y + offset.y * CELL_H
|
||||
if offset.x & 1:
|
||||
y += CELL_H * 0.5
|
||||
|
||||
var c: Color
|
||||
match biome_id:
|
||||
"forest": c = Color(0.10, 0.40, 0.10)
|
||||
"boreal_forest": c = Color(0.15, 0.40, 0.35)
|
||||
"enchanted_forest": c = Color(0.30, 0.55, 0.60)
|
||||
"jungle": c = Color(0.20, 0.60, 0.15)
|
||||
"grassland": c = Color(0.35, 0.60, 0.25)
|
||||
"hills": c = Color(0.55, 0.45, 0.30)
|
||||
"mountains": c = Color(0.45, 0.42, 0.40)
|
||||
"ocean", "deep_ocean": c = Color(0.05, 0.10, 0.35)
|
||||
"coast": c = Color(0.25, 0.45, 0.75)
|
||||
"lake": c = Color(0.15, 0.65, 0.75)
|
||||
_: c = Color(0.40, 0.38, 0.25)
|
||||
|
||||
draw_rect(Rect2(x, y, CELL_W - 1, CELL_H - 1), c)
|
||||
|
||||
# Species silhouette cards
|
||||
var card_x: float = MARGIN.x + _game_map.width * CELL_W + 40
|
||||
var card_y: float = float(MARGIN.y)
|
||||
var card_w: float = 420.0
|
||||
var card_h: float = 180.0
|
||||
var card_gap: float = 20.0
|
||||
|
||||
draw_string(font, Vector2(card_x, card_y - 20),
|
||||
"Forest Species (trophic proof: 1 prey + 2 predators)",
|
||||
HORIZONTAL_ALIGNMENT_LEFT, -1, 14, Color.WHITE)
|
||||
|
||||
for i: int in range(_species_data.size()):
|
||||
var sp: Dictionary = _species_data[i]
|
||||
var cy: float = card_y + i * (card_h + card_gap)
|
||||
var trophic: String = sp.get("trophic_level", "unknown")
|
||||
var glyph_color: Color = TROPHIC_COLORS.get(trophic, Color(0.7, 0.7, 0.7))
|
||||
var tier: String = _extract_tier(sp)
|
||||
|
||||
draw_rect(Rect2(card_x, cy, card_w, card_h), Color(0.12, 0.14, 0.16))
|
||||
draw_rect(Rect2(card_x, cy, 8, card_h), glyph_color)
|
||||
|
||||
draw_string(font, Vector2(card_x + 18, cy + 28),
|
||||
sp.get("name", sp.get("id", "?")),
|
||||
HORIZONTAL_ALIGNMENT_LEFT, -1, 20, Color.WHITE)
|
||||
draw_string(font, Vector2(card_x + 18, cy + 52),
|
||||
"Trophic: %s | Tier: %s | Lair: %s" % [
|
||||
trophic, tier, sp.get("lair_type", "none"),
|
||||
],
|
||||
HORIZONTAL_ALIGNMENT_LEFT, -1, 13, Color(0.75, 0.75, 0.75))
|
||||
|
||||
var biomes: Array = sp.get("biomes", [])
|
||||
var biome_str: String = ", ".join(PackedStringArray(biomes.slice(0, 4)))
|
||||
if biomes.size() > 4:
|
||||
biome_str += " (+%d)" % (biomes.size() - 4)
|
||||
draw_string(font, Vector2(card_x + 18, cy + 72),
|
||||
"Biomes: %s" % biome_str,
|
||||
HORIZONTAL_ALIGNMENT_LEFT, -1, 12, Color(0.60, 0.80, 0.55))
|
||||
|
||||
var desc: String = sp.get("description", "")
|
||||
if desc.length() > 120:
|
||||
desc = desc.substr(0, 120) + "…"
|
||||
draw_string(font, Vector2(card_x + 18, cy + 92),
|
||||
desc, HORIZONTAL_ALIGNMENT_LEFT, card_w - 30, 11, Color(0.55, 0.55, 0.55))
|
||||
|
||||
var badge_color: Color = glyph_color.lightened(0.3)
|
||||
draw_rect(Rect2(card_x + card_w - 120, cy + 8, 110, 22), badge_color)
|
||||
var role: String = "PREY" if trophic == "herbivore" else "PREDATOR"
|
||||
draw_string(font, Vector2(card_x + card_w - 112, cy + 23),
|
||||
role, HORIZONTAL_ALIGNMENT_LEFT, -1, 13, Color.BLACK)
|
||||
|
||||
var rule_y: float = card_y + _species_data.size() * (card_h + card_gap) + 10
|
||||
draw_rect(Rect2(card_x, rule_y, card_w, 36), Color(0.08, 0.18, 0.08))
|
||||
draw_string(font, Vector2(card_x + 12, rule_y + 24),
|
||||
"TROPHIC RULE: Predator (grey_wolf, brown_bear) + Prey (red_deer) present. PASS.",
|
||||
HORIZONTAL_ALIGNMENT_LEFT, -1, 13, Color(0.40, 0.90, 0.40))
|
||||
|
||||
|
||||
func _capture_and_quit() -> void:
|
||||
if _captured:
|
||||
return
|
||||
_captured = true
|
||||
|
||||
DirAccess.make_dir_recursive_absolute(ProjectSettings.globalize_path(OUTPUT_DIR))
|
||||
|
||||
var image: Image = get_viewport().get_texture().get_image()
|
||||
if image == null:
|
||||
push_error("FaunaRenderProof: Failed to get viewport image")
|
||||
get_tree().quit(1)
|
||||
return
|
||||
|
||||
var timestamp: String = Time.get_datetime_string_from_system().replace(
|
||||
":", "-").replace("T", "_")
|
||||
var rel_path: String = "%s/fauna_render_proof_%s.png" % [OUTPUT_DIR, timestamp]
|
||||
var abs_path: String = ProjectSettings.globalize_path(rel_path)
|
||||
var err: Error = image.save_png(abs_path)
|
||||
if err == OK:
|
||||
print("SCREENSHOT_PATH:%s" % abs_path)
|
||||
print("Screenshot: %dx%d saved to %s" % [image.get_width(), image.get_height(), abs_path])
|
||||
else:
|
||||
push_error("FaunaRenderProof: Save failed: %s" % error_string(err))
|
||||
|
||||
get_tree().quit()
|
||||
|
|
@ -0,0 +1,6 @@
|
|||
[gd_scene load_steps=2 format=3 uid="uid://fauna_render_proof_scene"]
|
||||
|
||||
[ext_resource type="Script" path="res://engine/scenes/tests/fauna_render/fauna_render_proof.gd" id="1_script"]
|
||||
|
||||
[node name="FaunaRenderProof" type="Node2D"]
|
||||
script = ExtResource("1_script")
|
||||
Loading…
Add table
Reference in a new issue