update
This commit is contained in:
19
README.md
19
README.md
@@ -34,8 +34,8 @@ hervorgehobene. Fenster in der Mitte gibt es nur an Orten: Brett, Hörsaal,
|
|||||||
Aushang schreiben. **Esc** geht eine Ebene zurück, nicht gleich ganz zu.
|
Aushang schreiben. **Esc** geht eine Ebene zurück, nicht gleich ganz zu.
|
||||||
|
|
||||||
Oben links stehen nur Zeit und Mission. Alles Weitere steht im Journal.
|
Oben links stehen nur Zeit und Mission. Alles Weitere steht im Journal.
|
||||||
In der Traumwelt springt **Leertaste**; auf der Erde wechselt sie ein
|
In der Traumwelt springt **Leertaste**. Auf der Erde gibt es keinen Sprung:
|
||||||
Stockwerk nach oben, **Umschalt** eines nach unten.
|
der Geist nimmt die Treppe.
|
||||||
|
|
||||||
## Spielschleife
|
## Spielschleife
|
||||||
|
|
||||||
@@ -172,14 +172,17 @@ nicht immer — Übung entscheidet.
|
|||||||
im Büro und an der Hochschule sitzt jeder auf seinem Stockwerk. Die
|
im Büro und an der Hochschule sitzt jeder auf seinem Stockwerk. Die
|
||||||
Bewohner gehen die Treppe hoch und runter. Alles andere steht als
|
Bewohner gehen die Treppe hoch und runter. Alles andere steht als
|
||||||
geschlossener Klotz da.
|
geschlossener Klotz da.
|
||||||
* Du bist ein unsichtbarer Geist, schwebst und gehst durch Wände. Bist du
|
* Du bist ein unsichtbarer Geist, der eine Handbreit über dem Boden schwebt,
|
||||||
in einem Haus, greift der **Etagenschnitt**: Dach, Etagen über dir und
|
sich aber bewegt wie ein Mensch: Wände halten, Türen und Treppen sind die
|
||||||
|
Wege, Schwerkraft gilt. Bist du in einem Haus, greift der **Etagenschnitt**: Dach, Etagen über dir und
|
||||||
die Wände zur Kamera hin verschwinden, wie bei den Sims. Ein Haus, das
|
die Wände zur Kamera hin verschwinden, wie bei den Sims. Ein Haus, das
|
||||||
zwischen Kamera und dir steht, wird durchsichtig. Wer auf einer anderen
|
zwischen Kamera und dir steht, wird durchsichtig. Wer auf einer anderen
|
||||||
Etage ist, ist nicht im Fokus — durch die Decke sieht man nichts.
|
Etage ist, ist nicht im Fokus — durch die Decke sieht man nichts.
|
||||||
* **F** hängt dich an einen Menschen: du treibst hinter ihm her, durch Türen
|
* **F** oder ein Klick hängt dich an einen Menschen: du gehst seiner Spur
|
||||||
und über den ganzen Tag, ohne ihm nachlaufen zu müssen. **F** noch einmal —
|
nach, durch dieselben Türen und Treppen, so schnell wie nötig — auch bei
|
||||||
oder ein Schritt mit **WASD** — lässt ihn wieder los.
|
Tempo 3, wo du ihm zu Fuß nie folgen könntest. Bleibst du hängen, zieht die
|
||||||
|
Leine dich nach. **F** noch einmal — oder ein Schritt mit **WASD** — lässt
|
||||||
|
ihn wieder los.
|
||||||
* **R notieren.** Was den Traum aufhält, steht nirgends geschrieben. Du siehst
|
* **R notieren.** Was den Traum aufhält, steht nirgends geschrieben. Du siehst
|
||||||
nur, was der Mensch tut, und musst selbst entscheiden: läuft hier etwas
|
nur, was der Mensch tut, und musst selbst entscheiden: läuft hier etwas
|
||||||
schief? Triffst du den Moment, steht die Ursache im Journal und der Slot
|
schief? Triffst du den Moment, steht die Ursache im Journal und der Slot
|
||||||
@@ -221,7 +224,7 @@ eintauschen könnte. Ein Erfolg bringt 2 EP, ein Fehlversuch 1 — auch der zäh
|
|||||||
scripts/orte.gd Orte, Türen, Wege, Etagen, Treppenhaus (beide Welten)
|
scripts/orte.gd Orte, Türen, Wege, Etagen, Treppenhaus (beide Welten)
|
||||||
scripts/bewohner.gd Bewohner mit Tagesablauf, Hut nach Beruf, Haltung nach Klemme
|
scripts/bewohner.gd Bewohner mit Tagesablauf, Hut nach Beruf, Haltung nach Klemme
|
||||||
scripts/main.gd Weltenwechsel, Fokus, Interaktion
|
scripts/main.gd Weltenwechsel, Fokus, Interaktion
|
||||||
scripts/player.gd Geist: feste Kamera, Etagenwechsel, Schleier, Funken, Verfolgung
|
scripts/player.gd Geist: feste Kamera, Schwerkraft, Spur-Leine, Schleier, Funken
|
||||||
scripts/dream_world.gd Insel mit Dorf
|
scripts/dream_world.gd Insel mit Dorf
|
||||||
scripts/earth_world.gd Stadt mit Stockwerken, Treppen, Etagenschnitt, Tag-Nacht-Wechsel
|
scripts/earth_world.gd Stadt mit Stockwerken, Treppen, Etagenschnitt, Tag-Nacht-Wechsel
|
||||||
scripts/ursachen.gd Ursachen, blockierende Tätigkeiten, Belohnungen
|
scripts/ursachen.gd Ursachen, blockierende Tätigkeiten, Belohnungen
|
||||||
|
|||||||
@@ -28,6 +28,7 @@ var _path: Array = []
|
|||||||
var _letzte_aktivitaet: String = ""
|
var _letzte_aktivitaet: String = ""
|
||||||
var boden: Callable = Callable() # Höhe des Bodens (x, z) -> y; leer heißt eben
|
var boden: Callable = Callable() # Höhe des Bodens (x, z) -> y; leer heißt eben
|
||||||
var slot: int = 0
|
var slot: int = 0
|
||||||
|
var spur: Array = [] # letzte Positionen -- der Geist folgt ihr durch Türen
|
||||||
var _bob: float = 0.0
|
var _bob: float = 0.0
|
||||||
var _offset: Vector3
|
var _offset: Vector3
|
||||||
|
|
||||||
@@ -87,33 +88,19 @@ func setup(d: Dictionary, index: int, orte: Dictionary,
|
|||||||
global_position = Orte.center(places, place) + _offset + Vector3(0, Orte.hoehe(etage(place)), 0)
|
global_position = Orte.center(places, place) + _offset + Vector3(0, Orte.hoehe(etage(place)), 0)
|
||||||
|
|
||||||
|
|
||||||
|
## Punkt auf der Spur, der mindestens `abstand` hinter dem Menschen liegt.
|
||||||
|
func spur_punkt(abstand: float) -> Vector3:
|
||||||
|
for i in range(spur.size() - 1, -1, -1):
|
||||||
|
if (spur[i] as Vector3).distance_to(global_position) >= abstand:
|
||||||
|
return spur[i]
|
||||||
|
return spur[0] if not spur.is_empty() else global_position
|
||||||
|
|
||||||
|
|
||||||
## In welcher Etage dieser Mensch an einem Ort ist -- 0, wenn er dort nur unten ist.
|
## In welcher Etage dieser Mensch an einem Ort ist -- 0, wenn er dort nur unten ist.
|
||||||
func etage(ort: String) -> int:
|
func etage(ort: String) -> int:
|
||||||
return int((data.get("etage", {}) as Dictionary).get(ort, 0))
|
return int((data.get("etage", {}) as Dictionary).get(ort, 0))
|
||||||
|
|
||||||
|
|
||||||
## Wege führen durchs Treppenhaus: aus der Etage runter zur Tür, und am Ziel
|
|
||||||
## von der Tür hinauf in die Etage.
|
|
||||||
func _mit_etagen(pts: Array, von: String, nach: String, war_unterwegs: bool) -> Array:
|
|
||||||
if pts.is_empty():
|
|
||||||
return pts
|
|
||||||
var e_von := etage(von)
|
|
||||||
if e_von > 0 and not war_unterwegs:
|
|
||||||
var runter: Array = [Orte.treppe(places, von, e_von)]
|
|
||||||
runter.append_array(Orte.treppen_weg(places, von, e_von, 0))
|
|
||||||
runter.append(Orte.innen_tuer(places, von))
|
|
||||||
runter.append_array(pts)
|
|
||||||
pts = runter
|
|
||||||
var e_nach := etage(nach)
|
|
||||||
if e_nach > 0:
|
|
||||||
pts.pop_back()
|
|
||||||
pts.append(Orte.innen_tuer(places, nach))
|
|
||||||
pts.append(Orte.treppe(places, nach, 0))
|
|
||||||
pts.append_array(Orte.treppen_weg(places, nach, 0, e_nach))
|
|
||||||
pts.append(Orte.center(places, nach) + _offset + Vector3(0, Orte.hoehe(e_nach), 0))
|
|
||||||
return pts
|
|
||||||
|
|
||||||
|
|
||||||
## Kopfbedeckung nach Tagestyp des Berufs -- so unterscheiden sich die Leute
|
## Kopfbedeckung nach Tagestyp des Berufs -- so unterscheiden sich die Leute
|
||||||
## schon aus der Ferne.
|
## schon aus der Ferne.
|
||||||
func _hut(kopf: Vector3, c: Color) -> void:
|
func _hut(kopf: Vector3, c: Color) -> void:
|
||||||
@@ -180,10 +167,10 @@ func _process(roh: float) -> void:
|
|||||||
slot = int(soll[2])
|
slot = int(soll[2])
|
||||||
if soll[0] != place:
|
if soll[0] != place:
|
||||||
var war_unterwegs := not _path.is_empty()
|
var war_unterwegs := not _path.is_empty()
|
||||||
_path = Orte.route(places, place, soll[0], _offset, netz, anker)
|
_path = Orte.route_voll(places, place, soll[0], _offset,
|
||||||
|
data.get("etage", {}), netz, anker, war_unterwegs)
|
||||||
if war_unterwegs and _path.size() > 1:
|
if war_unterwegs and _path.size() > 1:
|
||||||
_path.remove_at(0) # steht schon draußen, alte Tür überspringen
|
_path.remove_at(0) # steht schon draußen, alte Tür überspringen
|
||||||
_path = _mit_etagen(_path, place, soll[0], war_unterwegs)
|
|
||||||
place = soll[0]
|
place = soll[0]
|
||||||
activity = "unterwegs"
|
activity = "unterwegs"
|
||||||
elif _path.is_empty() and activity != soll[1]:
|
elif _path.is_empty() and activity != soll[1]:
|
||||||
@@ -213,6 +200,10 @@ func _process(roh: float) -> void:
|
|||||||
_haltung(delta, not _path.is_empty())
|
_haltung(delta, not _path.is_empty())
|
||||||
if boden.is_valid():
|
if boden.is_valid():
|
||||||
global_position.y = float(boden.call(global_position.x, global_position.z))
|
global_position.y = float(boden.call(global_position.x, global_position.z))
|
||||||
|
if spur.is_empty() or (spur.back() as Vector3).distance_to(global_position) > 0.4:
|
||||||
|
spur.append(global_position)
|
||||||
|
if spur.size() > 120:
|
||||||
|
spur.pop_front()
|
||||||
|
|
||||||
_visual.rotation.z = lerp_angle(_visual.rotation.z, PI * 0.5 if activity == "schlaeft" else 0.0,
|
_visual.rotation.z = lerp_angle(_visual.rotation.z, PI * 0.5 if activity == "schlaeft" else 0.0,
|
||||||
1.0 - pow(0.01, delta))
|
1.0 - pow(0.01, delta))
|
||||||
|
|||||||
@@ -122,10 +122,12 @@ func _orte() -> void:
|
|||||||
var cf := c + Vector3(0, Orte.hoehe(f), 0)
|
var cf := c + Vector3(0, Orte.hoehe(f), 0)
|
||||||
var ton := farbe.lightened(0.06 * float(f))
|
var ton := farbe.lightened(0.06 * float(f))
|
||||||
waende.append(Prims.room(eb, cf, groesse, ton, farbe.darkened(0.35),
|
waende.append(Prims.room(eb, cf, groesse, ton, farbe.darkened(0.35),
|
||||||
Orte.DIR_VEC[pl["dir"]] if f == 0 else Vector3.ZERO, tuer, true))
|
Orte.DIR_VEC[pl["dir"]] if f == 0 else Vector3.ZERO, tuer, f == 0))
|
||||||
|
if f > 0:
|
||||||
|
_decke(eb, key, cf, groesse, farbe.darkened(0.35))
|
||||||
_fenster(eb, cf, Vector2(groesse.x, groesse.z), ton)
|
_fenster(eb, cf, Vector2(groesse.x, groesse.z), ton)
|
||||||
_einrichtung(eb, cf, groesse, farbe, key if f == 0 or HumanDB.ETAGEN_ARBEIT.has(key)
|
_einrichtung(eb, cf, groesse, farbe, key if f == 0 or HumanDB.ETAGEN_ARBEIT.has(key)
|
||||||
else "heim_")
|
else "heim_", key)
|
||||||
if f + 1 < n:
|
if f + 1 < n:
|
||||||
_treppe(eb, key, f)
|
_treppe(eb, key, f)
|
||||||
var licht := OmniLight3D.new()
|
var licht := OmniLight3D.new()
|
||||||
@@ -159,51 +161,75 @@ func _fenster(parent: Node, cf: Vector3, g: Vector2, ton: Color) -> void:
|
|||||||
glas, false)
|
glas, false)
|
||||||
|
|
||||||
|
|
||||||
## Eine Rampe von Podest zu Podest -- die Treppe, die die Bewohner hochgehen.
|
## Ein Lauf von Podest zu Podest -- die Treppe, die Bewohner und Geist
|
||||||
|
## hochgehen. Sie trägt, deshalb mit Kollision.
|
||||||
func _treppe(parent: Node, key: String, f: int) -> void:
|
func _treppe(parent: Node, key: String, f: int) -> void:
|
||||||
var a := Orte.treppe(HumanDB.PLACES, key, f)
|
var lauf := Orte.treppen_lauf(HumanDB.PLACES, key, f)
|
||||||
var b := Orte.treppe(HumanDB.PLACES, key, f + 1)
|
var von: Vector3 = lauf[0]
|
||||||
var d := b - a
|
var bis: Vector3 = lauf[1]
|
||||||
var stufe := Prims.box(parent, (a + b) * 0.5, Vector3(1.2, 0.18, d.length()),
|
var d := bis - von
|
||||||
Color(0.55, 0.50, 0.46), false)
|
var stufe := Prims.box(parent, (von + bis) * 0.5, Vector3(1.6, 0.18, d.length()),
|
||||||
|
Color(0.55, 0.50, 0.46))
|
||||||
stufe.basis = Basis.looking_at(d.normalized(), Vector3.UP)
|
stufe.basis = Basis.looking_at(d.normalized(), Vector3.UP)
|
||||||
Prims.box(parent, b + Vector3(0, -0.09, 0), Vector3(1.4, 0.18, 1.4), Color(0.55, 0.50, 0.46), false)
|
var r := Orte.treppen_rahmen(HumanDB.PLACES, key)
|
||||||
|
var podest := Orte.treppe(HumanDB.PLACES, key, f + 1)
|
||||||
|
var mass := Orte._xz(r["a"], Orte.PODEST * 2.0, Orte.TREPPE_TIEFE - 0.8)
|
||||||
|
Prims.box(parent, podest + Vector3(0, -0.09, 0), Vector3(mass.x, 0.18, mass.y),
|
||||||
|
Color(0.55, 0.50, 0.46))
|
||||||
|
|
||||||
|
|
||||||
## Ein paar Möbel, damit man sieht, wofür ein Raum da ist.
|
## Der Boden einer oberen Etage lässt über dem Treppenhaus ein Loch frei --
|
||||||
func _einrichtung(parent: Node, c: Vector3, groesse: Vector3, farbe: Color, key: String) -> void:
|
## sonst stieße, wer die Treppe hochkommt, mit dem Kopf an die Decke.
|
||||||
|
func _decke(parent: Node, key: String, cf: Vector3, _groesse: Vector3, farbe: Color) -> void:
|
||||||
|
for platte in Orte.treppen_decke(HumanDB.PLACES, key):
|
||||||
|
var mitte: Vector3 = platte[0]
|
||||||
|
var mass: Vector2 = platte[1]
|
||||||
|
mitte.y = cf.y - 0.1
|
||||||
|
Prims.box(parent, mitte, Vector3(mass.x, 0.2, mass.y), farbe)
|
||||||
|
|
||||||
|
|
||||||
|
## Ein paar Möbel, damit man sieht, wofür ein Raum da ist. Nichts steht im
|
||||||
|
## Treppenstreifen.
|
||||||
|
func _einrichtung(parent: Node, c: Vector3, groesse: Vector3, farbe: Color, key: String,
|
||||||
|
ort: String = "") -> void:
|
||||||
|
if ort == "":
|
||||||
|
ort = key
|
||||||
var w := maxf(0.5, groesse.x * 0.5 - 2.0)
|
var w := maxf(0.5, groesse.x * 0.5 - 2.0)
|
||||||
var h := maxf(0.5, groesse.z * 0.5 - 2.0)
|
var h := maxf(0.5, groesse.z * 0.5 - 2.0)
|
||||||
|
var frei := func(v: Vector3, halb: float) -> Vector3:
|
||||||
|
var p := Orte.frei_von_treppe(HumanDB.PLACES, ort, c + v, halb)
|
||||||
|
p.y = c.y + v.y
|
||||||
|
return p
|
||||||
if key.begins_with("heim_"):
|
if key.begins_with("heim_"):
|
||||||
Prims.box(parent, c + Vector3(-w * 0.6, 0.35, -h * 0.5), Vector3(1.9, 0.7, 3.0),
|
Prims.box(parent, frei.call(Vector3(-w * 0.6, 0.35, -h * 0.5), 1.5), Vector3(1.9, 0.7, 3.0),
|
||||||
Color(0.85, 0.85, 0.90))
|
Color(0.85, 0.85, 0.90))
|
||||||
Prims.box(parent, c + Vector3(w * 0.6, 0.75, 0), Vector3(1.5, 0.15, 2.2),
|
Prims.box(parent, frei.call(Vector3(w * 0.6, 0.75, 0), 1.1), Vector3(1.5, 0.15, 2.2),
|
||||||
farbe.darkened(0.5))
|
farbe.darkened(0.5))
|
||||||
Prims.box(parent, c + Vector3(w * 0.6, 1.05, 0), Vector3(0.8, 0.55, 0.1),
|
Prims.box(parent, frei.call(Vector3(w * 0.6, 1.05, 0), 0.1), Vector3(0.8, 0.55, 0.1),
|
||||||
Color(0.2, 0.25, 0.3))
|
Color(0.2, 0.25, 0.3))
|
||||||
elif key == "cafe":
|
elif key == "cafe":
|
||||||
for i in range(3):
|
for i in range(3):
|
||||||
Prims.cyl(parent, c + Vector3(-w * 0.5 + float(i) * w * 0.5, 0.4, 0.4), 0.7, 0.8,
|
Prims.cyl(parent, frei.call(Vector3(-w * 0.5 + float(i) * w * 0.5, 0.4, 0.4), 0.7), 0.7, 0.8,
|
||||||
Color(0.55, 0.40, 0.30))
|
Color(0.55, 0.40, 0.30))
|
||||||
Prims.box(parent, c + Vector3(0, 0.55, -h * 0.7), Vector3(groesse.x - 3.0, 1.1, 0.8),
|
Prims.box(parent, frei.call(Vector3(0, 0.55, -h * 0.7), 0.4), Vector3(groesse.x - 3.0, 1.1, 0.8),
|
||||||
Color(0.45, 0.32, 0.24))
|
Color(0.45, 0.32, 0.24))
|
||||||
elif key == "buero":
|
elif key == "buero":
|
||||||
for i in range(3):
|
for i in range(3):
|
||||||
Prims.box(parent, c + Vector3(-w * 0.5 + float(i) * w * 0.5, 0.75, 0),
|
Prims.box(parent, frei.call(Vector3(-w * 0.5 + float(i) * w * 0.5, 0.75, 0), 0.8),
|
||||||
Vector3(1.6, 0.15, 1.2), Color(0.75, 0.75, 0.78))
|
Vector3(1.6, 0.15, 1.2), Color(0.75, 0.75, 0.78))
|
||||||
elif key == "baeckerei":
|
elif key == "baeckerei":
|
||||||
Prims.box(parent, c + Vector3(0, 0.55, h * 0.5), Vector3(groesse.x - 3.0, 1.1, 1.0),
|
Prims.box(parent, frei.call(Vector3(0, 0.55, h * 0.5), 0.5), Vector3(groesse.x - 3.0, 1.1, 1.0),
|
||||||
Color(0.70, 0.55, 0.35))
|
Color(0.70, 0.55, 0.35))
|
||||||
Prims.box(parent, c + Vector3(0, 0.85, -h * 0.6), Vector3(2.6, 1.7, 1.2),
|
Prims.box(parent, frei.call(Vector3(0, 0.85, -h * 0.6), 1.3), Vector3(2.6, 1.7, 1.2),
|
||||||
Color(0.4, 0.4, 0.42))
|
Color(0.4, 0.4, 0.42))
|
||||||
elif key == "uni":
|
elif key == "uni":
|
||||||
for i in range(3):
|
for i in range(3):
|
||||||
Prims.box(parent, c + Vector3(0, 0.5, -h * 0.6 + float(i) * h * 0.6),
|
Prims.box(parent, frei.call(Vector3(0, 0.5, -h * 0.6 + float(i) * h * 0.6), 0.35),
|
||||||
Vector3(groesse.x - 3.0, 0.2, 0.7), Color(0.66, 0.62, 0.58))
|
Vector3(groesse.x - 3.0, 0.2, 0.7), Color(0.66, 0.62, 0.58))
|
||||||
Prims.box(parent, c + Vector3(0, 1.1, -h), Vector3(groesse.x * 0.55, 1.6, 0.15),
|
Prims.box(parent, frei.call(Vector3(0, 1.1, -h), 0.1), Vector3(groesse.x * 0.55, 1.6, 0.15),
|
||||||
Color(0.15, 0.25, 0.20))
|
Color(0.15, 0.25, 0.20))
|
||||||
elif key == "werkstatt":
|
elif key == "werkstatt":
|
||||||
Prims.box(parent, c + Vector3(0, 0.6, 0), Vector3(groesse.x - 4.0, 1.2, 1.4),
|
Prims.box(parent, frei.call(Vector3(0, 0.6, 0), 0.7), Vector3(groesse.x - 4.0, 1.2, 1.4),
|
||||||
Color(0.52, 0.48, 0.46))
|
Color(0.52, 0.48, 0.46))
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -59,7 +59,6 @@ func _setup_input() -> void:
|
|||||||
"links": [KEY_A, KEY_LEFT],
|
"links": [KEY_A, KEY_LEFT],
|
||||||
"rechts": [KEY_D, KEY_RIGHT],
|
"rechts": [KEY_D, KEY_RIGHT],
|
||||||
"steigen": [KEY_SPACE],
|
"steigen": [KEY_SPACE],
|
||||||
"sinken": [KEY_SHIFT],
|
|
||||||
"interagieren": [KEY_E],
|
"interagieren": [KEY_E],
|
||||||
"folgen": [KEY_F],
|
"folgen": [KEY_F],
|
||||||
"notieren": [KEY_R],
|
"notieren": [KEY_R],
|
||||||
|
|||||||
@@ -388,7 +388,9 @@ static func _sonderbauten_verteilen() -> void:
|
|||||||
# Das Café gehört in die Mitte -- jeder Tagesablauf führt dorthin.
|
# Das Café gehört in die Mitte -- jeder Tagesablauf führt dorthin.
|
||||||
# Die übrigen Sonderbauten verteilen sich rundum.
|
# Die übrigen Sonderbauten verteilen sich rundum.
|
||||||
var wunsch := Vector3.ZERO
|
var wunsch := Vector3.ZERO
|
||||||
if str(SONDER[s][0]) != "cafe":
|
if str(SONDER[s][0]) == "werkstatt":
|
||||||
|
wunsch = Vector3(0, 0, 30.0) # kurze Mittagspause: das Café muss nah sein
|
||||||
|
elif str(SONDER[s][0]) != "cafe":
|
||||||
var w := TAU * float(s) / float(SONDER.size() - 1)
|
var w := TAU * float(s) / float(SONDER.size() - 1)
|
||||||
wunsch = Vector3(cos(w), 0, sin(w)) * 42.0
|
wunsch = Vector3(cos(w), 0, sin(w)) * 42.0
|
||||||
var idx: int = -1
|
var idx: int = -1
|
||||||
|
|||||||
144
scripts/orte.gd
144
scripts/orte.gd
@@ -59,9 +59,13 @@ static func hoehe(e: int) -> float:
|
|||||||
return float(e) * ETAGE
|
return float(e) * ETAGE
|
||||||
|
|
||||||
|
|
||||||
## Treppenhaus: die Ecke neben der Tür. Die Podeste wechseln je Etage die
|
const TREPPE_LAUF := 6.0 # Abstand der Wendepodeste entlang der Wand
|
||||||
## Seite, so läuft die Treppe im Zickzack an der Türwand hoch.
|
const TREPPE_TIEFE := 4.4 # Streifen an der Treppenwand: zwei Läufe nebeneinander
|
||||||
static func treppe(places: Dictionary, key: String, e: int) -> Vector3:
|
const PODEST := 0.9 # halbe Podestlänge
|
||||||
|
|
||||||
|
## Rahmen des Treppenhauses: an der längeren Wand, die nicht die Türwand ist.
|
||||||
|
## n zeigt von der Mitte zur Treppenwand, a läuft an ihr entlang.
|
||||||
|
static func treppen_rahmen(places: Dictionary, key: String) -> Dictionary:
|
||||||
var pl: Dictionary = places[key]
|
var pl: Dictionary = places[key]
|
||||||
var c := center(places, key)
|
var c := center(places, key)
|
||||||
var d: Vector3 = DIR_VEC[pl["dir"]]
|
var d: Vector3 = DIR_VEC[pl["dir"]]
|
||||||
@@ -70,11 +74,98 @@ static func treppe(places: Dictionary, key: String, e: int) -> Vector3:
|
|||||||
var halb_d: float = (float(size[1]) if quer_ist else float(size[0])) * 0.5
|
var halb_d: float = (float(size[1]) if quer_ist else float(size[0])) * 0.5
|
||||||
var halb_q: float = (float(size[0]) if quer_ist else float(size[1])) * 0.5
|
var halb_q: float = (float(size[0]) if quer_ist else float(size[1])) * 0.5
|
||||||
var quer := Vector3(-d.z, 0, d.x)
|
var quer := Vector3(-d.z, 0, d.x)
|
||||||
var p := c + d * (halb_d - 1.6) + quer * (halb_q - 1.4) - quer * (3.0 if e % 2 == 1 else 0.0)
|
if halb_q >= halb_d:
|
||||||
|
return {"c": c, "n": -d, "a": quer, "halb_n": halb_d, "halb_a": halb_q}
|
||||||
|
return {"c": c, "n": -quer, "a": -d, "halb_n": halb_q, "halb_a": halb_d}
|
||||||
|
|
||||||
|
|
||||||
|
static func _lauf(r: Dictionary) -> float:
|
||||||
|
return minf(TREPPE_LAUF, float(r["halb_a"]) * 2.0 - 2.8)
|
||||||
|
|
||||||
|
|
||||||
|
static func _podest_a(r: Dictionary, e: int) -> float:
|
||||||
|
var p0: float = float(r["halb_a"]) - 1.4
|
||||||
|
return p0 if e % 2 == 0 else p0 - _lauf(r)
|
||||||
|
|
||||||
|
|
||||||
|
## Wendepodest der Etage e: zwei Läufe liegen nebeneinander, das Podest
|
||||||
|
## verbindet sie. Der obere Lauf ist so nie die Decke des unteren.
|
||||||
|
static func treppe(places: Dictionary, key: String, e: int) -> Vector3:
|
||||||
|
var r := treppen_rahmen(places, key)
|
||||||
|
var p: Vector3 = r["c"] + r["n"] * (float(r["halb_n"]) - TREPPE_TIEFE * 0.5) \
|
||||||
|
+ r["a"] * _podest_a(r, e)
|
||||||
p.y = hoehe(e)
|
p.y = hoehe(e)
|
||||||
return p
|
return p
|
||||||
|
|
||||||
|
|
||||||
|
## Ein Lauf: [Anfang auf Etage f, Ende auf Etage f + 1].
|
||||||
|
static func treppen_lauf(places: Dictionary, key: String, f: int) -> Array:
|
||||||
|
var r := treppen_rahmen(places, key)
|
||||||
|
var tiefe: float = float(r["halb_n"]) - (1.4 if f % 2 == 0 else 3.0)
|
||||||
|
var richtung := -1.0 if f % 2 == 0 else 1.0
|
||||||
|
var von: Vector3 = r["c"] + r["n"] * tiefe + r["a"] * (_podest_a(r, f) + richtung * PODEST)
|
||||||
|
var bis: Vector3 = r["c"] + r["n"] * tiefe + r["a"] * (_podest_a(r, f + 1) - richtung * PODEST)
|
||||||
|
von.y = hoehe(f)
|
||||||
|
bis.y = hoehe(f + 1)
|
||||||
|
return [von, bis]
|
||||||
|
|
||||||
|
|
||||||
|
## Wegpunkte durchs Treppenhaus von Etage a nach Etage b, ohne a selbst:
|
||||||
|
## Laufanfang, Laufende, Podest -- je Etage.
|
||||||
|
static func treppen_weg(places: Dictionary, key: String, a: int, b: int) -> Array:
|
||||||
|
var out: Array = []
|
||||||
|
if b > a:
|
||||||
|
for f in range(a, b):
|
||||||
|
var l := treppen_lauf(places, key, f)
|
||||||
|
out.append(l[0])
|
||||||
|
out.append(l[1])
|
||||||
|
out.append(treppe(places, key, f + 1))
|
||||||
|
else:
|
||||||
|
for f in range(a - 1, b - 1, -1):
|
||||||
|
var l := treppen_lauf(places, key, f)
|
||||||
|
out.append(l[1])
|
||||||
|
out.append(l[0])
|
||||||
|
out.append(treppe(places, key, f))
|
||||||
|
return out
|
||||||
|
|
||||||
|
|
||||||
|
## Deckenplatten einer oberen Etage: alles außer dem Treppenloch.
|
||||||
|
## Liefert [[mitte, groesse_xz], ...] ohne Höhe.
|
||||||
|
static func treppen_decke(places: Dictionary, key: String) -> Array:
|
||||||
|
var r := treppen_rahmen(places, key)
|
||||||
|
var c: Vector3 = r["c"]
|
||||||
|
var n: Vector3 = r["n"]
|
||||||
|
var a: Vector3 = r["a"]
|
||||||
|
var halb_n := float(r["halb_n"])
|
||||||
|
var halb_a := float(r["halb_a"])
|
||||||
|
var out: Array = []
|
||||||
|
# Hauptplatte: alles außer dem Streifen an der Treppenwand
|
||||||
|
out.append([c - n * (TREPPE_TIEFE * 0.5), _xz(a, halb_a * 2.0, halb_n * 2.0 - TREPPE_TIEFE)])
|
||||||
|
# Rest des Streifens jenseits des Lochs
|
||||||
|
var ende: float = _podest_a(r, 1) - PODEST
|
||||||
|
var rest := ende + halb_a
|
||||||
|
if rest > 0.3:
|
||||||
|
out.append([c + n * (halb_n - TREPPE_TIEFE * 0.5) + a * ((ende - halb_a) * 0.5),
|
||||||
|
_xz(a, rest, TREPPE_TIEFE)])
|
||||||
|
return out
|
||||||
|
|
||||||
|
|
||||||
|
## Kastenmaß in Weltachsen: laenge_a entlang a, laenge_n quer dazu.
|
||||||
|
static func _xz(a: Vector3, laenge_a: float, laenge_n: float) -> Vector2:
|
||||||
|
return Vector2(laenge_a, laenge_n) if absf(a.x) > 0.0 else Vector2(laenge_n, laenge_a)
|
||||||
|
|
||||||
|
|
||||||
|
## Rückt einen Punkt aus dem Treppenstreifen heraus (für Möbel).
|
||||||
|
static func frei_von_treppe(places: Dictionary, key: String, pos: Vector3, halb: float) -> Vector3:
|
||||||
|
var r := treppen_rahmen(places, key)
|
||||||
|
var n: Vector3 = r["n"]
|
||||||
|
var pn: float = (pos - r["c"]).dot(n)
|
||||||
|
var grenze: float = float(r["halb_n"]) - TREPPE_TIEFE - halb - 0.2
|
||||||
|
if pn > grenze:
|
||||||
|
pos -= n * (pn - grenze)
|
||||||
|
return pos
|
||||||
|
|
||||||
|
|
||||||
## Punkt gleich hinter der Tür, im Haus.
|
## Punkt gleich hinter der Tür, im Haus.
|
||||||
static func innen_tuer(places: Dictionary, key: String) -> Vector3:
|
static func innen_tuer(places: Dictionary, key: String) -> Vector3:
|
||||||
var pl: Dictionary = places[key]
|
var pl: Dictionary = places[key]
|
||||||
@@ -85,15 +176,42 @@ static func innen_tuer(places: Dictionary, key: String) -> Vector3:
|
|||||||
return c + d * (halb - 1.2)
|
return c + d * (halb - 1.2)
|
||||||
|
|
||||||
|
|
||||||
## Wegpunkte durchs Treppenhaus von Etage a nach Etage b, ohne a selbst.
|
## Ein Ort ist ein Gebäude, wenn er Grundriss und Tür hat.
|
||||||
static func treppen_weg(places: Dictionary, key: String, a: int, b: int) -> Array:
|
static func gebaeude(places: Dictionary, key: String) -> bool:
|
||||||
var out: Array = []
|
return places.has(key) and float(places[key]["size"][0]) > 0.0 \
|
||||||
var schritt := 1 if b > a else -1
|
and DIR_VEC[places[key]["dir"]] != Vector3.ZERO
|
||||||
var e := a
|
|
||||||
while e != b:
|
|
||||||
e += schritt
|
## Route mit allem, was ein Körper braucht: aus der Etage runter, gerade durch
|
||||||
out.append(treppe(places, key, e))
|
## die Tür, über das Netz, durch die nächste Tür und die Treppe hinauf.
|
||||||
return out
|
## `etagen` sagt, in welcher Etage der Mensch an welchem Ort ist.
|
||||||
|
static func route_voll(places: Dictionary, a: String, b: String, offset: Vector3,
|
||||||
|
etagen: Dictionary, netz: Netz = null, anker: Dictionary = {},
|
||||||
|
war_unterwegs: bool = false) -> Array:
|
||||||
|
var pts := route(places, a, b, offset, netz, anker)
|
||||||
|
if pts.is_empty():
|
||||||
|
return pts
|
||||||
|
if gebaeude(places, a) and not war_unterwegs:
|
||||||
|
var e_von := int(etagen.get(a, 0))
|
||||||
|
var runter: Array = []
|
||||||
|
if e_von > 0:
|
||||||
|
runter.append(treppe(places, a, e_von))
|
||||||
|
runter.append_array(treppen_weg(places, a, e_von, 0))
|
||||||
|
runter.append(innen_tuer(places, a))
|
||||||
|
runter.append(door(places, a))
|
||||||
|
runter.append_array(pts)
|
||||||
|
pts = runter
|
||||||
|
if gebaeude(places, b):
|
||||||
|
var e_nach := int(etagen.get(b, 0))
|
||||||
|
var ziel: Vector3 = pts.pop_back()
|
||||||
|
pts.append(door(places, b))
|
||||||
|
pts.append(innen_tuer(places, b))
|
||||||
|
if e_nach > 0:
|
||||||
|
pts.append(treppe(places, b, 0))
|
||||||
|
pts.append_array(treppen_weg(places, b, 0, e_nach))
|
||||||
|
ziel.y = hoehe(e_nach)
|
||||||
|
pts.append(ziel)
|
||||||
|
return pts
|
||||||
|
|
||||||
|
|
||||||
static func center(places: Dictionary, key: String) -> Vector3:
|
static func center(places: Dictionary, key: String) -> Vector3:
|
||||||
|
|||||||
@@ -9,8 +9,9 @@ const SPEED_TRAUM := 8.0
|
|||||||
const SPEED_GEIST := 11.0
|
const SPEED_GEIST := 11.0
|
||||||
const GRAVITY := 24.0
|
const GRAVITY := 24.0
|
||||||
const JUMP := 9.0
|
const JUMP := 9.0
|
||||||
const FOLGE_ABSTAND := 2.2
|
const FOLGE_ABSTAND := 2.5 # so weit bleibt der Geist auf der Spur zurück
|
||||||
const FOLGE_SPIEL := 1.5
|
const LEINE := 14.0 # weiter weg reißt die Leine: er wird nachgezogen
|
||||||
|
const SCHWEBE := 0.25 # eine Handbreit über dem Boden
|
||||||
const PITCH := -0.96 # 55° von oben, fest wie in Diablo
|
const PITCH := -0.96 # 55° von oben, fest wie in Diablo
|
||||||
const CAM_YAW := PI * 0.25 # Blick diagonal über den Bezirk
|
const CAM_YAW := PI * 0.25 # Blick diagonal über den Bezirk
|
||||||
const ZOOM := [26.0, 40.0] # zwei Stufen, Mausrad
|
const ZOOM := [26.0, 40.0] # zwei Stufen, Mausrad
|
||||||
@@ -27,7 +28,6 @@ var arm: Node3D
|
|||||||
var cam: Camera3D
|
var cam: Camera3D
|
||||||
var _dreh_rest := 0.0 # noch zu drehender Winkel (Q)
|
var _dreh_rest := 0.0 # noch zu drehender Winkel (Q)
|
||||||
var _zoom_stufe := 0
|
var _zoom_stufe := 0
|
||||||
var _schwebe_ziel := -1.0 # Etage, zu der der Geist gerade gleitet
|
|
||||||
var body: Node3D
|
var body: Node3D
|
||||||
var _schleier: MeshInstance3D
|
var _schleier: MeshInstance3D
|
||||||
var _kern: MeshInstance3D
|
var _kern: MeshInstance3D
|
||||||
@@ -51,10 +51,10 @@ const FUNKEN_MAX := 6
|
|||||||
func _ready() -> void:
|
func _ready() -> void:
|
||||||
var cs := CollisionShape3D.new()
|
var cs := CollisionShape3D.new()
|
||||||
var shape := CapsuleShape3D.new()
|
var shape := CapsuleShape3D.new()
|
||||||
shape.radius = 0.45
|
shape.radius = 0.4
|
||||||
shape.height = 1.9
|
shape.height = 1.6
|
||||||
cs.shape = shape
|
cs.shape = shape
|
||||||
cs.position.y = 0.95
|
cs.position.y = 0.8
|
||||||
add_child(cs)
|
add_child(cs)
|
||||||
|
|
||||||
body = Node3D.new()
|
body = Node3D.new()
|
||||||
@@ -107,18 +107,15 @@ func _ready() -> void:
|
|||||||
func set_mode(m: int) -> void:
|
func set_mode(m: int) -> void:
|
||||||
mode = m
|
mode = m
|
||||||
folgt = null
|
folgt = null
|
||||||
|
collision_layer = 1
|
||||||
|
collision_mask = 1
|
||||||
if m == Mode.GEIST:
|
if m == Mode.GEIST:
|
||||||
collision_layer = 0
|
|
||||||
collision_mask = 0
|
|
||||||
body.scale = Vector3.ONE * 0.6
|
body.scale = Vector3.ONE * 0.6
|
||||||
_schleier_mat.albedo_color.a = 0.3
|
_schleier_mat.albedo_color.a = 0.3
|
||||||
else:
|
else:
|
||||||
collision_layer = 1
|
|
||||||
collision_mask = 1
|
|
||||||
body.scale = Vector3.ONE * 0.8
|
body.scale = Vector3.ONE * 0.8
|
||||||
_schleier_mat.albedo_color.a = 0.55
|
_schleier_mat.albedo_color.a = 0.55
|
||||||
velocity = Vector3.ZERO
|
velocity = Vector3.ZERO
|
||||||
_schwebe_ziel = -1.0
|
|
||||||
|
|
||||||
|
|
||||||
func _unhandled_input(event: InputEvent) -> void:
|
func _unhandled_input(event: InputEvent) -> void:
|
||||||
@@ -157,56 +154,16 @@ func _physics_process(delta: float) -> void:
|
|||||||
elif dir.length() > 0.01:
|
elif dir.length() > 0.01:
|
||||||
folgt = null # eigene Bewegung löst die Verfolgung
|
folgt = null # eigene Bewegung löst die Verfolgung
|
||||||
else:
|
else:
|
||||||
var rechts := Basis(Vector3.UP, yaw) * Vector3(1, 0, 0)
|
_an_der_leine(delta)
|
||||||
var schulter := folgt.global_position + Vector3(0, 1.4, 0) \
|
|
||||||
+ rechts * FOLGE_ABSTAND - blickrichtung() * 0.8
|
|
||||||
global_position = global_position.lerp(schulter, 1.0 - pow(0.004, delta))
|
|
||||||
# weich nachziehen, aber an der Leine: sonst reißt der Faden beim Gehen
|
|
||||||
var ab := global_position - schulter
|
|
||||||
if ab.length() > FOLGE_SPIEL:
|
|
||||||
global_position = schulter + ab.normalized() * FOLGE_SPIEL
|
|
||||||
velocity = Vector3.ZERO
|
|
||||||
body.rotation.y = lerp_angle(body.rotation.y, yaw, 1.0 - pow(0.001, delta))
|
|
||||||
return
|
return
|
||||||
|
|
||||||
if mode == Mode.GEIST:
|
var tempo := SPEED_GEIST if mode == Mode.GEIST else SPEED_TRAUM
|
||||||
var v := dir * SPEED_GEIST
|
velocity.x = lerpf(velocity.x, dir.x * tempo, 1.0 - pow(0.0005, delta))
|
||||||
velocity.x = lerpf(velocity.x, v.x, 1.0 - pow(0.001, delta))
|
velocity.z = lerpf(velocity.z, dir.z * tempo, 1.0 - pow(0.0005, delta))
|
||||||
velocity.z = lerpf(velocity.z, v.z, 1.0 - pow(0.001, delta))
|
_fallen(delta)
|
||||||
# Steigen und Sinken wechseln die Etage: der Geist gleitet ein Stockwerk
|
move_and_slide()
|
||||||
if look_enabled:
|
if global_position.y < -400.0:
|
||||||
var von: float = _schwebe_ziel if _schwebe_ziel >= 0.0 else global_position.y
|
global_position.y = 2.0
|
||||||
if Input.is_action_just_pressed("steigen"):
|
|
||||||
_schwebe_ziel = clampf(von + Orte.ETAGE, 0.4, 45.0)
|
|
||||||
if Input.is_action_just_pressed("sinken"):
|
|
||||||
_schwebe_ziel = clampf(von - Orte.ETAGE, 0.4, 45.0)
|
|
||||||
if _schwebe_ziel >= 0.0:
|
|
||||||
var dy := _schwebe_ziel - global_position.y
|
|
||||||
velocity.y = clampf(dy * 6.0, -SPEED_GEIST, SPEED_GEIST)
|
|
||||||
if absf(dy) < 0.05:
|
|
||||||
global_position.y = _schwebe_ziel
|
|
||||||
velocity.y = 0.0
|
|
||||||
_schwebe_ziel = -1.0
|
|
||||||
else:
|
|
||||||
velocity.y = 0.0
|
|
||||||
move_and_slide()
|
|
||||||
if global_position.y < 0.4:
|
|
||||||
global_position.y = 0.4
|
|
||||||
if global_position.y > 45.0:
|
|
||||||
global_position.y = 45.0
|
|
||||||
else:
|
|
||||||
velocity.x = lerpf(velocity.x, dir.x * SPEED_TRAUM, 1.0 - pow(0.0005, delta))
|
|
||||||
velocity.z = lerpf(velocity.z, dir.z * SPEED_TRAUM, 1.0 - pow(0.0005, delta))
|
|
||||||
if is_on_floor():
|
|
||||||
if look_enabled and Input.is_action_pressed("steigen"):
|
|
||||||
velocity.y = JUMP
|
|
||||||
else:
|
|
||||||
velocity.y = -1.0
|
|
||||||
else:
|
|
||||||
velocity.y -= GRAVITY * delta
|
|
||||||
move_and_slide()
|
|
||||||
if global_position.y < -400.0:
|
|
||||||
global_position.y = 2.0
|
|
||||||
|
|
||||||
if dir.length() > 0.01:
|
if dir.length() > 0.01:
|
||||||
var ziel := atan2(-dir.x, -dir.z)
|
var ziel := atan2(-dir.x, -dir.z)
|
||||||
@@ -217,6 +174,40 @@ func blickrichtung() -> Vector3:
|
|||||||
return -Vector3(sin(yaw), 0, cos(yaw))
|
return -Vector3(sin(yaw), 0, cos(yaw))
|
||||||
|
|
||||||
|
|
||||||
|
## Schwerkraft in beiden Welten. Springen kann nur der Läufer im Traum.
|
||||||
|
func _fallen(delta: float) -> void:
|
||||||
|
if is_on_floor():
|
||||||
|
if mode == Mode.TRAUM and look_enabled and Input.is_action_pressed("steigen"):
|
||||||
|
velocity.y = JUMP
|
||||||
|
else:
|
||||||
|
velocity.y = -1.0
|
||||||
|
else:
|
||||||
|
velocity.y -= GRAVITY * delta
|
||||||
|
|
||||||
|
|
||||||
|
## Folgen heißt: seiner Spur nachgehen, durch dieselben Türen und Treppen.
|
||||||
|
## Er läuft so schnell wie nötig, um dranzubleiben -- auch bei hohem Tempo.
|
||||||
|
func _an_der_leine(delta: float) -> void:
|
||||||
|
var mensch := folgt as Bewohner
|
||||||
|
var ziel: Vector3 = mensch.spur_punkt(FOLGE_ABSTAND)
|
||||||
|
var d := ziel - global_position
|
||||||
|
d.y = 0.0
|
||||||
|
var tempo := maxf(SPEED_GEIST, Bewohner.GEHTEMPO * Game.zeit_faktor() * 1.4)
|
||||||
|
if d.length() > 0.3:
|
||||||
|
var v := d.normalized() * minf(tempo, d.length() / delta)
|
||||||
|
velocity.x = v.x
|
||||||
|
velocity.z = v.z
|
||||||
|
body.rotation.y = lerp_angle(body.rotation.y, atan2(-d.x, -d.z), 1.0 - pow(0.001, delta))
|
||||||
|
else:
|
||||||
|
velocity.x = 0.0
|
||||||
|
velocity.z = 0.0
|
||||||
|
_fallen(delta)
|
||||||
|
move_and_slide()
|
||||||
|
if global_position.distance_to(mensch.global_position) > LEINE:
|
||||||
|
global_position = ziel # hängen geblieben: die Leine zieht ihn nach
|
||||||
|
velocity = Vector3.ZERO
|
||||||
|
|
||||||
|
|
||||||
## Schweben, Funken, Schweif und Modusfarbe -- der Zustand ist am Geist ablesbar.
|
## Schweben, Funken, Schweif und Modusfarbe -- der Zustand ist am Geist ablesbar.
|
||||||
func _beleben(delta: float) -> void:
|
func _beleben(delta: float) -> void:
|
||||||
var t := Time.get_ticks_msec() * 0.001
|
var t := Time.get_ticks_msec() * 0.001
|
||||||
@@ -233,7 +224,7 @@ func _beleben(delta: float) -> void:
|
|||||||
_kopf_mat.albedo_color = _farbe.lightened(0.4)
|
_kopf_mat.albedo_color = _farbe.lightened(0.4)
|
||||||
_kopf_mat.emission = _farbe.lightened(0.4)
|
_kopf_mat.emission = _farbe.lightened(0.4)
|
||||||
|
|
||||||
body.position.y = sin(t * 1.6) * 0.08
|
body.position.y = (SCHWEBE if mode == Mode.GEIST else 0.0) + sin(t * 1.6) * 0.08
|
||||||
_kern.scale = Vector3.ONE * (1.0 + sin(t * 3.1) * 0.12)
|
_kern.scale = Vector3.ONE * (1.0 + sin(t * 3.1) * 0.12)
|
||||||
var tempo_flach := Vector2(velocity.x, velocity.z).length()
|
var tempo_flach := Vector2(velocity.x, velocity.z).length()
|
||||||
var neigung := -0.16 * clampf(tempo_flach / SPEED_TRAUM, 0.0, 1.0)
|
var neigung := -0.16 * clampf(tempo_flach / SPEED_TRAUM, 0.0, 1.0)
|
||||||
|
|||||||
91
tests/_probe.gd
Normal file
91
tests/_probe.gd
Normal 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
6
tests/_probe.tscn
Normal 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
54
tests/_probe2.gd
Normal 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
6
tests/_probe2.tscn
Normal 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")
|
||||||
115
tests/verify.gd
115
tests/verify.gd
@@ -760,7 +760,8 @@ func _wege_pruefen(welt_name: String, places: Dictionary, liste: Array,
|
|||||||
var nach: String = String(r[i][1])
|
var nach: String = String(r[i][1])
|
||||||
if von == nach:
|
if von == nach:
|
||||||
continue
|
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() \
|
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]))
|
else (24.0 - float(r[i][0]))
|
||||||
var fenster := slot_h * sek_pro_stunde
|
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])
|
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:
|
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 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:
|
for pt in pts:
|
||||||
l += pos.distance_to(pt)
|
l += pos.distance_to(pt)
|
||||||
pos = pt
|
pos = pt
|
||||||
@@ -789,15 +790,14 @@ func _weg_laenge(places: Dictionary, von: String, nach: String,
|
|||||||
func test_geist() -> void:
|
func test_geist() -> void:
|
||||||
abschnitt("Geist-Bewegung")
|
abschnitt("Geist-Bewegung")
|
||||||
p(main.player.mode == Player.Mode.GEIST, "Spieler ist auf der Erde ein Geist")
|
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,
|
p(main.player.collision_mask == 1, "Der Geist stößt an Wände wie ein Mensch")
|
||||||
"Der Geist kollidiert mit nichts — er schwebt durch Wände")
|
|
||||||
var vor: Vector3 = main.player.global_position
|
|
||||||
main.player.global_position = Vector3(0, 8.0, 0)
|
main.player.global_position = Vector3(0, 8.0, 0)
|
||||||
main.player.velocity = Vector3(6, 0, 0)
|
main.player.velocity = Vector3(6, 0, 0)
|
||||||
for i in range(30):
|
for i in range(60):
|
||||||
await get_tree().physics_frame
|
await get_tree().physics_frame
|
||||||
p(main.player.global_position.x > 0.5, "Der Geist bewegt sich frei durch den Raum")
|
p(main.player.global_position.x > 0.5, "Der Geist bewegt sich durch den Park")
|
||||||
p(absf(main.player.global_position.y - 8.0) < 0.5, "Ohne Schwerkraft fällt er nicht")
|
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 lena: Bewohner = welt().humans[0]
|
||||||
var davor: Vector3 = lena.global_position
|
var davor: Vector3 = lena.global_position
|
||||||
@@ -817,6 +817,8 @@ func test_charakter() -> void:
|
|||||||
sp.set_mode(Player.Mode.GEIST)
|
sp.set_mode(Player.Mode.GEIST)
|
||||||
sp.look_enabled = true
|
sp.look_enabled = true
|
||||||
sp.folgt = null
|
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._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)
|
p(sp._funken.size() == Player.FUNKEN_MAX, "%d Funken stehen bereit" % Player.FUNKEN_MAX)
|
||||||
for i in range(60):
|
for i in range(60):
|
||||||
@@ -835,7 +837,11 @@ func test_charakter() -> void:
|
|||||||
for i in range(90):
|
for i in range(90):
|
||||||
await get_tree().physics_frame
|
await get_tree().physics_frame
|
||||||
p(_farbabstand(sp._farbe, Player.FARBE_FOLGE) < 0.1, "Beim Verfolgen leuchtet er warm")
|
p(_farbabstand(sp._farbe, Player.FARBE_FOLGE) < 0.1, "Beim Verfolgen leuchtet er warm")
|
||||||
|
Game.situation = moment_merker
|
||||||
sp.folgt = null
|
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")
|
Input.action_press("vor")
|
||||||
for i in range(40):
|
for i in range(40):
|
||||||
await get_tree().physics_frame
|
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(),
|
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)" %
|
"Die Wände zur Kamera hin sind weg, die hinteren bleiben (%d von %d Teile)" %
|
||||||
[wand_weg, (bau["waende"][0] as Array).size()])
|
[wand_weg, (bau["waende"][0] as Array).size()])
|
||||||
Input.action_press("steigen")
|
var stufen: Array = Orte.treppen_lauf(HumanDB.PLACES, heim, 0)
|
||||||
for i in range(60):
|
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
|
await get_tree().physics_frame
|
||||||
Input.action_release("steigen")
|
hoechste = maxf(hoechste, sp.global_position.y)
|
||||||
p(absf(sp.global_position.y - (1.4 + Orte.ETAGE)) < 0.1,
|
Input.action_release("vor")
|
||||||
"Leertaste hebt den Geist genau ein Stockwerk (y = %.1f)" % sp.global_position.y)
|
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)
|
welt()._process(0.05)
|
||||||
p((bau["etagen"][0] as Node3D).visible and (bau["etagen"][1] as Node3D).visible
|
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),
|
and (n < 3 or not (bau["etagen"][2] as Node3D).visible),
|
||||||
@@ -1102,7 +1119,14 @@ func test_verfolgung() -> void:
|
|||||||
main.player.yaw = 0.0
|
main.player.yaw = 0.0
|
||||||
var mensch: Bewohner = welt().humans[0]
|
var mensch: Bewohner = welt().humans[0]
|
||||||
Game.active_mission = str(mensch.data["id"])
|
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.player.velocity = Vector3.ZERO
|
||||||
main._process(0.05)
|
main._process(0.05)
|
||||||
p(main._fokus_mensch == mensch, "Der Mensch ist im Fokus")
|
p(main._fokus_mensch == mensch, "Der Mensch ist im Fokus")
|
||||||
@@ -1114,9 +1138,8 @@ func test_verfolgung() -> void:
|
|||||||
var weiteste := 0.0
|
var weiteste := 0.0
|
||||||
var gelaufen := false
|
var gelaufen := false
|
||||||
var im_fokus := 0
|
var im_fokus := 0
|
||||||
for i in range(900):
|
for i in range(2400):
|
||||||
schritte(1)
|
await get_tree().physics_frame # nur die Engine steppt: sonst laufen die Menschen doppelt
|
||||||
await get_tree().physics_frame
|
|
||||||
if not mensch._path.is_empty():
|
if not mensch._path.is_empty():
|
||||||
gelaufen = true
|
gelaufen = true
|
||||||
if main._fokus_mensch == mensch:
|
if main._fokus_mensch == mensch:
|
||||||
@@ -1124,8 +1147,8 @@ func test_verfolgung() -> void:
|
|||||||
weiteste = maxf(weiteste,
|
weiteste = maxf(weiteste,
|
||||||
main.player.global_position.distance_to(mensch.global_position))
|
main.player.global_position.distance_to(mensch.global_position))
|
||||||
p(gelaufen, "Er wechselt in dieser Zeit den Ort")
|
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(weiteste < 8.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(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,
|
p(main._fokus_mensch == mensch or main.player.folgt == mensch,
|
||||||
"Unterwegs bleibt er notierbar")
|
"Unterwegs bleibt er notierbar")
|
||||||
|
|
||||||
@@ -2203,8 +2226,8 @@ func test_journal_ueberall() -> void:
|
|||||||
|
|
||||||
func test_steuerung() -> void:
|
func test_steuerung() -> void:
|
||||||
abschnitt("Steuerung")
|
abschnitt("Steuerung")
|
||||||
var aktionen := ["vor", "zurueck", "links", "rechts", "steigen", "sinken",
|
var aktionen := ["vor", "zurueck", "links", "rechts", "steigen", "drehen",
|
||||||
"interagieren", "journal", "tempo_1", "tempo_2", "tempo_3"]
|
"interagieren", "folgen", "notieren", "journal", "tempo_1", "tempo_2", "tempo_3"]
|
||||||
var alle := true
|
var alle := true
|
||||||
for a in aktionen:
|
for a in aktionen:
|
||||||
if not InputMap.has_action(a) or InputMap.action_get_events(a).is_empty():
|
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,
|
p(main.player.global_position.x > 1.0,
|
||||||
"D schiebt den Spieler nach rechts (x = %.1f)" % main.player.global_position.x)
|
"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
|
main.player.velocity = Vector3.ZERO
|
||||||
Input.action_press("steigen")
|
main.player.yaw = atan2(richtung.x, richtung.z) # "vor" zeigt zum Klotz
|
||||||
for i in range(40):
|
Input.action_press("vor")
|
||||||
|
for i in range(60):
|
||||||
await get_tree().physics_frame
|
await get_tree().physics_frame
|
||||||
Input.action_release("steigen")
|
Input.action_release("vor")
|
||||||
p(main.player.global_position.y > 9.0,
|
var tiefe_im_klotz: float = halb - (main.player.global_position - kc).dot(richtung)
|
||||||
"Leertaste lässt den Geist steigen (y = %.1f)" % main.player.global_position.y)
|
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.player.velocity = Vector3.ZERO
|
main._traumwelt() # die folgenden Messungen erwarten die Traumwelt
|
||||||
var hoch: float = main.player.global_position.y
|
await get_tree().process_frame
|
||||||
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)
|
|
||||||
|
|
||||||
|
|
||||||
## Nach jedem Einsatz braucht eine Technik Ruhe. Ein Weg allein deckt daher
|
## Nach jedem Einsatz braucht eine Technik Ruhe. Ein Weg allein deckt daher
|
||||||
|
|||||||
Reference in New Issue
Block a user