This commit is contained in:
Team3
2026-09-16 13:08:59 +02:00
parent 89fad5dc7a
commit e813b5f7aa
17 changed files with 483 additions and 247 deletions

View File

@@ -11,6 +11,7 @@ const GRAVITY := 24.0
const JUMP := 9.0
const FOLGE_ABSTAND := 2.5 # so weit bleibt der Geist auf der Spur zurück
const LEINE := 14.0 # weiter weg reißt die Leine: er wird nachgezogen
const FOLGE_NAH := 5.0 # näher dran braucht es keinen Anlauf
const SCHWEBE := 0.25 # eine Handbreit über dem Boden
const PITCH := -0.96 # 55° von oben, fest wie in Diablo
const CAM_YAW := PI * 0.25 # Blick diagonal über den Bezirk
@@ -28,6 +29,9 @@ var arm: Node3D
var cam: Camera3D
var _dreh_rest := 0.0 # noch zu drehender Winkel (Q)
var _zoom_stufe := 0
var _anlauf: Array = [] # Weg zu dem Menschen, an den man sich gehängt hat
var _stockt := 0.0 # Sekunden ohne Vorankommen
var spruenge := 0 # wie oft die Leine nachziehen musste
var body: Node3D
var _schleier: MeshInstance3D
var _kern: MeshInstance3D
@@ -51,7 +55,7 @@ const FUNKEN_MAX := 6
func _ready() -> void:
var cs := CollisionShape3D.new()
var shape := CapsuleShape3D.new()
shape.radius = 0.4
shape.radius = 0.35 # passt durch die 0,8 m zwischen zwei Häusern
shape.height = 1.6
cs.shape = shape
cs.position.y = 0.8
@@ -164,12 +168,33 @@ func _physics_process(delta: float) -> void:
move_and_slide()
if global_position.y < -400.0:
global_position.y = 2.0
_eingeklemmt(delta, dir.length() > 0.01)
if dir.length() > 0.01:
var ziel := atan2(-dir.x, -dir.z)
body.rotation.y = lerp_angle(body.rotation.y, ziel, 1.0 - pow(0.0005, delta))
## Wer mit gedrückter Taste zwei Sekunden nicht vorankommt, steckt fest --
## dann setzt ihn die Stadt auf die nächste Straße.
func _eingeklemmt(delta: float, will: bool) -> void:
if mode != Mode.GEIST or not will or Vector2(velocity.x, velocity.z).length() > 0.3:
_stockt = 0.0
return
_stockt += delta
if _stockt < 2.0:
return
_stockt = 0.0
var netz: Netz = HumanDB.NETZ
if netz == null or netz.knoten.is_empty():
return
var nah: Vector3 = netz.knoten[int(netz.andocken(global_position)["knoten"])]
global_position = Vector3(nah.x, 0.3, nah.z)
velocity = Vector3.ZERO
spruenge += 1
Game.notified.emit("Eingeklemmt -- du stehst wieder auf der Straße.", Color(0.8, 0.85, 1))
func blickrichtung() -> Vector3:
return -Vector3(sin(yaw), 0, cos(yaw))
@@ -185,11 +210,33 @@ func _fallen(delta: float) -> void:
velocity.y -= GRAVITY * delta
## An einen Menschen hängen. Steht er weit weg, wird erst der Weg zu ihm
## geplant: aus dem Haus, über die Straßen, in seine Wohnung.
func anhaengen(m: Bewohner) -> void:
folgt = m
_anlauf = []
_stockt = 0.0
if global_position.distance_to(m.global_position) > FOLGE_NAH:
var ort: String = m.place if m._path.is_empty() else ""
_anlauf = Orte.route_zu(m.places, m.netz, global_position, m.global_position,
ort, m.etage(ort) if ort != "" else 0)
## 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 ziel: Vector3
if not _anlauf.is_empty():
ziel = _anlauf[0]
var bis := ziel - global_position
bis.y = 0.0
if bis.length() < 0.6 and absf(ziel.y - global_position.y) < 1.6:
_anlauf.pop_front()
if _anlauf.is_empty():
ziel = mensch.spur_punkt(FOLGE_ABSTAND)
else:
ziel = _anlauf[0]
var d := ziel - global_position
d.y = 0.0
var tempo := maxf(SPEED_GEIST, Bewohner.GEHTEMPO * Game.zeit_faktor() * 1.4)
@@ -203,9 +250,17 @@ func _an_der_leine(delta: float) -> void:
velocity.z = 0.0
_fallen(delta)
move_and_slide()
if global_position.distance_to(mensch.global_position) > LEINE:
if d.length() > 0.6 and Vector2(velocity.x, velocity.z).length() < 0.3:
_stockt += delta
else:
_stockt = 0.0
var zu_weit: bool = _anlauf.is_empty() \
and global_position.distance_to(mensch.global_position) > LEINE
if _stockt > 2.0 or zu_weit:
global_position = ziel # hängen geblieben: die Leine zieht ihn nach
velocity = Vector3.ZERO
_stockt = 0.0
spruenge += 1
## Schweben, Funken, Schweif und Modusfarbe -- der Zustand ist am Geist ablesbar.