7b6a141767
Move the 40-odd root-level scripts and scenes into a tree that groups by role,
per the approved roadmap (WS2/WS3): actors/{player,matador,bear}, systems/{combat,
fx,input,debug,render,crowd,config}, ui/, props/ (was tscn_s/). Rename the shell
scene.tscn -> levels/game_shell.tscn and every PascalCase scene to snake_case
(Player.tscn -> player.tscn, MainMenu.tscn -> main_menu.tscn, etc.) so the
case-insensitive web/macOS filesystems can't alias two files together.
Done as a scripted move: each file travels with its .uid; every quoted res:// path
across scenes, scripts, .tres, and project.godot's 9 autoloads is rewritten; the
.godot uid/class cache is rebuilt from scratch. Scenes still resolve by uid, so the
rewrite is belt-and-suspenders. Lint globs (run_tests.sh + both CI workflows) now
walk the new dirs; an orphan animation_tree.gd.uid and 7 pre-existing trailing-
whitespace lints (barrel/torch, never covered by the old root-only glob) are cleaned.
Full suite green on both sides. Asset consolidation (Assets/Animations/fonts ->
art/) is deferred — moving imported .glb/.png/.ttf is safer done in the editor.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017KoYBYQgRyY1zDHXMsXY3V
66 lines
2.0 KiB
GDScript
66 lines
2.0 KiB
GDScript
extends SceneTree
|
|
## Top-down + angled aerial of the arena with the crowd, plus axis markers, to locate
|
|
## the ruined section and any billboards left floating over it.
|
|
## godot --script tools/preview_topdown.gd
|
|
## Output: tools/preview/top.png (ortho top-down), tools/preview/aerial.png
|
|
|
|
const OUT := "res://tools/preview"
|
|
|
|
|
|
func _init() -> void:
|
|
_run.call_deferred()
|
|
|
|
|
|
func _run() -> void:
|
|
DirAccess.make_dir_recursive_absolute(OUT)
|
|
var scene := (load("res://levels/game_shell.tscn") as PackedScene).instantiate()
|
|
root.add_child(scene)
|
|
current_scene = scene
|
|
|
|
# Axis markers: red pillar at +X (east), green at +Z (south), so directions read.
|
|
_marker(scene, Vector3(18, 5, 0), Color(1, 0.2, 0.2))
|
|
_marker(scene, Vector3(0, 5, 18), Color(0.2, 1, 0.2))
|
|
|
|
await create_timer(0.4).timeout
|
|
var crowd := scene.get_node_or_null(^"CrowdBillboards") as MultiMeshInstance3D
|
|
if crowd != null and crowd.multimesh != null:
|
|
print("crowd instances = ", crowd.multimesh.instance_count)
|
|
|
|
var top := Camera3D.new()
|
|
top.projection = Camera3D.PROJECTION_ORTHOGONAL
|
|
top.size = 46.0
|
|
scene.add_child(top)
|
|
top.look_at_from_position(Vector3(0, 60, 0.01), Vector3.ZERO, Vector3(0, 0, -1))
|
|
top.current = true
|
|
await create_timer(0.2).timeout
|
|
_shot("top.png")
|
|
|
|
var air := Camera3D.new()
|
|
air.fov = 60.0
|
|
scene.add_child(air)
|
|
air.look_at_from_position(Vector3(0, 26, 34), Vector3(0, 3, 0), Vector3.UP)
|
|
air.current = true
|
|
await create_timer(0.2).timeout
|
|
_shot("aerial.png")
|
|
quit(0)
|
|
|
|
|
|
func _marker(scene: Node, pos: Vector3, col: Color) -> void:
|
|
var m := MeshInstance3D.new()
|
|
var box := BoxMesh.new()
|
|
box.size = Vector3(1.5, 10.0, 1.5)
|
|
var mat := StandardMaterial3D.new()
|
|
mat.shading_mode = BaseMaterial3D.SHADING_MODE_UNSHADED
|
|
mat.albedo_color = col
|
|
box.material = mat
|
|
m.mesh = box
|
|
scene.add_child(m)
|
|
m.global_position = pos
|
|
|
|
|
|
func _shot(name: String) -> void:
|
|
var img := root.get_viewport().get_texture().get_image()
|
|
if img != null:
|
|
img.save_png(OUT + "/" + name)
|
|
print("captured ", name)
|