94 lines
4.4 KiB
Markdown
94 lines
4.4 KiB
Markdown
# 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.
|