This commit is contained in:
team3
2026-09-16 17:55:28 +02:00
parent 9800c614bb
commit a0597110bd
17 changed files with 652 additions and 278 deletions

View File

@@ -12,7 +12,7 @@ const Stoffe = preload("res://scripts/stoffe.gd") ## Materialien aus Regeln, o
const Formen = preload("res://scripts/formen.gd") ## Becher, Fass, Laterne aus Primitiven
const RIM_RUHE := Color(0.22, 0.15, 0.09) ## Zonenrand, wenn der Platz wartet
const RIM_ZUG := Color(0.85, 0.66, 0.22) ## Zonenrand des Platzes, der dran ist
const TILT_DEG := 15.0 ## Neigung der Kamera gegen die Senkrechte
const TILT_DEG := 45.0 ## Neigung der Kamera gegen die Senkrechte
const HUD_TOP := 0.13 ## Bildanteil oben für die Gebotsanzeige
const HUD_BOTTOM := 0.17 ## Bildanteil unten für die Ansage-Leiste
@@ -33,7 +33,7 @@ var _bid_anchor: Array[Vector3] = []
var plates: Array[Sprite3D] = []
var rims: Array[MeshInstance3D] = [] ## Rand der Zone, leuchtet beim Zug
var topf_muenzen: Dictionary = {} ## Wurfnummer -> Münze in der Tischmitte
static var _muenz_mesh: CylinderMesh
static var _muenz_mesh: ArrayMesh
static var _muenz_mat: StandardMaterial3D
var dice: Array = [] ## seat -> Array[Die]
@@ -62,96 +62,80 @@ func build(count: int, local_index: int) -> void:
## Formregeln bleibt weg: vom Boden aus ist es aus Kamerahöhe nur ein Fleck.
func _deko() -> void:
var laterne := Formen.laterne()
laterne.position = Vector3(-(table_r + 0.35), TABLE_H, table_r * 0.55)
laterne.position = Vector3(-(table_r + 0.45), 0.0, table_r * 0.55) # steht auf der Platte
add_child(laterne)
func _build_room() -> void:
# Low-Poly-Look: heller Himmel, eine Sonne mit weichen Schatten, viel
# Umgebungslicht. Kein Nebel, kein Glow - die Formen sollen klar stehen.
var env := WorldEnvironment.new()
var e := Environment.new()
e.background_mode = Environment.BG_COLOR
e.background_color = Color(0.04, 0.05, 0.07)
e.background_color = Color(0.56, 0.74, 0.88)
e.ambient_light_source = Environment.AMBIENT_SOURCE_COLOR
e.ambient_light_color = Color(0.35, 0.38, 0.45)
e.ambient_light_energy = 1.1
e.ambient_light_color = Color(0.70, 0.78, 0.92)
e.ambient_light_energy = 0.75
e.tonemap_mode = Environment.TONE_MAPPER_FILMIC
e.glow_enabled = true
e.glow_intensity = 0.45
e.glow_bloom = 0.05
e.glow_hdr_threshold = 0.9
e.fog_enabled = true
e.fog_light_color = Color(0.05, 0.06, 0.09)
e.fog_density = 0.02
e.tonemap_exposure = 0.9
env.environment = e
add_child(env)
var lamp := SpotLight3D.new()
lamp.position = Vector3(0, TABLE_H + table_r * 1.45, 0)
lamp.rotation_degrees = Vector3(-90, 0, 0)
lamp.light_energy = 2.5
lamp.light_color = Color(1.0, 0.94, 0.82)
lamp.spot_range = table_r * 4.2
lamp.spot_angle = 60.0
lamp.spot_attenuation = 0.6
lamp.shadow_enabled = true
add_child(lamp)
var sonne := DirectionalLight3D.new()
sonne.light_color = Color(1.0, 0.96, 0.90)
sonne.light_energy = 1.1
sonne.shadow_enabled = true
sonne.light_angular_distance = 3.0 # weiche Schattenkanten
sonne.directional_shadow_mode = DirectionalLight3D.SHADOW_ORTHOGONAL
sonne.directional_shadow_max_distance = 30.0
sonne.rotation_degrees = Vector3(-52.0, 35.0, 0.0)
add_child(sonne)
# Kein sichtbarer Lampenschirm: die Kamera schaut fast senkrecht von oben,
# alles über der Tischmitte hinge ihr vor der Linse.
# Sockelplatte wie ein Diorama: eine runde Scheibe mit weicher Kante,
# darunter nur Himmel.
var platte := MeshInstance3D.new()
# Klein genug, dass an den Rändern Himmel bleibt - sonst ist alles Platte.
platte.mesh = Formen.scheibe(table_r * 1.55, 0.18, 0.08)
platte.position = Vector3(0, -0.18, 0)
platte.material_override = Stoffe.boden()
add_child(platte)
var boden := StaticBody3D.new()
var bc := CollisionShape3D.new()
var bs := BoxShape3D.new()
bs.size = Vector3(40, 0.2, 40)
bc.shape = bs
bc.position = Vector3(0, -0.1, 0)
boden.add_child(bc)
add_child(boden)
var fill := DirectionalLight3D.new()
fill.rotation_degrees = Vector3(-55, 35, 0)
fill.light_energy = 0.25
add_child(fill)
# Boden
var floor_body := StaticBody3D.new()
var floor_col := CollisionShape3D.new()
var fs := BoxShape3D.new()
fs.size = Vector3(24, 0.4, 24)
floor_col.shape = fs
floor_col.position = Vector3(0, -0.2, 0)
floor_body.add_child(floor_col)
var floor_mi := MeshInstance3D.new()
var fpm := PlaneMesh.new()
fpm.size = Vector2(24, 24)
floor_mi.mesh = fpm
# Bewusst glatt und dunkel: eine Maserung auf der riesigen Fläche wird aus
# Kamerahöhe zu Rauschen, und der Nebel soll den Boden ohnehin schlucken.
floor_mi.material_override = _mat(Color(0.08, 0.07, 0.09), 0.9)
floor_body.add_child(floor_mi)
add_child(floor_body)
# Tischplatte
var table := StaticBody3D.new()
var tcol := CollisionShape3D.new()
# Tischplatte: Holz mit runder Kante, darauf die Filzeinlage.
var tisch := MeshInstance3D.new()
tisch.mesh = Formen.scheibe(table_r, 0.10, 0.045)
tisch.position = Vector3(0, TABLE_H - 0.10, 0)
tisch.material_override = Stoffe.holz()
add_child(tisch)
var einlage := MeshInstance3D.new()
einlage.mesh = Formen.scheibe(table_r - 0.16, 0.025, 0.012)
einlage.position = Vector3(0, TABLE_H - 0.012, 0)
einlage.material_override = Stoffe.filz()
add_child(einlage)
var tcol := StaticBody3D.new()
var tc := CollisionShape3D.new()
var tcs := CylinderShape3D.new()
tcs.radius = table_r
tcs.height = 0.12
tcol.shape = tcs
tcol.position = Vector3(0, TABLE_H - 0.06, 0)
table.add_child(tcol)
var tmi := MeshInstance3D.new()
var tcm := CylinderMesh.new()
tcm.top_radius = table_r
tcm.bottom_radius = table_r
tcm.height = 0.12
tmi.mesh = tcm
tmi.position = Vector3(0, TABLE_H - 0.06, 0)
tmi.material_override = Stoffe.filz()
table.add_child(tmi)
add_child(table)
tc.shape = tcs
# Oberkante auf Höhe des Zonenfilzes, damit Würfel darauf liegen, nicht darin.
tc.position = Vector3(0, TABLE_H - 0.048, 0)
tcol.add_child(tc)
add_child(tcol)
# Tischbein
var leg := MeshInstance3D.new()
var lcm := CylinderMesh.new()
lcm.top_radius = table_r * 0.09
lcm.bottom_radius = table_r * 0.22
lcm.height = TABLE_H - 0.12
leg.mesh = lcm
leg.position = Vector3(0, (TABLE_H - 0.12) * 0.5, 0)
leg.material_override = Stoffe.holz()
add_child(leg)
# Ein dicker Mittelfuss statt vier Beinen - aus Kamerahöhe sieht man ohnehin
# nur den Ansatz, und rund passt zur Knete.
var fuss := MeshInstance3D.new()
fuss.mesh = Formen.rund_zylinder(0.55, 0.35, TABLE_H - 0.10, 0.06)
fuss.material_override = Stoffe.holz()
add_child(fuss)
func _build_seat(i: int) -> void:
@@ -180,24 +164,14 @@ func _build_seat(i: int) -> void:
# Filzfläche
var felt := MeshInstance3D.new()
var fm := CylinderMesh.new()
fm.top_radius = ZONE_RAD
fm.bottom_radius = ZONE_RAD
fm.height = 0.012
fm.radial_segments = 32
felt.mesh = fm
felt.position = Vector3(0, 0.006, 0)
felt.material_override = Stoffe.filz()
felt.mesh = Formen.scheibe(ZONE_RAD + 0.02, 0.012, 0.006)
felt.position = Vector3(0, 0.0, 0)
felt.material_override = Stoffe.filz_dunkel()
zone.add_child(felt)
# Sichtbarer Rand
var rim := MeshInstance3D.new()
var tm := TorusMesh.new()
tm.inner_radius = ZONE_RAD
tm.outer_radius = ZONE_RAD + 0.07
tm.rings = 32
tm.ring_segments = 8
rim.mesh = tm
rim.mesh = Formen.ring(ZONE_RAD + 0.045, 0.035)
rim.position = Vector3(0, 0.02, 0)
rim.material_override = Stoffe.rand()
zone.add_child(rim)
@@ -287,6 +261,10 @@ func _frame_camera() -> void:
var band := 1.0 - HUD_TOP - HUD_BOTTOM
var half_v := tan(fov_v * 0.5)
var dist := (table_r * cos(tilt)) / (band * half_v)
# Geneigt wächst die nahe Tischhälfte durch die Perspektive; je schräger,
# desto mehr Abstand braucht es, damit die eigene Zone nicht unter der
# Ansageleiste verschwindet.
dist *= 1.0 + 0.38 * sin(tilt)
# Waagerecht ist normalerweise reichlich Platz, in schmalen Fenstern nicht.
dist = maxf(dist, table_r / (0.98 * tan(fov_v * 0.5) * aspect))
# Das freie Band liegt nicht mittig, der Tisch rückt entsprechend nach oben.
@@ -527,7 +505,7 @@ func set_topf(liste: Array, ziel := -1) -> void:
var ang := r.randf() * TAU
var rad := r.randf_range(0.30, 0.55)
var wappen: bool = m.get("stark", false)
var lage := Vector3(cos(ang) * rad, TABLE_H + 0.007, sin(ang) * rad)
var lage := Vector3(cos(ang) * rad, TABLE_H + 0.013, sin(ang) * rad) # auf der Einlage
var mi := MeshInstance3D.new()
mi.mesh = _muenz_form()
mi.material_override = _muenz_stoff(wappen)
@@ -565,15 +543,11 @@ static var _praeg_mesh: TorusMesh
static var _praeg_mat: StandardMaterial3D
static func _muenz_form() -> CylinderMesh:
static func _muenz_form() -> ArrayMesh:
if _muenz_mesh == null:
_muenz_mesh = CylinderMesh.new()
# Aus Kamerahöhe muss eine Münze fast so gross sein wie ein Würfel,
# sonst ist sie ein Punkt.
_muenz_mesh.top_radius = 0.11
_muenz_mesh.bottom_radius = 0.11
_muenz_mesh.height = 0.014
_muenz_mesh.radial_segments = 24
_muenz_mesh = Formen.scheibe(0.11, 0.016, 0.006)
return _muenz_mesh