This commit is contained in:
Team3
2026-09-16 12:08:04 +02:00
parent 936773c4e9
commit 89fad5dc7a
12 changed files with 493 additions and 167 deletions

91
tests/_probe.gd Normal file
View File

@@ -0,0 +1,91 @@
extends Node
var main: Node3D
func _ready() -> void:
seed(20240)
main = load("res://scenes/main.tscn").instantiate()
add_child(main)
await get_tree().process_frame
main.ui.schliessen()
main._erde()
await get_tree().process_frame
# B: engste Wege mit Türen und Treppen
var liste: Array = []
for m in HumanDB.LIST:
var r: Array = m["routine"]
for i in range(r.size()):
var von: String = String(r[i - 1][1]) if i > 0 else String(r[r.size() - 1][1])
var nach: String = String(r[i][1])
if von == nach:
continue
var pts: Array = Orte.route_voll(HumanDB.PLACES, von, nach, Vector3.ZERO, m.get("etage", {}), HumanDB.NETZ, HumanDB.ANKER)
var l := 0.0
var pos := Orte.center(HumanDB.PLACES, von) + Vector3(0, Orte.hoehe(int(m.get("etage", {}).get(von, 0))), 0)
for pt in pts:
l += pos.distance_to(pt)
pos = pt
var slot_h: float = (float(r[i + 1][0]) - float(r[i][0])) if i + 1 < r.size() else (24.0 - float(r[i][0]))
liste.append([slot_h * 15.0 - l / 8.0, "%s %s->%s %.1fs / %.0fs" % [m["name"], von, nach, l / 8.0, slot_h * 15.0]])
liste.sort_custom(func(a, b): return a[0] < b[0])
for k in range(6):
print("ENG %s" % liste[k][1])
# C: Treppe hoch, was blockiert?
var sp: Player = main.player
var oben: Bewohner = null
for m in main.welt.humans:
if m.etage(str(m.data["heim"])) > 0:
oben = m
break
var heim := str(oben.data["heim"])
var pl: Dictionary = HumanDB.PLACES[heim]
print("HAUS %s size=%s dir=%s etagen=%d" % [heim, str(pl["size"]), pl["dir"], Orte.etagen(HumanDB.PLACES, heim)])
var t1 := Orte.treppe(HumanDB.PLACES, heim, 1)
var stufen: Array = Orte.treppen_lauf(HumanDB.PLACES, heim, 0)
sp.global_position = (stufen[0] as Vector3) + Vector3(0, 0.3, 0)
sp.velocity = Vector3.ZERO
var lauf: Vector3 = stufen[1] - stufen[0]
lauf.y = 0.0
sp.yaw = atan2(-lauf.x, -lauf.z)
Input.action_press("vor")
var hoechste := 0.0
for i in range(70):
await get_tree().physics_frame
hoechste = maxf(hoechste, sp.global_position.y)
if i % 10 == 9 or i == 69:
var k := sp.get_last_slide_collision()
var txt := "-"
if k != null and k.get_collider() != null:
var body: Node = k.get_collider()
var mi: Node = body.get_parent()
txt = "%s pos=%s size=%s normal=%s" % [mi.name, str(mi.global_position), str((mi as MeshInstance3D).mesh.get("size")) if mi is MeshInstance3D else "?", str(k.get_normal())]
print("TREPPE f=%d pos=%s y=%.2f koll=%s" % [i, str(sp.global_position), sp.global_position.y, txt])
Input.action_release("vor")
print("TREPPE hoechste=%.2f t1=%s" % [hoechste, str(t1)])
# E: Verfolgung -- wo reißt die Leine?
var mensch: Bewohner = main.welt.humans[0]
sp.global_position = mensch.global_position + Vector3(0, 0.3, 0)
sp.velocity = Vector3.ZERO
sp.folgt = mensch
var weiteste := 0.0
for i in range(2400):
await get_tree().physics_frame
var d := sp.global_position.distance_to(mensch.global_position)
if d > weiteste:
weiteste = d
if d > 6.0 and i % 5 == 0:
var k := sp.get_last_slide_collision()
var txt := "-"
if k != null and k.get_collider() != null:
var mi: Node = (k.get_collider() as Node).get_parent()
txt = "%s pos=%s" % [mi.name, str(mi.global_position)]
print("LEINE f=%d d=%.1f geist=%s mensch=%s ort=%s pfad=%d koll=%s" % [i, d, str(sp.global_position), str(mensch.global_position), mensch.place, mensch._path.size(), txt])
print("LEINE weiteste=%.1f" % weiteste)
# D: wieder anhängen
sp.folgt = null
sp.global_position = mensch.global_position + Vector3(0, 1.5, 2.0)
sp.velocity = Vector3.ZERO
main._process(0.05)
print("ANHAENGEN fokus_mensch=%s fokus=%s d=%.2f geist=%s mensch=%s auf_erde=%s offen=%s" % [
str(main._fokus_mensch), str(main._fokus), sp.global_position.distance_to(mensch.global_position + Vector3(0, 1, 0)),
str(sp.global_position), str(mensch.global_position), str(main.auf_erde), str(main.ui.offen)])
get_tree().quit()

6
tests/_probe.tscn Normal file
View File

@@ -0,0 +1,6 @@
[gd_scene load_steps=2 format=3]
[ext_resource type="Script" path="res://tests/_probe.gd" id="1_p"]
[node name="Probe" type="Node"]
script = ExtResource("1_p")

54
tests/_probe2.gd Normal file
View File

@@ -0,0 +1,54 @@
extends Node
var main: Node3D
const OUT := "user://treppe/"
func _ready() -> void:
seed(7)
DirAccess.make_dir_recursive_absolute(ProjectSettings.globalize_path(OUT))
main = load("res://scenes/main.tscn").instantiate()
add_child(main)
await get_tree().process_frame
main.ui.schliessen()
Game.time_h = 11.0
main._erde()
await get_tree().process_frame
var sp: Player = main.player
var oben: Bewohner = null
for m in main.welt.humans:
if m.etage(str(m.data["heim"])) > 0 and Orte.etagen(HumanDB.PLACES, str(m.data["heim"])) >= 3:
oben = m
break
var heim := str(oben.data["heim"])
# 1 Erdgeschoss, am Fuß der Treppe
var t0 := Orte.treppe(HumanDB.PLACES, heim, 0)
var innen := Orte.innen_tuer(HumanDB.PLACES, heim)
sp.global_position = innen + Vector3(0, 0.3, 0)
sp.velocity = Vector3.ZERO
await knipse("1_erdgeschoss_treppe")
# 2 auf dem Wendepodest im ersten Stock
sp.global_position = Orte.treppe(HumanDB.PLACES, heim, 1) + Vector3(0, 0.3, 0)
sp.velocity = Vector3.ZERO
await knipse("2_podest_erster_stock")
# 3 Leine auf der Straße: an jemanden hängen, der unterwegs ist
var laeufer: Bewohner = null
for i in range(3000):
await get_tree().process_frame
for m in main.welt.humans:
if m._path.size() > 3 and m.etage(m.place) == 0:
laeufer = m
break
if laeufer != null:
break
sp.global_position = laeufer.global_position + Vector3(0, 0.3, 0)
sp.folgt = laeufer
for i in range(240):
await get_tree().process_frame
await knipse("3_leine_strasse")
get_tree().quit()
func knipse(name: String) -> void:
for i in range(30):
await get_tree().process_frame
await RenderingServer.frame_post_draw
get_viewport().get_texture().get_image().save_png(OUT + name + ".png")
print("Bild: " + name)

6
tests/_probe2.tscn Normal file
View File

@@ -0,0 +1,6 @@
[gd_scene load_steps=2 format=3]
[ext_resource type="Script" path="res://tests/_probe2.gd" id="1_p"]
[node name="Probe" type="Node"]
script = ExtResource("1_p")

View File

@@ -760,7 +760,8 @@ func _wege_pruefen(welt_name: String, places: Dictionary, liste: Array,
var nach: String = String(r[i][1])
if von == nach:
continue
var dauer := _weg_laenge(places, von, nach, netz, anker) / Bewohner.GEHTEMPO
var dauer := _weg_laenge(places, von, nach, m.get("etage", {}), netz, anker) \
/ Bewohner.GEHTEMPO
var slot_h: float = (float(r[i + 1][0]) - float(r[i][0])) if i + 1 < r.size() \
else (24.0 - float(r[i][0]))
var fenster := slot_h * sek_pro_stunde
@@ -775,11 +776,11 @@ func _wege_pruefen(welt_name: String, places: Dictionary, liste: Array,
p(alles_ok, "%s — jeder Weg passt, engster Fall: %s" % [welt_name, engste_text])
func _weg_laenge(places: Dictionary, von: String, nach: String,
func _weg_laenge(places: Dictionary, von: String, nach: String, etagen: Dictionary,
netz: Netz = null, anker: Dictionary = {}) -> float:
var pts: Array = Orte.route(places, von, nach, Vector3.ZERO, netz, anker)
var pts: Array = Orte.route_voll(places, von, nach, Vector3.ZERO, etagen, netz, anker)
var l := 0.0
var pos := Orte.center(places, von)
var pos := Orte.center(places, von) + Vector3(0, Orte.hoehe(int(etagen.get(von, 0))), 0)
for pt in pts:
l += pos.distance_to(pt)
pos = pt
@@ -789,15 +790,14 @@ func _weg_laenge(places: Dictionary, von: String, nach: String,
func test_geist() -> void:
abschnitt("Geist-Bewegung")
p(main.player.mode == Player.Mode.GEIST, "Spieler ist auf der Erde ein Geist")
p(main.player.collision_layer == 0 and main.player.collision_mask == 0,
"Der Geist kollidiert mit nichts — er schwebt durch Wände")
var vor: Vector3 = main.player.global_position
p(main.player.collision_mask == 1, "Der Geist stößt an Wände wie ein Mensch")
main.player.global_position = Vector3(0, 8.0, 0)
main.player.velocity = Vector3(6, 0, 0)
for i in range(30):
for i in range(60):
await get_tree().physics_frame
p(main.player.global_position.x > 0.5, "Der Geist bewegt sich frei durch den Raum")
p(absf(main.player.global_position.y - 8.0) < 0.5, "Ohne Schwerkraft fällt er nicht")
p(main.player.global_position.x > 0.5, "Der Geist bewegt sich durch den Park")
p(main.player.global_position.y < 0.6 and main.player.is_on_floor(),
"Die Schwerkraft holt ihn auf den Boden (y = %.2f)" % main.player.global_position.y)
var lena: Bewohner = welt().humans[0]
var davor: Vector3 = lena.global_position
@@ -817,6 +817,8 @@ func test_charakter() -> void:
sp.set_mode(Player.Mode.GEIST)
sp.look_enabled = true
sp.folgt = null
var moment_merker: Dictionary = Game.situation.duplicate(true)
Game.situation = {} # ein laufender Moment ließe die Farbe flackern
p(sp._augen.size() == 2 and sp._augen[0].position.z < 0.0, "Zwei Augen, vorn am Kopf")
p(sp._funken.size() == Player.FUNKEN_MAX, "%d Funken stehen bereit" % Player.FUNKEN_MAX)
for i in range(60):
@@ -835,7 +837,11 @@ func test_charakter() -> void:
for i in range(90):
await get_tree().physics_frame
p(_farbabstand(sp._farbe, Player.FARBE_FOLGE) < 0.1, "Beim Verfolgen leuchtet er warm")
Game.situation = moment_merker
sp.folgt = null
sp.global_position = Vector3(0, 0.5, 9.0) # freier Rasen im Park
sp.velocity = Vector3.ZERO
sp.yaw = 0.0
Input.action_press("vor")
for i in range(40):
await get_tree().physics_frame
@@ -1016,12 +1022,23 @@ func test_kamera_und_etagen() -> void:
p(wand_weg >= 2 and wand_weg < (bau["waende"][0] as Array).size(),
"Die Wände zur Kamera hin sind weg, die hinteren bleiben (%d von %d Teile)" %
[wand_weg, (bau["waende"][0] as Array).size()])
Input.action_press("steigen")
for i in range(60):
var stufen: Array = Orte.treppen_lauf(HumanDB.PLACES, heim, 0)
sp.global_position = (stufen[0] as Vector3) + Vector3(0, 0.3, 0)
sp.velocity = Vector3.ZERO
var lauf: Vector3 = stufen[1] - stufen[0]
lauf.y = 0.0
sp.yaw = atan2(-lauf.x, -lauf.z)
Input.action_press("vor")
var hoechste := 0.0
for i in range(70):
await get_tree().physics_frame
Input.action_release("steigen")
p(absf(sp.global_position.y - (1.4 + Orte.ETAGE)) < 0.1,
"Leertaste hebt den Geist genau ein Stockwerk (y = %.1f)" % sp.global_position.y)
hoechste = maxf(hoechste, sp.global_position.y)
Input.action_release("vor")
p(hoechste > Orte.ETAGE - 0.3,
"Über die Treppe kommt der Geist in den ersten Stock (y = %.1f)" % hoechste)
sp.global_position = t1 + Vector3(0, 0.3, 0)
sp.velocity = Vector3.ZERO
await get_tree().physics_frame
welt()._process(0.05)
p((bau["etagen"][0] as Node3D).visible and (bau["etagen"][1] as Node3D).visible
and (n < 3 or not (bau["etagen"][2] as Node3D).visible),
@@ -1102,7 +1119,14 @@ func test_verfolgung() -> void:
main.player.yaw = 0.0
var mensch: Bewohner = welt().humans[0]
Game.active_mission = str(mensch.data["id"])
main.player.global_position = mensch.global_position + Vector3(0, 1.5, 2.0)
# kurz vor seinem nächsten Ortswechsel einsteigen, damit er auch losgeht
var routine: Array = mensch.data["routine"]
for k in range(routine.size()):
if str(routine[k][1]) != mensch.place and float(routine[k][0]) > 0.5:
Game.time_h = float(routine[k][0]) - 0.4
break
schritte(5)
main.player.global_position = mensch.global_position + Vector3(0, 0.3, 0)
main.player.velocity = Vector3.ZERO
main._process(0.05)
p(main._fokus_mensch == mensch, "Der Mensch ist im Fokus")
@@ -1114,9 +1138,8 @@ func test_verfolgung() -> void:
var weiteste := 0.0
var gelaufen := false
var im_fokus := 0
for i in range(900):
schritte(1)
await get_tree().physics_frame
for i in range(2400):
await get_tree().physics_frame # nur die Engine steppt: sonst laufen die Menschen doppelt
if not mensch._path.is_empty():
gelaufen = true
if main._fokus_mensch == mensch:
@@ -1124,8 +1147,8 @@ func test_verfolgung() -> void:
weiteste = maxf(weiteste,
main.player.global_position.distance_to(mensch.global_position))
p(gelaufen, "Er wechselt in dieser Zeit den Ort")
p(weiteste < 6.0, "Der Geist bleibt die ganze Zeit dicht dabei (höchstens %.1f)" % weiteste)
p(im_fokus > 850, "Und behält ihn im Fokus (%d von 900 Schritten)" % im_fokus)
p(weiteste < 8.0, "Der Geist bleibt die ganze Zeit dicht dabei (höchstens %.1f)" % weiteste)
p(im_fokus > 2000, "Und behält ihn im Fokus (%d von 2400 Schritten)" % im_fokus)
p(main._fokus_mensch == mensch or main.player.folgt == mensch,
"Unterwegs bleibt er notierbar")
@@ -2203,8 +2226,8 @@ func test_journal_ueberall() -> void:
func test_steuerung() -> void:
abschnitt("Steuerung")
var aktionen := ["vor", "zurueck", "links", "rechts", "steigen", "sinken",
"interagieren", "journal", "tempo_1", "tempo_2", "tempo_3"]
var aktionen := ["vor", "zurueck", "links", "rechts", "steigen", "drehen",
"interagieren", "folgen", "notieren", "journal", "tempo_1", "tempo_2", "tempo_3"]
var alle := true
for a in aktionen:
if not InputMap.has_action(a) or InputMap.action_get_events(a).is_empty():
@@ -2236,23 +2259,39 @@ func test_steuerung() -> void:
p(main.player.global_position.x > 1.0,
"D schiebt den Spieler nach rechts (x = %.1f)" % main.player.global_position.x)
main.player.global_position = Vector3(0, 8.0, 0)
# Ein geschlossener Klotz hält ihn auf: von der Straße aus gegen die Wand
var war_erde := main.auf_erde
if not war_erde:
main._erde()
await get_tree().process_frame
main.player.look_enabled = true
var klotz: Dictionary = {}
var richtung := Vector3.ZERO
for b in welt()._bauten:
if not bool(b.get("voll", false)):
continue
for pz in HumanDB.PARZELLEN:
if (pz["pos"] as Vector3).distance_to(b["c"]) < 0.1:
klotz = b
richtung = Orte.DIR_VEC[pz["dir"]]
if not klotz.is_empty():
break
p(not klotz.is_empty(), "Es gibt geschlossene Klötze")
var kc: Vector3 = klotz["c"]
var kg: Vector2 = klotz["size"]
var halb: float = (kg.y if absf(richtung.z) > 0.0 else kg.x) * 0.5
main.player.global_position = kc + richtung * (halb + 2.0) + Vector3(0, 0.3, 0)
main.player.velocity = Vector3.ZERO
Input.action_press("steigen")
for i in range(40):
main.player.yaw = atan2(richtung.x, richtung.z) # "vor" zeigt zum Klotz
Input.action_press("vor")
for i in range(60):
await get_tree().physics_frame
Input.action_release("steigen")
p(main.player.global_position.y > 9.0,
"Leertaste lässt den Geist steigen (y = %.1f)" % main.player.global_position.y)
main.player.velocity = Vector3.ZERO
var hoch: float = main.player.global_position.y
Input.action_press("sinken")
for i in range(40):
await get_tree().physics_frame
Input.action_release("sinken")
p(main.player.global_position.y < hoch - 1.0,
"Umschalt lässt den Geist sinken (y = %.1f)" % main.player.global_position.y)
Input.action_release("vor")
var tiefe_im_klotz: float = halb - (main.player.global_position - kc).dot(richtung)
p(tiefe_im_klotz < 0.6, "Wände halten den Geist auf (%.1f m in der Wand)" % maxf(0.0, tiefe_im_klotz))
if not war_erde:
main._traumwelt() # die folgenden Messungen erwarten die Traumwelt
await get_tree().process_frame
## Nach jedem Einsatz braucht eine Technik Ruhe. Ein Weg allein deckt daher