Files

94 lines
4.4 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Eight windows and random entry
## Layout
`scripts/room.gd` now builds **eight windows, two per wall** (four walls), spaced
symmetrically about each wall centre. `WIN_EDGE_GAP = 2.4 m` is the wall left between a
window edge and the room corner, which for an 18 m wall with 4 m windows gives: openings
centred at ±4.6 m, 2.4 m of wall at each corner, and a **5.2 m pillar** between the two
openings. The number of windows follows from the constants:
```gdscript
const WINDOWS_PER_WALL := 2
const WIN_EDGE_GAP := 2.4
static func window_offsets(length: float) -> Array[float]
```
`window_offsets()` works for any count: centres are spread evenly between
±(length/2 − WIN_W/2 − WIN_EDGE_GAP), so raising `WINDOWS_PER_WALL` widens the row
instead of pushing openings out of the wall, and a single window stays centred.
The wall builder was generalised from "one opening in the middle" to any number of
openings: solid pieces along the wall between openings and at both ends, plus a sill and
a header per opening. The room-space UVs (see `OFFICE-SURFACES.md`) are unchanged: a
segment is mapped from its own world position, so the extra openings do not restart the
pattern. With two openings per wall there are 7 segments per wall, 29 surfaces in total
(counted from the constants by `test_office_uv.gd`).
## Spawn data
Every window publishes one record:
```gdscript
windows.append({"center": center, "normal": wall.normal, "axis": wall.axis,
"slots": slots, "glass": glass})
```
- `center`: a point on the room-side wall face at y = 0;
- `normal`: pointing into the room;
- `slots`: `SPAWN_SLOTS = 4` points spread across the opening, `SPAWN_OUTSIDE = 1.2 m`
outside the wall;
- `glass`: the pane of that specific window.
The old `window_spawn_points` and `window_normals` arrays are still filled and are now
actually consumed — they were computed and ignored before, which was one of the known
anomalies of this prototype.
## Entry logic
`main.gd` no longer uses four hardcoded cardinal centres:
- `_pick_window()` draws a random window and **never repeats the previous one**, so
successive zombies come from different openings instead of always the same wall;
- a random slot inside that window is picked, so even the same window is entered from a
different spot;
- the entry tween is unchanged (1.2 s rising to sill height, then 0.8 s into the room);
- only **that** window's glass is shattered (looked up by identity) instead of scanning
every pane and guessing by distance.
## Notes and limits
- With eight openings, three of the window-to-centre diagonals are crossed by furniture
(the rotated chair at (6.8, 0, −4) and the two desks). This is not a defect: the A*
grid routes zombies around it, and `test_office_atmosphere.gd` now asserts what
matters — every window is a real opening **and** every window is connected to the room
centre through the navigation grid. It prints a note for the obstructed diagonals.
- Zombies entering from eight directions spend visibly less time in a queue at one wall,
which changes the pacing a little; wave sizes are untouched (`4 + 2n`).
## Verification
```sh
"$G" --headless --path . --script res://tools/test_spawn_windows.gd
"$G" --display-driver x11 --rendering-method gl_compatibility --path . --script res://tools/shot_windows.gd
```
`test_spawn_windows.gd` checks: eight windows, two per wall, symmetric, with at least 1 m
of wall at the corners and the expected pillar; 32 spawn slots, all outside the room,
aligned with their opening and at the right distance; 400 random draws covering all eight
windows with no immediate repetition; a ray proving each opening is a real hole in the
wall while the pillar between the openings is solid; six real spawns, all starting
outside and ending inside with the correct pane shattered (counted by identity, so two
zombies using the same window break it once).
Two traps met while writing it, both worth remembering:
1. the **first wave starts automatically in `_ready`**, so a test that counts panes must
wait for that wave and its tweens, otherwise the counts are polluted;
2. physics ray queries need `await physics_frame` after building the room, otherwise
`direct_space_state` is still empty and the assertions pass or fail for the wrong
reason.
Images `/tmp/zombie-windows-{nord,est,sud,ovest,angolo,ingresso}.png` show the two
openings per wall, the pillar between them, and a group of zombies that came in.