129 lines
5.9 KiB
GDScript
129 lines
5.9 KiB
GDScript
extends SceneTree
|
|
## Verifica finestre multiple e spawn casuale da finestre diverse.
|
|
##
|
|
## Ordine voluto: prima i controlli sui DATI della stanza (immediati e indipendenti
|
|
## dal gioco), poi la parte con gli spawn, che richiede di aspettare la prima ondata
|
|
## automatica e i suoi tween.
|
|
func _initialize() -> void:
|
|
call_deferred("run_test")
|
|
|
|
func run_test() -> void:
|
|
var world = load("res://scenes/main.tscn").instantiate()
|
|
root.add_child(world)
|
|
var room = world.room
|
|
var walls := 4
|
|
|
|
# --- finestre: almeno otto, due per muro, distribuite in modo simmetrico ---
|
|
assert(room.WINDOWS_PER_WALL == 2)
|
|
var expected: int = room.WINDOWS_PER_WALL * walls
|
|
assert(room.windows.size() == expected and expected >= 8)
|
|
assert(room.window_spawn_points.size() == expected * room.SPAWN_SLOTS)
|
|
assert(room.window_normals.size() == room.window_spawn_points.size())
|
|
assert(room.glass_panes.size() == expected) # nessun vetro rotto prima delle ondate
|
|
var sides := {}
|
|
for window in room.windows:
|
|
var center: Vector3 = window.center
|
|
var on_x := absf(center.z) > absf(center.x) # muro nord/sud
|
|
sides[("x" if on_x else "z")] = int(sides.get("x" if on_x else "z", 0)) + 1
|
|
var slots: Array = window.slots
|
|
assert(slots.size() == room.SPAWN_SLOTS)
|
|
assert(is_instance_valid(window.glass))
|
|
for slot in slots:
|
|
assert(not (absf(slot.x) <= 9.0 and absf(slot.z) <= 9.0)) # fuori dalla stanza
|
|
assert(is_equal_approx(window.normal.dot(slot - center), -room.SPAWN_OUTSIDE))
|
|
assert(absf((slot - center).dot(Vector3.UP)) < 0.001)
|
|
assert(sides.size() == 2 and sides["x"] == walls and sides["z"] == walls) # 4 finestre per asse
|
|
var north_centers: Array[float] = []
|
|
for window in room.windows:
|
|
if absf(window.center.z + 9.0) < 0.01:
|
|
north_centers.append(window.center.x)
|
|
north_centers.sort()
|
|
# Geometria, non formula: simmetria, margine agli angoli e pilastro fra le aperture.
|
|
var limit: float = room.W * 0.5 - room.WIN_W * 0.5
|
|
for i in north_centers.size():
|
|
assert(is_equal_approx(north_centers[i], -north_centers[north_centers.size() - 1 - i]))
|
|
assert(limit - absf(north_centers[i]) >= 1.0) # almeno 1 m di muro all'angolo
|
|
var pillar: float = room.W - 2.0 * room.WIN_EDGE_GAP - 2.0 * room.WIN_W
|
|
assert(pillar >= 1.0)
|
|
assert(is_equal_approx(north_centers[1] - north_centers[0] - room.WIN_W, pillar))
|
|
print("PASS: %d finestre, due per muro a %.1f m dal centro, pilastro %.1f m fra le aperture" % [room.windows.size(), north_centers[1], pillar])
|
|
|
|
# --- le finestre sono aperture vere: si vede il cielo attraverso ---
|
|
await physics_frame # lo spazio fisico va aggiornato, altrimenti le query non vedono nulla
|
|
await physics_frame
|
|
var space = world.get_world_3d().direct_space_state
|
|
for window in room.windows:
|
|
var center: Vector3 = window.center + Vector3(0, room.WIN_Y0 + room.WIN_H * 0.5, 0) # centro apertura
|
|
var query := PhysicsRayQueryParameters3D.create(center, center - Vector3(window.normal) * 3.0, 1)
|
|
assert(space.intersect_ray(query).is_empty()) # nessun muro davanti all'apertura
|
|
var pillar_ray := PhysicsRayQueryParameters3D.create(Vector3(0, 2.5, -6.0), Vector3(0, 2.5, -9.6), 1) # dall'interno verso il muro
|
|
assert(not space.intersect_ray(pillar_ray).is_empty()) # il pilastro fra le due finestre c'e'
|
|
print("PASS: le otto aperture sono libere e i pilastri fra le finestre sono solidi")
|
|
|
|
# --- selezione casuale, mai la stessa finestra due volte di fila ---
|
|
var hits := {}
|
|
var repeats := 0
|
|
world.last_window = -1
|
|
for i in 400:
|
|
var picked: int = world._pick_window()
|
|
assert(picked >= 0 and picked < room.windows.size())
|
|
if picked == world.last_window:
|
|
repeats += 1
|
|
hits[picked] = int(hits.get(picked, 0)) + 1
|
|
world.last_window = picked
|
|
assert(repeats == 0)
|
|
assert(hits.size() == expected) # tutte le finestre vengono usate
|
|
var minimum := 400
|
|
for count in hits.values():
|
|
minimum = mini(minimum, count)
|
|
assert(minimum > 10) # non sempre le stesse due
|
|
print("PASS: 400 estrazioni su %d finestre, nessuna ripetizione immediata, minimo %d per finestra" % [hits.size(), minimum])
|
|
|
|
# --- da qui servono gli spawn: prima si aspetta la prima ondata automatica ---
|
|
world.player.hp = 100000
|
|
world.spawning = true
|
|
world.wave_pending = true # nessuna nuova ondata
|
|
var guard := 0
|
|
while world.spawning and guard < 200:
|
|
await create_timer(0.1).timeout
|
|
guard += 1
|
|
await create_timer(2.4).timeout # fine dei tween d'ingresso dell'ondata
|
|
for zombie in get_nodes_in_group("live_zombies"):
|
|
zombie.set_physics_process(false)
|
|
|
|
# --- spawn reale: ogni zombie esce e rientra dalla propria finestra ---
|
|
var before: int = room.glass_panes.size()
|
|
var intact := {}
|
|
for i in room.windows.size():
|
|
intact[i] = is_instance_valid(room.windows[i].glass)
|
|
var spawned: Array = []
|
|
var windows_used := {}
|
|
for i in 6:
|
|
world._spawn()
|
|
spawned.append(world.get_child(world.get_child_count() - 1))
|
|
windows_used[world.last_window] = true # _pick_window registra la scelta
|
|
assert(windows_used.size() >= 3) # non tutti dalla stessa apertura
|
|
var used := {}
|
|
for zombie in spawned:
|
|
assert(not (absf(zombie.position.x) <= 9.0 and absf(zombie.position.z) <= 9.0))
|
|
used[Vector2i(roundi(zombie.position.x * 0.5), roundi(zombie.position.z * 0.5))] = true
|
|
assert(used.size() >= 3)
|
|
await create_timer(2.6).timeout # tween d'ingresso: 1,2 + 0,8 s
|
|
for zombie in spawned:
|
|
if is_instance_valid(zombie):
|
|
assert(absf(zombie.position.x) <= 9.0 and absf(zombie.position.z) <= 9.0) # dentro
|
|
assert(not zombie.entering)
|
|
# Identita', non solo conteggio: si rompe il vetro della finestra usata, e una volta
|
|
# sola anche se due zombie entrano dalla stessa apertura.
|
|
var broken_by_me := 0
|
|
for index in windows_used.keys():
|
|
assert(intact.has(index))
|
|
if intact[index]:
|
|
broken_by_me += 1
|
|
assert(not is_instance_valid(room.windows[index].glass))
|
|
assert(room.glass_panes.size() == before - broken_by_me)
|
|
print("PASS: 6 zombie entrati dall'esterno usando %d finestre diverse, %d vetri rotti, tutti dentro" % [windows_used.size(), broken_by_me])
|
|
world.queue_free()
|
|
await process_frame
|
|
quit()
|