Visual polish pass (v0.2.0): phase lighting, street lamps, marquee, dressing, night screenshots
- Phase-based lighting: sun direction/energy/color, ProceduralSkyMaterial gradient, and ambient per shift phase (GameManager.PHASE_LIGHTING), applied on phase transitions and shift start - WorldBuilder: street lamp poles with emissive bulbs + OmniLights, set_night_mode(), glowing STEP LINE marquee (Label3D + emissive bars), crosswalk stripes, planters, low-poly street trees - NPC avatars: per-seed height/brightness variation (deterministic LCG) - Denser routine traffic probabilities - capture_screenshots.gd: fast-forward to LATE phase and capture night set; README gallery is now 2x3 day+night; docs/screenshots regenerated - Version bumped to 0.2.0; build/ artifacts rebuilt; Linux binary smoke-tested - New headless tests for phased lighting config and street dressing (56 total)
This commit is contained in:
1 parent
93883334d0
commit
513f8a0f60
21 files changed
+280
-25
No files matched your search
@@ -7,6 +7,12 @@ var root: Node3D = null
|
||||
## Door lock indicator mesh near the handle; toggled by GameManager.
|
||||
var door_indicator: MeshInstance3D = null
|
||||
var _door_indicator_mat: StandardMaterial3D = null
|
||||
## Street lamps and signage so night mode can switch them on.
|
||||
var _street_lamps: Array[MeshInstance3D] = []
|
||||
var _lamp_omni: Array[OmniLight3D] = []
|
||||
var _lamp_bulb_mats: Array[StandardMaterial3D] = []
|
||||
var marquee_label: Label3D = null
|
||||
var _marquee_emissive: Array[StandardMaterial3D] = []
|
||||
|
||||
func _init(root_node: Node3D) -> void:
|
||||
root = root_node
|
||||
@@ -14,11 +20,15 @@ func _init(root_node: Node3D) -> void:
|
||||
func build() -> void:
|
||||
_build_ground()
|
||||
_build_building()
|
||||
_build_marquee()
|
||||
_build_steps()
|
||||
_build_sidewalk()
|
||||
_build_street()
|
||||
_build_crosswalk()
|
||||
_build_street_furniture()
|
||||
_build_guard_spawn()
|
||||
_build_navmesh()
|
||||
set_night_mode(false)
|
||||
|
||||
func _add_box(parent: Node3D, size: Vector3, pos: Vector3, color: Color, cast_shadow: bool = false) -> MeshInstance3D:
|
||||
var mesh := BoxMesh.new()
|
||||
@@ -127,6 +137,112 @@ func _build_navmesh() -> void:
|
||||
region.navigation_mesh = mesh
|
||||
root.add_child(region)
|
||||
|
||||
func _build_marquee() -> void:
|
||||
## Neon-style marquee strip above the door: emissive bars + a label.
|
||||
var strip_parent := Node3D.new()
|
||||
strip_parent.name = "Marquee"
|
||||
for offset in [-2.2, 2.2]:
|
||||
var bar := _add_box(strip_parent, Vector3(0.25, 0.5, 0.5), Vector3(offset, 7.4, -3.6), Color(1, 0.35, 0.75))
|
||||
var mat := _emissive_material(Color(1.0, 0.35, 0.75))
|
||||
bar.material_override = mat
|
||||
_marquee_emissive.append(mat)
|
||||
marquee_label = Label3D.new()
|
||||
marquee_label.name = "MarqueeLabel"
|
||||
marquee_label.text = "STEP LINE"
|
||||
marquee_label.position = Vector3(0, 7.3, -3.55)
|
||||
marquee_label.modulate = Color(1, 0.6, 0.9)
|
||||
marquee_label.font_size = 72
|
||||
marquee_label.pixel_size = 0.004
|
||||
marquee_label.outline_size = 12
|
||||
marquee_label.outline_modulate = Color(0.9, 0.15, 0.5)
|
||||
marquee_label.billboard = BaseMaterial3D.BILLBOARD_ENABLED
|
||||
marquee_label.no_depth_test = false
|
||||
strip_parent.add_child(marquee_label)
|
||||
root.add_child(strip_parent)
|
||||
|
||||
func _build_street_furniture() -> void:
|
||||
# Street lamps along the sidewalk (bulbs + omni lights, off by day).
|
||||
for side in [-7.5, 7.5]:
|
||||
var lamp := Node3D.new()
|
||||
lamp.name = "Lamp_%d" % int(side)
|
||||
_add_box(lamp, Vector3(0.22, 5.0, 0.22), Vector3(side, 2.5, 8.5), Color(0.16, 0.16, 0.18))
|
||||
_add_box(lamp, Vector3(1.6, 0.15, 0.15), Vector3(side + (0.8 if side < 0 else -0.8), 4.9, 8.5), Color(0.16, 0.16, 0.18))
|
||||
var bulb := _add_box(lamp, Vector3(0.16, 0.16, 0.5), Vector3(side + (0.8 if side < 0 else -0.8), 4.85, 8.5), Color(1, 1, 0.85))
|
||||
var bulb_mat := _emissive_material(Color(1.0, 1.0, 0.8))
|
||||
bulb.material_override = bulb_mat
|
||||
bulb.material_override.emission_energy_multiplier = 1.5
|
||||
_lamp_bulb_mats.append(bulb_mat)
|
||||
var omni := OmniLight3D.new()
|
||||
omni.position = Vector3(side + (0.8 if side < 0 else -0.8), 4.7, 8.5)
|
||||
omni.omni_range = 14.0
|
||||
omni.light_energy = 0.0
|
||||
omni.light_color = Color(1, 0.93, 0.75)
|
||||
lamp.add_child(omni)
|
||||
_lamp_omni.append(omni)
|
||||
root.add_child(lamp)
|
||||
_street_lamps.append(bulb)
|
||||
# Planters beside the steps.
|
||||
for side in [-4.6, 4.6]:
|
||||
var planter := _add_box(root, Vector3(1.1, 0.7, 1.1), Vector3(side, 0.35, 1.0), Color(0.42, 0.34, 0.28))
|
||||
planter.name = "Planter_%d" % int(side)
|
||||
# Low-poly trees along the street front.
|
||||
var trunk_color := Color(0.35, 0.25, 0.18)
|
||||
var leaf_color := Color(0.16, 0.42, 0.2)
|
||||
for i in 6:
|
||||
var x := -11.0 + i * 4.4
|
||||
var z := 4.0 + float((i * 7) % 5)
|
||||
var tree := Node3D.new()
|
||||
tree.name = "Tree_%d" % (i + 1)
|
||||
var trunk := MeshInstance3D.new()
|
||||
var trunk_mesh := CylinderMesh.new()
|
||||
trunk_mesh.top_radius = 0.09
|
||||
trunk_mesh.bottom_radius = 0.14
|
||||
trunk_mesh.height = 1.4
|
||||
trunk.mesh = trunk_mesh
|
||||
trunk.material_override = _plain_material(trunk_color)
|
||||
trunk.position = Vector3(x, 0.7, z)
|
||||
tree.add_child(trunk)
|
||||
var crown := MeshInstance3D.new()
|
||||
var crown_mesh := CylinderMesh.new()
|
||||
crown_mesh.top_radius = 0.05
|
||||
crown_mesh.bottom_radius = 0.85
|
||||
crown_mesh.height = 2.2
|
||||
crown.mesh = crown_mesh
|
||||
crown.material_override = _plain_material(leaf_color)
|
||||
crown.position = Vector3(x, 2.1, z)
|
||||
tree.add_child(crown)
|
||||
root.add_child(tree)
|
||||
|
||||
func _build_crosswalk() -> void:
|
||||
# White crosswalk stripes in front of the entrance on the street.
|
||||
for i in 8:
|
||||
_add_box(root, Vector3(0.8, 0.02, 0.5), Vector3(-2.8 + i * 0.85, 0.11, 17.0), Color(0.92, 0.92, 0.92))
|
||||
_add_box(root, Vector3(0.8, 0.02, 0.5), Vector3(-2.8 + i * 0.85, 0.11, 19.0), Color(0.92, 0.92, 0.92))
|
||||
|
||||
## Switch street lamps and signage to night mode (emissive + lights on).
|
||||
func set_night_mode(night: bool) -> void:
|
||||
for mat in _lamp_bulb_mats:
|
||||
mat.emission_energy_multiplier = (2.0 if night else 0.0)
|
||||
for omni in _lamp_omni:
|
||||
omni.light_energy = (3.0 if night else 0.0)
|
||||
for mat in _marquee_emissive:
|
||||
mat.emission_energy_multiplier = (2.0 if night else 0.2)
|
||||
if marquee_label:
|
||||
marquee_label.modulate.a = (1.0 if night else 0.9)
|
||||
|
||||
func _emissive_material(color: Color) -> StandardMaterial3D:
|
||||
var mat := StandardMaterial3D.new()
|
||||
mat.albedo_color = color
|
||||
mat.emission_enabled = true
|
||||
mat.emission = color
|
||||
mat.emission_energy_multiplier = 1.0
|
||||
return mat
|
||||
|
||||
func _plain_material(color: Color) -> StandardMaterial3D:
|
||||
var mat := StandardMaterial3D.new()
|
||||
mat.albedo_color = color
|
||||
return mat
|
||||
|
||||
func _build_guard_spawn() -> void:
|
||||
var marker := Marker3D.new()
|
||||
marker.name = "GuardSpawn"
|
||||
|
||||
Reference in new issue
Block a user