Feat/visual audio overhaul #21

Merged
Dotts merged 31 commits from feat/visual-audio-overhaul into main 2026-07-21 14:09:18 -07:00
81 changed files with 194 additions and 24 deletions
Showing only changes of commit f62f4f2503 - Show all commits
+23
View File
@@ -0,0 +1,23 @@
Nature Kit (2.1)
Created/distributed by Kenney (www.kenney.nl)
Creation date: 29-04-2020 01:02
------------------------------
License: (Creative Commons Zero, CC0)
http://creativecommons.org/publicdomain/zero/1.0/
This content is free to use in personal, educational and commercial projects.␍
Support us by crediting Kenney or www.kenney.nl (this is not mandatory)
------------------------------
Donate: http://support.kenney.nl
Request: http://request.kenney.nl
Patreon: http://patreon.com/kenney/
Follow on Twitter for updates:
http://twitter.com/KenneyNL
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.

After

Width:  |  Height:  |  Size: 8.5 KiB

Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
+36
View File
@@ -0,0 +1,36 @@
extends SceneTree
## Dev tool: print AABBs of prop models used by the city builder.
const PATHS := [
"res://assets/props/roads/road-straight.glb",
"res://assets/props/roads/road-crossroad-line.glb",
"res://assets/props/roads/road-crossing.glb",
"res://assets/props/roads/light-curved.glb",
"res://assets/props/roads/light-curved-double.glb",
"res://assets/props/roads/construction-barrier.glb",
"res://assets/props/roads/construction-cone.glb",
"res://assets/props/nature/tree_default.glb",
"res://assets/props/nature/tree_detailed.glb",
"res://assets/props/nature/tree_oak.glb",
"res://assets/props/nature/tree_tall.glb",
]
func _initialize() -> void:
for p in PATHS:
var scene = load(p)
if scene == null:
print("measure: FAILED ", p)
continue
var inst: Node3D = scene.instantiate()
get_root().add_child(inst)
var aabb := AABB()
var first := true
for mi in inst.find_children("*", "MeshInstance3D", true, false):
var b: AABB = mi.global_transform * mi.get_aabb()
aabb = b if first else aabb.merge(b)
first = false
print("measure: %s size=%s min=%s" % [p.get_file(), aabb.size, aabb.position])
inst.queue_free()
quit()
+1
View File
@@ -0,0 +1 @@
uid://dd4g4l7mg66ro
+134 -24
View File
@@ -134,9 +134,25 @@ func _kit_building(key: String, front_pos: Vector3, yaw_deg: float, node_name: S
inst.scale = Vector3.ONE * scale_f inst.scale = Vector3.ONE * scale_f
body.add_child(inst) body.add_child(inst)
LevelMaterials.apply_toon_recursive(inst, 0.0) LevelMaterials.apply_toon_recursive(inst, 0.0)
# Subtle per-building tint so repeated kit models read as different shops
_tint_recursive(inst, Color(1, 1, 1).lerp(Color.from_hsv(_rng.randf(), 0.3, 1.0), 0.16))
return w return w
func _tint_recursive(node: Node, tint: Color) -> void:
if node is MeshInstance3D:
var mi := node as MeshInstance3D
var sc: int = mi.mesh.get_surface_count() if mi.mesh else 0
for s in sc:
var m := mi.get_surface_override_material(s)
if m is ShaderMaterial:
var c = m.get_shader_parameter("albedo_color")
if c is Color:
m.set_shader_parameter("albedo_color", c * tint)
for child in node.get_children():
_tint_recursive(child, tint)
## Fill one street-facing edge of a lot with kit buildings + Akiba signage. ## Fill one street-facing edge of a lot with kit buildings + Akiba signage.
func _kit_fill_side(front_x: float, dir: int, z0: float, z1: float, seed_id: String) -> void: func _kit_fill_side(front_x: float, dir: int, z0: float, z1: float, seed_id: String) -> void:
var yaw := -90.0 if dir > 0 else 90.0 # face the street (-x for east row) var yaw := -90.0 if dir > 0 else 90.0 # face the street (-x for east row)
@@ -252,6 +268,7 @@ func _build_geometry() -> void:
_build_block(bx, bz) _build_block(bx, bz)
_build_rail_line() _build_rail_line()
_build_streets()
_build_avenues() _build_avenues()
if _spawn_points.is_empty(): if _spawn_points.is_empty():
@@ -430,12 +447,14 @@ func _shrine_block(c: Vector3, bx: int, bz: int) -> void:
# Hall with slide roof # Hall with slide roof
_box_static(c + Vector3(0, 2.0, -10.0), Vector3(12.0, 4.0, 8.0), WOOD.darkened(0.2), n + "_Hall", "wood") _box_static(c + Vector3(0, 2.0, -10.0), Vector3(12.0, 4.0, 8.0), WOOD.darkened(0.2), n + "_Hall", "wood")
_ramp_static(c + Vector3(0, 4.9, -8.2), Vector3(13.0, 0.3, 5.6), Vector3(-24, 0, 0), VERMILION.darkened(0.35), n + "_Roof", "wood") _ramp_static(c + Vector3(0, 4.9, -8.2), Vector3(13.0, 0.3, 5.6), Vector3(-24, 0, 0), VERMILION.darkened(0.35), n + "_Roof", "wood")
# Stone lanterns + trees (trunk static, canopy deco) # Stone lanterns + real modeled trees (trunk collider under each)
for i in 2: for i in 2:
var lx := -8.0 + 16.0 * float(i) var lx := -8.0 + 16.0 * float(i)
_box_static(c + Vector3(lx, 1.0, 8.0), Vector3(1.0, 2.0, 1.0), Color(0.55, 0.55, 0.52), n + "_Lant%d" % i, "brick") _box_static(c + Vector3(lx, 1.0, 8.0), Vector3(1.0, 2.0, 1.0), Color(0.55, 0.55, 0.52), n + "_Lant%d" % i, "brick")
_box_static(c + Vector3(lx, 1.6, -2.0), Vector3(0.7, 3.2, 0.7), TRUNK, n + "_Trunk%d" % i, "wood") _box_static(c + Vector3(lx, 1.6, -2.0), Vector3(0.8, 3.2, 0.8), TRUNK, n + "_Trunk%d" % i, "wood")
_deco_box(c + Vector3(lx, 4.6, -2.0), Vector3(4.2, 3.4, 4.2), LEAF) _kit_prop_path("res://assets/props/nature/" + ["tree_detailed.glb", "tree_default.glb"][i % 2],
c + Vector3(lx, 0, -2.0), _rng.randf_range(0.0, 360.0), 7.0)
_kit_prop_path("res://assets/props/nature/tree_oak.glb", c + Vector3(0, 0, 2.0), _rng.randf_range(0.0, 360.0), 6.0)
_spawn_points.append(c + Vector3(0, 1.5, 12)) _spawn_points.append(c + Vector3(0, 1.5, 12))
@@ -470,12 +489,12 @@ func _market_block(c: Vector3, bx: int, bz: int) -> void:
## Plaza: open ground; the exact centre cell hosts the giant screen tower. ## Plaza: open ground; the exact centre cell hosts the giant screen tower.
func _plaza_block(c: Vector3, bx: int, bz: int) -> void: func _plaza_block(c: Vector3, bx: int, bz: int) -> void:
var n := "Plaza_%d_%d" % [bx, bz] var n := "Plaza_%d_%d" % [bx, bz]
# Planter cover ring # Planter cover ring with real trees
for i in 4: for i in 4:
var a := TAU * float(i) / 4.0 + PI / 4.0 var a := TAU * float(i) / 4.0 + PI / 4.0
var p := c + Vector3(cos(a), 0, sin(a)) * (BLOCK * 0.32) var p := c + Vector3(cos(a), 0, sin(a)) * (BLOCK * 0.32)
_box_static(Vector3(p.x, 0.55, p.z), Vector3(4.0, 1.1, 4.0), Color(0.5, 0.48, 0.52), "%s_Pl%d" % [n, i], "brick") _box_static(Vector3(p.x, 0.55, p.z), Vector3(4.0, 1.1, 4.0), Color(0.5, 0.48, 0.52), "%s_Pl%d" % [n, i], "brick")
_deco_box(Vector3(p.x, 1.5, p.z), Vector3(3.2, 1.0, 3.2), LEAF) _kit_prop_path("res://assets/props/nature/tree_oak.glb", Vector3(p.x, 1.0, p.z), float(i) * 90.0, 4.5)
# The Crossing screen tower on the single centre-most plaza cell # The Crossing screen tower on the single centre-most plaza cell
if bx == 5 and bz == 4: if bx == 5 and bz == 4:
_box_static(c + Vector3(0, 9.0, 0), Vector3(6.0, 18.0, 6.0), METAL.darkened(0.2), n + "_ScreenTower", "metal") _box_static(c + Vector3(0, 9.0, 0), Vector3(6.0, 18.0, 6.0), METAL.darkened(0.2), n + "_ScreenTower", "metal")
@@ -511,6 +530,13 @@ func _construction_block(c: Vector3, bx: int, bz: int) -> void:
for i in 3: for i in 3:
_box_static(c + Vector3(10, 1.3 + 2.6 * float(mini(i, 1)), -12.0 + float(i) * 3.2), Vector3(6.2, 2.6, 2.6), _box_static(c + Vector3(10, 1.3 + 2.6 * float(mini(i, 1)), -12.0 + float(i) * 3.2), Vector3(6.2, 2.6, 2.6),
cc[i], "%s_Cont%d" % [n, i], "metal") cc[i], "%s_Cont%d" % [n, i], "metal")
# Cones + barriers scattered around the site entrance
for i in 4:
_kit_prop_path("res://assets/props/roads/construction-cone.glb",
c + Vector3(-16.0 + float(i) * 4.0, 0.1, 18.0), 0.0, 8.0)
for i in 2:
_kit_prop_path("res://assets/props/roads/construction-barrier.glb",
c + Vector3(-14.0 + float(i) * 12.0, 0.1, 14.0), float(i * 30), 8.0)
_spawn_points.append(c + Vector3(14, 1.5, -14)) _spawn_points.append(c + Vector3(14, 1.5, -14))
const INK_COLOR := Color(0.08, 0.07, 0.1) const INK_COLOR := Color(0.08, 0.07, 0.1)
@@ -543,26 +569,110 @@ func _build_rail_line() -> void:
_spawn_points.append(Vector3(0, RAIL_TOP + 1.5, z)) _spawn_points.append(Vector3(0, RAIL_TOP + 1.5, z))
# ── Main avenues: lights + crosswalks ──────────────────────────────────────── # ── Streets: real road meshes with markings ──────────────────────────────────
const ROAD_W := 12.0 # visual road width between sidewalk aprons
## Street lines run between block columns/rows at multiples of PITCH.
func _street_lines() -> Array[float]:
var lines: Array[float] = []
for i in GRID - 1:
lines.append((float(i) - float(GRID) * 0.5 + 1.0) * PITCH)
return lines
func _road_piece(key: String, pos: Vector3, yaw_deg: float, sc: Vector3) -> void:
var inst: Node3D = _kit_scene_at("res://assets/props/roads/" + key + ".glb").instantiate()
inst.scale = sc
add_child(inst)
inst.global_position = pos
inst.rotation_degrees.y = yaw_deg
LevelMaterials.apply_toon_recursive(inst, 0.0)
# The kit's pale concrete clips to white under the map lighting
_tint_recursive(inst, Color(0.55, 0.55, 0.6))
var _path_cache: Dictionary = {}
func _kit_scene_at(path: String) -> PackedScene:
if not _path_cache.has(path):
_path_cache[path] = load(path)
return _path_cache[path]
func _build_streets() -> void:
var lines := _street_lines()
var seg := PITCH - ROAD_W # straight run between intersections
var y := 0.02
# Intersections with line markings
for x in lines:
for z in lines:
_road_piece("road-crossroad-line", Vector3(x, y, z), 0.0, Vector3(ROAD_W, 2.0, ROAD_W))
# Straight segments (stretched single meshes) + edge stubs to the wall
for x in lines:
for i in lines.size() + 1:
var z0 := -CITY_HALF if i == 0 else lines[i - 1] + ROAD_W * 0.5
var z1 := CITY_HALF if i == lines.size() else lines[i] - ROAD_W * 0.5
if z1 - z0 < 2.0:
continue
_road_piece("road-straight", Vector3(x, y, (z0 + z1) * 0.5), 0.0, Vector3(ROAD_W, 2.0, z1 - z0))
for z in lines:
for i in lines.size() + 1:
var x0 := -CITY_HALF if i == 0 else lines[i - 1] + ROAD_W * 0.5
var x1 := CITY_HALF if i == lines.size() else lines[i] - ROAD_W * 0.5
if x1 - x0 < 2.0:
continue
_road_piece("road-straight", Vector3((x0 + x1) * 0.5, y, z), 90.0, Vector3(ROAD_W, 2.0, x1 - x0))
# Overhead cable bundles across east-west streets (urban-Japan clutter)
for z in lines:
var x := -CITY_HALF + 24.0
while x < CITY_HALF - 24.0:
if absf(x) > 14.0: # keep the central avenue sky clear
var h := 9.5 + fmod(absf(x), 3.0) * 0.4
for s3 in 3:
var t0 := float(s3) / 3.0
var t1 := float(s3 + 1) / 3.0
var sag0 := sin(t0 * PI) * 0.7
var sag1 := sin(t1 * PI) * 0.7
var za := z - STREET * 0.5 + STREET * t0
var zb := z - STREET * 0.5 + STREET * t1
var mid := Vector3(x, h - (sag0 + sag1) * 0.5, (za + zb) * 0.5)
_deco_box(mid, Vector3(0.07, 0.07, zb - za + 0.1), INK_COLOR)
x += 48.0
else:
x += 48.0
# ── Main avenues: kit streetlights ───────────────────────────────────────────
func _build_avenues() -> void: func _build_avenues() -> void:
# The two central avenues (x=0 and z=0) get matched streetlights and var lines := _street_lines()
# zebra crossings at every block line. var lamp_scale := 10.0
var zline := -CITY_HALF + PITCH * 0.5 for z in lines:
while zline <= CITY_HALF:
for side: float in [-1.0, 1.0]: for side: float in [-1.0, 1.0]:
var x := side * (STREET * 0.5 + 0.6) # Double-arm lights along the central N-S avenue at every block line
_box_static(Vector3(x, 3.25, zline), Vector3(0.28, 6.5, 0.28), METAL, "LampA_%d_%d" % [int(zline), int(side)], "metal") var x := side * (ROAD_W * 0.5 + 0.4)
_box_static(Vector3(x - side * 1.5, 6.35, zline), Vector3(3.0, 0.22, 0.22), METAL, "LampArmA_%d_%d" % [int(zline), int(side)], "metal") _box_static(Vector3(x, 3.4, z), Vector3(0.26, 6.8, 0.26), METAL, "LampP_%d_%d" % [int(z), int(side)], "metal")
_deco_box(Vector3(x - side * 2.8, 6.2, zline), Vector3(0.9, 0.18, 0.4), Color(1.0, 0.95, 0.8), true) _kit_prop_path("res://assets/props/roads/light-curved.glb",
# Crosswalk across the x=0 avenue at each block line Vector3(x, 0, z), 90.0 if side > 0 else -90.0, lamp_scale)
for s in 5: for x in lines:
var sxx := -6.0 + 3.0 * float(s) if absf(x) < 1.0:
_deco_box(Vector3(sxx, 0.03, zline + PITCH * 0.5 - 4.0), Vector3(0.9, 0.06, 3.2), STRIPE) continue
zline += PITCH # Single lights down the central E-W avenue
var xline := -CITY_HALF + PITCH * 0.5
while xline <= CITY_HALF:
for side: float in [-1.0, 1.0]: for side: float in [-1.0, 1.0]:
var z2 := side * (STREET * 0.5 + 0.6) var z2 := side * (ROAD_W * 0.5 + 0.4)
_box_static(Vector3(xline, 3.25, z2), Vector3(0.28, 6.5, 0.28), METAL, "LampB_%d_%d" % [int(xline), int(side)], "metal") _kit_prop_path("res://assets/props/roads/light-curved.glb",
xline += PITCH Vector3(x, 0, z2), 0.0 if side > 0 else 180.0, lamp_scale)
func _kit_prop_path(path: String, pos: Vector3, yaw_deg: float, scale_f: float) -> void:
var inst: Node3D = _kit_scene_at(path).instantiate()
inst.scale = Vector3.ONE * scale_f
add_child(inst)
inst.global_position = pos
inst.rotation_degrees.y = yaw_deg
# Nature-kit foliage uses vertex-colored materials that the toon swap
# mangles (cyan trees) — keep original materials; the faceted low-poly
# look already reads cel under this lighting.
if not path.contains("/nature/"):
LevelMaterials.apply_toon_recursive(inst, 0.0)