update
This commit is contained in:
@@ -4,6 +4,7 @@ class_name Bewohner
|
||||
## einer Technik erreicht werden -- oder eben nicht.
|
||||
|
||||
const GEHTEMPO := 8.0
|
||||
const MASSSTAB := 0.8 # Menschen sind klein, die Stadt wirkt groß
|
||||
|
||||
var data: Dictionary
|
||||
var idx: int = 0
|
||||
@@ -16,6 +17,8 @@ var anker: Dictionary = {}
|
||||
var mit_mission := false
|
||||
|
||||
var _visual: Node3D
|
||||
var _ober: Node3D # Oberkörper: neigt sich, duckt sich, zappelt
|
||||
var _arme: Array = []
|
||||
var _label: Label3D
|
||||
var _koerper: MeshInstance3D
|
||||
var _kopf: MeshInstance3D
|
||||
@@ -23,6 +26,7 @@ var _aura: MeshInstance3D
|
||||
var _strahl: MeshInstance3D
|
||||
var _path: Array = []
|
||||
var _letzte_aktivitaet: String = ""
|
||||
var boden: Callable = Callable() # Höhe des Bodens (x, z) -> y; leer heißt eben
|
||||
var slot: int = 0
|
||||
var _bob: float = 0.0
|
||||
var _offset: Vector3
|
||||
@@ -41,18 +45,30 @@ func setup(d: Dictionary, index: int, orte: Dictionary,
|
||||
_offset = Vector3(cos(winkel), 0, sin(winkel)) * 2.2
|
||||
|
||||
_visual = Node3D.new()
|
||||
_visual.scale = Vector3.ONE * MASSSTAB
|
||||
add_child(_visual)
|
||||
var c: Color = d["farbe"]
|
||||
var leuchtet := bool(d.get("leuchtet", false))
|
||||
var hoehe := 1.05 + float(index % 3) * 0.08
|
||||
_koerper = Prims.capsule(_visual, Vector3(0, hoehe * 0.62, 0), 0.32, hoehe, c)
|
||||
_kopf = Prims.sphere(_visual, Vector3(0, hoehe * 1.18 + 0.1, 0), 0.24, c.lightened(0.45))
|
||||
Prims.box(_visual, Vector3(0, hoehe * 0.95, 0), Vector3(0.9, 0.14, 0.3), c.darkened(0.25), false)
|
||||
_ober = Node3D.new()
|
||||
_ober.position.y = hoehe * 0.45
|
||||
_visual.add_child(_ober)
|
||||
var o := Vector3(0, -hoehe * 0.45, 0)
|
||||
_koerper = Prims.capsule(_ober, o + Vector3(0, hoehe * 0.62, 0), 0.32, hoehe, c)
|
||||
_kopf = Prims.sphere(_ober, o + Vector3(0, hoehe * 1.18 + 0.1, 0), 0.24, c.lightened(0.45))
|
||||
Prims.box(_ober, o + Vector3(0, hoehe * 0.95, 0), Vector3(0.9, 0.14, 0.3), c.darkened(0.25), false)
|
||||
for sx: float in [-1.0, 1.0]:
|
||||
var gelenk := Node3D.new()
|
||||
gelenk.position = o + Vector3(sx * 0.46, hoehe * 0.92, 0)
|
||||
_ober.add_child(gelenk)
|
||||
Prims.capsule(gelenk, Vector3(0, -0.32, 0), 0.09, 0.62, c.darkened(0.1))
|
||||
_arme.append(gelenk)
|
||||
_hut(o + Vector3(0, hoehe * 1.18 + 0.1, 0), c)
|
||||
Prims.box(_visual, Vector3(0, 0.06, 0), Vector3(0.5, 0.12, 0.7), c.darkened(0.45), false)
|
||||
if leuchtet:
|
||||
_koerper.material_override = Prims.mat(c, 0.9)
|
||||
_kopf.material_override = Prims.mat(c.lightened(0.45), 0.8)
|
||||
var reif := Prims.cyl(_visual, Vector3(0, hoehe * 0.5, 0), 0.62, 0.05,
|
||||
var reif := Prims.cyl(_ober, o + Vector3(0, hoehe * 0.5, 0), 0.62, 0.05,
|
||||
c.lightened(0.3), false, 1.6)
|
||||
reif.cast_shadow = GeometryInstance3D.SHADOW_CASTING_SETTING_OFF
|
||||
|
||||
@@ -61,13 +77,85 @@ func setup(d: Dictionary, index: int, orte: Dictionary,
|
||||
_strahl = Prims.cyl(self, Vector3(0, 11.0, 0), 0.14, 16.0, Color(1, 0.85, 0.35, 0.22), false, 1.2)
|
||||
_strahl.visible = false
|
||||
|
||||
_label = Prims.label(self, Vector3(0, 2.9, 0), d["name"], 0.30)
|
||||
# gestaffelt, damit sich Schilder in einem Raum nicht übereinanderlegen
|
||||
_label = Prims.label(self, Vector3(0, 2.3 + float(index % 5) * 0.35, 0), d["name"], 0.36)
|
||||
|
||||
var start := _routine_at(Game.time_h)
|
||||
place = start[0]
|
||||
activity = start[1]
|
||||
_letzte_aktivitaet = activity
|
||||
global_position = Orte.center(places, place) + _offset
|
||||
global_position = Orte.center(places, place) + _offset + Vector3(0, Orte.hoehe(etage(place)), 0)
|
||||
|
||||
|
||||
## In welcher Etage dieser Mensch an einem Ort ist -- 0, wenn er dort nur unten ist.
|
||||
func etage(ort: String) -> int:
|
||||
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
|
||||
## schon aus der Ferne.
|
||||
func _hut(kopf: Vector3, c: Color) -> void:
|
||||
var typ := str(HumanDB.BERUF_TAGESTYP.get(str(data.get("beruf", "")), ""))
|
||||
var dunkel := c.darkened(0.4)
|
||||
match typ:
|
||||
"frueh": # Mütze
|
||||
Prims.cyl(_ober, kopf + Vector3(0, 0.2, 0), 0.22, 0.14, dunkel, false)
|
||||
"buero": # Hut mit Krempe
|
||||
Prims.cyl(_ober, kopf + Vector3(0, 0.16, 0), 0.36, 0.04, dunkel, false)
|
||||
Prims.cyl(_ober, kopf + Vector3(0, 0.3, 0), 0.18, 0.24, dunkel, false)
|
||||
"studium": # Zipfel
|
||||
var z := Prims.cyl(_ober, kopf + Vector3(0, 0.36, 0), 0.2, 0.4, dunkel, false)
|
||||
(z.mesh as CylinderMesh).top_radius = 0.0
|
||||
"werkstatt": # Kappe mit Schirm
|
||||
Prims.cyl(_ober, kopf + Vector3(0, 0.18, 0), 0.25, 0.1, dunkel, false)
|
||||
Prims.box(_ober, kopf + Vector3(0, 0.14, -0.3), Vector3(0.3, 0.04, 0.2), dunkel, false)
|
||||
_:
|
||||
pass
|
||||
|
||||
|
||||
## Angst duckt, Erschöpfung beugt, Unruhe zappelt -- solange die Klemme nicht
|
||||
## überwunden ist. So sieht man Probleme beim Beobachten am Körper.
|
||||
func _haltung(delta: float, geht: bool) -> void:
|
||||
var id := str(data["id"])
|
||||
var offen: Dictionary = {}
|
||||
for k in data.get("probleme", []):
|
||||
if not Game.problem_ueberwunden(id, str(k)):
|
||||
offen[str(k)] = true
|
||||
var neigung := 0.38 if offen.has("erschoepfung") else 0.0
|
||||
var groesse := 0.86 if offen.has("angst") else 1.0
|
||||
var zappeln := 0.0
|
||||
if offen.has("unruhe") and not geht:
|
||||
zappeln = sin(Time.get_ticks_msec() * 0.011) * 0.06
|
||||
_ober.rotation.x = lerpf(_ober.rotation.x, -neigung, 1.0 - pow(0.02, delta))
|
||||
_ober.rotation.z = lerpf(_ober.rotation.z, zappeln, 1.0 - pow(0.001, delta))
|
||||
_ober.scale = _ober.scale.lerp(Vector3.ONE * groesse, 1.0 - pow(0.02, delta))
|
||||
var schwung := sin(_bob) * 0.7 if geht else 0.0
|
||||
for i in range(_arme.size()):
|
||||
var a: Node3D = _arme[i]
|
||||
a.rotation.x = lerpf(a.rotation.x, schwung * (1.0 if i == 0 else -1.0),
|
||||
1.0 - pow(0.001, delta))
|
||||
|
||||
|
||||
## [Ort, Tätigkeit, Slotnummer] zur Stunde h. Steht in dem Slot ein System,
|
||||
@@ -95,6 +183,7 @@ func _process(roh: float) -> void:
|
||||
_path = Orte.route(places, place, soll[0], _offset, netz, anker)
|
||||
if war_unterwegs and _path.size() > 1:
|
||||
_path.remove_at(0) # steht schon draußen, alte Tür überspringen
|
||||
_path = _mit_etagen(_path, place, soll[0], war_unterwegs)
|
||||
place = soll[0]
|
||||
activity = "unterwegs"
|
||||
elif _path.is_empty() and activity != soll[1]:
|
||||
@@ -102,9 +191,9 @@ func _process(roh: float) -> void:
|
||||
|
||||
if not _path.is_empty():
|
||||
var ziel: Vector3 = _path[0]
|
||||
ziel.y = 0.0
|
||||
var hier := global_position
|
||||
hier.y = 0.0
|
||||
if boden.is_valid():
|
||||
ziel.y = hier.y # das Gelände bestimmt die Höhe, nicht der Wegpunkt
|
||||
var d := ziel - hier
|
||||
if d.length() < 0.4:
|
||||
_path.remove_at(0)
|
||||
@@ -121,6 +210,9 @@ func _process(roh: float) -> void:
|
||||
|
||||
if _path.is_empty():
|
||||
_visual.position.y = lerpf(_visual.position.y, 0.0, 1.0 - pow(0.01, delta))
|
||||
_haltung(delta, not _path.is_empty())
|
||||
if boden.is_valid():
|
||||
global_position.y = float(boden.call(global_position.x, global_position.z))
|
||||
|
||||
_visual.rotation.z = lerp_angle(_visual.rotation.z, PI * 0.5 if activity == "schlaeft" else 0.0,
|
||||
1.0 - pow(0.01, delta))
|
||||
@@ -161,7 +253,7 @@ func beschriftung() -> String:
|
||||
|
||||
## Sichtbare Reaktion auf eine angewandte Technik.
|
||||
func reagiere(success: bool, text: String) -> void:
|
||||
var l := Prims.label(self, Vector3(0, 3.5, 0), text, 0.34,
|
||||
var l := Prims.label(self, Vector3(0, 3.0, 0), text, 0.4,
|
||||
Color(0.55, 1.0, 0.6) if success else Color(1, 0.55, 0.45))
|
||||
var tw := l.create_tween()
|
||||
tw.set_parallel(true)
|
||||
|
||||
Reference in New Issue
Block a user