feat: Neon Alley — urban-Japan movement map built on the acoustic materials

New map (scenes/maps/neon_alley/, auto-appears in the level selectors):

Layout for movement flow:
- Main N-S street = the long sightline, crossed by a pedestrian bridge
  (slide ramps up both ends, underpass cover below, railed high ground)
- West machiya row: wooden two-story houses with a jump route
  (awning -> balcony -> roof deck) and 25-degree slide roofs facing the street
- East concrete towers with glass storefronts; brick wallrun alley between
  them (AC units to vault); metal fire-escape platform route to the roofs;
  angled rooftop billboard as cover + grapple anchor
- Three power pylons with crossarms over the street chain a grapple route;
  the torii gate crossbeam at the north shrine plaza is a fourth anchor
- South market: wooden stalls with neon canopies + metal vending machines
  = scattered mid cover; shipping container corner piece
- Spawns ring the block and face the map center

Acoustics as level design: every surface is tagged (machiya/stalls/torii
wood, towers concrete, storefronts glass, alley+perimeter brick, escapes/
AC/rails/container metal) so occlusion tells you which structure a shot
came through and reflections differ per street.

Style: sunset sky + fixed dusk-lavender ambient (calibrated for the toon
shader's 1/PI light response), warm low sun, neon sign columns, shop signs,
lantern strings, billboard glow, underpass strip lights.

Verified: aerial + street-level + third-person captures; movement 11/11,
smoke 0 failures, acoustics ALL PASSED.

Co-Authored-By: Claude Fable 5 <[email protected]>
This commit is contained in:
Nicholas Butzke
2026-07-18 14:18:06 -04:00
co-authored by Claude Fable 5
parent a51595e3b9
commit 0813d0b40d
6 changed files with 331 additions and 5 deletions
+3 -2
View File
@@ -90,8 +90,9 @@ func _box_static(pos: Vector3, size: Vector3, color: Color, node_name: String =
return body
func _ramp_static(pos: Vector3, size: Vector3, rot_deg: Vector3, color: Color, node_name: String = "") -> StaticBody3D:
var body := _box_static(pos, size, color, node_name)
func _ramp_static(pos: Vector3, size: Vector3, rot_deg: Vector3, color: Color, node_name: String = "",
acoustic: String = "") -> StaticBody3D:
var body := _box_static(pos, size, color, node_name, acoustic)
body.rotation_degrees = rot_deg
return body
+17 -3
View File
@@ -2,17 +2,21 @@ extends SceneTree
## Dev tool: launch with rendering, screenshot the main menu and a level,
## then quit. Run:
## godot --path . -s res://debug/visual_capture.gd -- <output_dir>
## Screenshots land in <output_dir>/shot_menu.png and shot_level.png.
## godot --path . -s res://debug/visual_capture.gd -- <output_dir> [scene_path]
## Screenshots land in <output_dir>/shot_menu.png, shot_level.png, shot_tp_run.png
## and shot_aerial.png. scene_path defaults to the test level.
var _frames := 0
var _out_dir := "."
var _scene := "res://scenes/maps/test_level/test_level.tscn"
func _initialize() -> void:
var args := OS.get_cmdline_user_args()
if args.size() > 0:
_out_dir = args[0]
if args.size() > 1:
_scene = args[1]
change_scene_to_file("res://ui/main_menu/main_menu.tscn")
@@ -23,7 +27,7 @@ func _process(_delta: float) -> bool:
var nm = root.get_node_or_null("NetworkManager")
if nm and nm.has_method("start_singleplayer_match"):
nm.start_singleplayer_match("Deathmatch")
change_scene_to_file("res://scenes/maps/test_level/test_level.tscn")
change_scene_to_file(_scene)
elif _frames == 240:
_shot("level")
# Third person + run forward, to eyeball model grounding and animation
@@ -34,6 +38,16 @@ func _process(_delta: float) -> bool:
elif _frames == 320:
_shot("tp_run")
Input.action_release("move_forward")
# Aerial overview of the whole map
var cam := root.get_camera_3d()
if cam:
var aerial := Camera3D.new()
current_scene.add_child(aerial)
aerial.global_position = Vector3(0, 55, 42)
aerial.look_at(Vector3(0, 0, -5), Vector3.UP)
aerial.current = true
elif _frames == 340:
_shot("aerial")
return true
return false