This commit is contained in:
Team3
2026-09-16 01:23:42 +02:00
parent 12cbb88692
commit 936773c4e9
13 changed files with 1300 additions and 314 deletions

View File

@@ -2,8 +2,10 @@ extends Node3D
class_name EarthWorld
## Die Erde: eine Kleinstadt mit vier Menschen, die ihren Tag leben.
var spawn := Vector3(0, 3.0, 12.0)
var spawn := Vector3(0, 1.4, 12.0)
var humans: Array = []
var spieler: Node3D = null # setzt main, für den Etagenschnitt
var _bauten: Array = [] # alles, was der Etagenschnitt aufschneidet
var _sun: DirectionalLight3D
var _sky: ProceduralSkyMaterial
@@ -64,8 +66,8 @@ func _strassen() -> void:
band.rotation.y = atan2(d.x, d.z)
## Alles, was nicht Wohnung oder Sonderbau ist, steht als geschlossener Bau da.
## Erst dadurch wird der Bezirk dicht.
## Alles, was nicht Wohnung oder Sonderbau ist, steht als geschlossener Klotz
## mit ein bis vier Stockwerken da. Erst dadurch wird der Bezirk dicht.
func _bebauung() -> void:
var rng := RandomNumberGenerator.new()
rng.seed = 8123
@@ -81,18 +83,26 @@ func _bebauung() -> void:
var g: Vector2 = p["size"]
if minf(g.x, g.y) < 3.0:
continue
var hoehe := rng.randf_range(4.0, 9.0)
var n := 1 + rng.randi_range(0, 3)
var hoehe := Orte.hoehe(n)
var ton := Color.from_hsv(fmod(0.07 + rng.randf() * 0.12, 1.0),
0.10 + rng.randf() * 0.14, 0.62 + rng.randf() * 0.26)
Prims.box(self, c + Vector3(0, hoehe * 0.5, 0), Vector3(g.x, hoehe, g.y), ton)
Prims.box(self, c + Vector3(0, hoehe + 0.2, 0),
var bau := Node3D.new()
add_child(bau)
Prims.box(bau, c + Vector3(0, hoehe * 0.5, 0), Vector3(g.x, hoehe, g.y), ton)
for f in range(n):
_fenster(bau, c + Vector3(0, Orte.hoehe(f), 0), g, ton)
Prims.box(bau, c + Vector3(0, hoehe + 0.2, 0),
Vector3(g.x + 0.5, 0.4, g.y + 0.5), ton.darkened(0.25))
if rng.randf() < 0.35:
Prims.box(self, c + Vector3(0, hoehe + 0.9, 0),
Prims.box(bau, c + Vector3(0, hoehe + 0.9, 0),
Vector3(g.x * 0.4, 1.0, g.y * 0.4), ton.darkened(0.1))
_bauten.append({"c": c, "size": g, "hoch": hoehe, "etagen": [bau], "dach": [],
"waende": [], "voll": true})
## Wohnungen und Sonderbauten stehen offen, damit der Geist von oben hineinsieht.
## Wohnungen und Sonderbauten: geschlossene Häuser mit Stockwerken, Treppenhaus
## und Möbeln. Der Geist gleitet hinein, der Etagenschnitt öffnet sie ihm.
func _orte() -> void:
for key in HumanDB.PLACES:
var pl: Dictionary = HumanDB.PLACES[key]
@@ -100,57 +110,100 @@ func _orte() -> void:
if float(s[0]) <= 0.0:
continue
var c := Orte.center(HumanDB.PLACES, key)
var groesse := Vector3(float(s[0]), 2.3, float(s[1]))
var groesse := Vector3(float(s[0]), Orte.ETAGE, float(s[1]))
var farbe: Color = pl["color"]
var tuer: float = minf(3.0, minf(groesse.x, groesse.z) - 3.0)
Prims.room(self, c, groesse, farbe, farbe.darkened(0.35),
Orte.DIR_VEC[pl["dir"]], maxf(1.6, tuer), true)
Prims.label(self, c + Vector3(0, 4.4, 0), str(pl["name"]), 0.55, Color(1, 1, 0.9))
_einrichtung(c, groesse, farbe, key)
var tuer: float = maxf(1.6, minf(3.0, minf(groesse.x, groesse.z) - 3.0))
var n := Orte.etagen(HumanDB.PLACES, key)
var etagen: Array = []
var waende: Array = []
for f in range(n):
var eb := Node3D.new()
add_child(eb)
var cf := c + Vector3(0, Orte.hoehe(f), 0)
var ton := farbe.lightened(0.06 * float(f))
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))
_fenster(eb, cf, Vector2(groesse.x, groesse.z), ton)
_einrichtung(eb, cf, groesse, farbe, key if f == 0 or HumanDB.ETAGEN_ARBEIT.has(key)
else "heim_")
if f + 1 < n:
_treppe(eb, key, f)
var licht := OmniLight3D.new()
licht.position = cf + Vector3(0, 2.2, 0)
licht.omni_range = 12.0
licht.light_color = Color(1.0, 0.85, 0.6)
licht.light_energy = 0.0
eb.add_child(licht)
_nachtlichter.append(licht)
etagen.append(eb)
var dach := Node3D.new()
add_child(dach)
Prims.box(dach, c + Vector3(0, Orte.hoehe(n) + 0.1, 0),
Vector3(groesse.x + 0.4, 0.2, groesse.z + 0.4), farbe.darkened(0.3))
Prims.label(self, c + Vector3(0, Orte.hoehe(n) + 1.6, 0), str(pl["name"]), 0.55,
Color(1, 1, 0.9))
_bauten.append({"c": c, "size": Vector2(groesse.x, groesse.z), "hoch": Orte.hoehe(n),
"etagen": etagen, "dach": [dach], "waende": waende})
var licht := OmniLight3D.new()
licht.position = c + Vector3(0, 2.0, 0)
licht.omni_range = 16.0
licht.light_color = Color(1.0, 0.85, 0.6)
licht.light_energy = 0.0
add_child(licht)
_nachtlichter.append(licht)
## Ein Fensterband je Wand, damit man die Stockwerke von außen zählt.
func _fenster(parent: Node, cf: Vector3, g: Vector2, ton: Color) -> void:
var glas := ton.darkened(0.55).lerp(Color(0.35, 0.45, 0.6), 0.5)
for d: Vector3 in [Vector3.FORWARD, Vector3.BACK, Vector3.LEFT, Vector3.RIGHT]:
var quer := absf(d.z) > 0.0
var laenge: float = (g.x if quer else g.y) - 2.4
if laenge < 1.0:
continue
var off := Vector3(d.x * (g.x * 0.5 + 0.05), 1.75, d.z * (g.y * 0.5 + 0.05))
Prims.box(parent, cf + off, Vector3(laenge, 0.9, 0.08) if quer else Vector3(0.08, 0.9, laenge),
glas, false)
## Eine Rampe von Podest zu Podest -- die Treppe, die die Bewohner hochgehen.
func _treppe(parent: Node, key: String, f: int) -> void:
var a := Orte.treppe(HumanDB.PLACES, key, f)
var b := Orte.treppe(HumanDB.PLACES, key, f + 1)
var d := b - a
var stufe := Prims.box(parent, (a + b) * 0.5, Vector3(1.2, 0.18, d.length()),
Color(0.55, 0.50, 0.46), false)
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)
## Ein paar Möbel, damit man sieht, wofür ein Raum da ist.
func _einrichtung(c: Vector3, groesse: Vector3, farbe: Color, key: String) -> void:
func _einrichtung(parent: Node, c: Vector3, groesse: Vector3, farbe: Color, key: String) -> void:
var w := maxf(0.5, groesse.x * 0.5 - 2.0)
var h := maxf(0.5, groesse.z * 0.5 - 2.0)
if key.begins_with("heim_"):
Prims.box(self, c + Vector3(-w * 0.6, 0.35, -h * 0.5), Vector3(1.9, 0.7, 3.0),
Prims.box(parent, c + Vector3(-w * 0.6, 0.35, -h * 0.5), Vector3(1.9, 0.7, 3.0),
Color(0.85, 0.85, 0.90))
Prims.box(self, c + Vector3(w * 0.6, 0.75, 0), Vector3(1.5, 0.15, 2.2),
Prims.box(parent, c + Vector3(w * 0.6, 0.75, 0), Vector3(1.5, 0.15, 2.2),
farbe.darkened(0.5))
Prims.box(self, c + Vector3(w * 0.6, 1.05, 0), Vector3(0.8, 0.55, 0.1),
Prims.box(parent, c + Vector3(w * 0.6, 1.05, 0), Vector3(0.8, 0.55, 0.1),
Color(0.2, 0.25, 0.3))
elif key == "cafe":
for i in range(3):
Prims.cyl(self, c + Vector3(-w * 0.5 + float(i) * w * 0.5, 0.4, 0.4), 0.7, 0.8,
Prims.cyl(parent, c + Vector3(-w * 0.5 + float(i) * w * 0.5, 0.4, 0.4), 0.7, 0.8,
Color(0.55, 0.40, 0.30))
Prims.box(self, c + Vector3(0, 0.55, -h * 0.7), Vector3(groesse.x - 3.0, 1.1, 0.8),
Prims.box(parent, c + Vector3(0, 0.55, -h * 0.7), Vector3(groesse.x - 3.0, 1.1, 0.8),
Color(0.45, 0.32, 0.24))
elif key == "buero":
for i in range(3):
Prims.box(self, c + Vector3(-w * 0.5 + float(i) * w * 0.5, 0.75, 0),
Prims.box(parent, c + Vector3(-w * 0.5 + float(i) * w * 0.5, 0.75, 0),
Vector3(1.6, 0.15, 1.2), Color(0.75, 0.75, 0.78))
elif key == "baeckerei":
Prims.box(self, c + Vector3(0, 0.55, h * 0.5), Vector3(groesse.x - 3.0, 1.1, 1.0),
Prims.box(parent, c + Vector3(0, 0.55, h * 0.5), Vector3(groesse.x - 3.0, 1.1, 1.0),
Color(0.70, 0.55, 0.35))
Prims.box(self, c + Vector3(0, 0.85, -h * 0.6), Vector3(2.6, 1.7, 1.2),
Prims.box(parent, c + Vector3(0, 0.85, -h * 0.6), Vector3(2.6, 1.7, 1.2),
Color(0.4, 0.4, 0.42))
elif key == "uni":
for i in range(3):
Prims.box(self, c + Vector3(0, 0.5, -h * 0.6 + float(i) * h * 0.6),
Prims.box(parent, c + Vector3(0, 0.5, -h * 0.6 + float(i) * h * 0.6),
Vector3(groesse.x - 3.0, 0.2, 0.7), Color(0.66, 0.62, 0.58))
Prims.box(self, c + Vector3(0, 1.1, -h), Vector3(groesse.x * 0.55, 1.6, 0.15),
Prims.box(parent, c + Vector3(0, 1.1, -h), Vector3(groesse.x * 0.55, 1.6, 0.15),
Color(0.15, 0.25, 0.20))
elif key == "werkstatt":
Prims.box(self, c + Vector3(0, 0.6, 0), Vector3(groesse.x - 4.0, 1.2, 1.4),
Prims.box(parent, c + Vector3(0, 0.6, 0), Vector3(groesse.x - 4.0, 1.2, 1.4),
Color(0.52, 0.48, 0.46))
@@ -209,6 +262,8 @@ func _menschen() -> void:
func _process(_delta: float) -> void:
_himmel_aktualisieren()
if spieler != null:
Prims.schnitt(_bauten, spieler.global_position, spieler.cam.global_position)
func _himmel_aktualisieren() -> void: