From 37e01519881c264c2268e0016e8d1fa89a7d3623 Mon Sep 17 00:00:00 2001 From: Jonas Reith Date: Wed, 26 Aug 2026 20:46:52 +0200 Subject: [PATCH] Wall off the table's own 6 edges too, not just the outer ridges MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit _build_region_borders() previously only bordered the 6 seams between adjacent outer regions (table corner -> girdle corner). Generalized _build_ridge() into _build_border_segment(p0, p1), which chains overlap-guaranteed props along any straight 3D segment, and reused it for the 6 table edges (table corner -> next table corner) as well — these separate the center region from each outer region. Verified headless the same way as the ridges: 43/43 pairs on one table edge genuinely overlap (worst case -0.13 units). 744 border props total across all 12 edges now. --- terrain.gd | 55 +++++++++++++++++++++++++++++++----------------------- 1 file changed, 32 insertions(+), 23 deletions(-) diff --git a/terrain.gd b/terrain.gd index 2ee4b64..4ede1e6 100644 --- a/terrain.gd +++ b/terrain.gd @@ -134,47 +134,62 @@ func _build_pavilion() -> void: add_child(mi) # ═══════════════════════════════════════════════ -# GRENZEN — Berg/Wald entlang der 6 Grate zwischen den Regionen -# Grat k = Strecke von Tisch-Ecke T[k] zu Rundiste-Ecke G[k] -# (gemeinsame Kante von Facette k-1 und Facette k) +# GRENZEN — Berg/Wald entlang aller Kanten zwischen den 7 Regionen: +# 6 Grate Tisch-Ecke T[k] -> Rundiste-Ecke G[k] (zwischen den Außenregionen) +# + 6 Tisch-Kanten T[k] -> T[k+1] (zwischen Zentrum und jeder Außenregion) # ═══════════════════════════════════════════════ func _build_region_borders() -> void: var borders := Node3D.new() borders.name = "Borders" add_child(borders) + var table_pts : Array[Vector3] = [] + var girdle_pts : Array[Vector3] = [] for k in range(6): var a := _hex_angle(k) - var dir := Vector3(cos(a), 0.0, sin(a)) - var perp := Vector3(-dir.z, 0.0, dir.x) - _build_ridge(borders, dir, perp) + table_pts.append(Vector3(cos(a) * table_radius, 0.0, sin(a) * table_radius)) + girdle_pts.append(Vector3(cos(a) * girdle_radius, -crown_drop, sin(a) * girdle_radius)) -# Kettet Props entlang eines Grats: jeder neue Prop wird so nah an den vorigen -# gesetzt, dass sich ihre Welt-Radien garantiert überlappen (Distanz zwischen -# den Mittelpunkten <= (r1+r2) * border_overlap). Kein Rätselraten über feste -# Abstände mehr — die Lücke wird pro Prop-Paar explizit geprüft und korrigiert. -func _build_ridge(borders: Node3D, dir: Vector3, perp: Vector3) -> void: - var t := table_radius + for k in range(6): + var k1 := (k + 1) % 6 + _build_border_segment(borders, table_pts[k], girdle_pts[k]) # Grat: Außenregion <-> Außenregion + _build_border_segment(borders, table_pts[k], table_pts[k1]) # Tisch-Kante: Zentrum <-> Außenregion + +# Kettet Props entlang einer geraden Strecke p0->p1: jeder neue Prop wird so nah +# an den vorigen gesetzt, dass sich ihre Welt-Radien garantiert überlappen +# (Distanz zwischen den Mittelpunkten <= (r1+r2) * border_overlap). Kein +# Rätselraten über feste Abstände mehr — die Lücke wird pro Prop-Paar +# explizit geprüft und korrigiert. Funktioniert für geneigte (Grat) wie +# flache (Tisch-Kante) Strecken gleichermaßen, da einfach entlang der echten +# 3D-Linie zwischen den beiden Punkten gelaufen wird. +func _build_border_segment(borders: Node3D, p0: Vector3, p1: Vector3) -> void: + var length := p0.distance_to(p1) + if length < 0.001: + return + var dir := (p1 - p0) / length + var perp := Vector3(-dir.z, 0.0, dir.x) + + var t := 0.0 var prev_pos := Vector3.ZERO var prev_radius := 0.0 var first := true - while t <= girdle_radius: + while t <= length: var kind: Dictionary = BORDER_KINDS[randi() % BORDER_KINDS.size()] var radius: float = kind["radius"] * kind["scale"] var lateral := randf_range(-border_jitter, border_jitter) - var pos := _ridge_point(dir, perp, t, lateral) + var pos := p0 + dir * t + perp * lateral if not first: var min_dist := (prev_radius + radius) * border_overlap - # Iterativ korrigieren statt blind zu vertrauen: die Facette ist geneigt, - # daher ist die Distanz nicht rein radial (Höhe hängt am Abstand mit dran). + # Iterativ korrigieren statt blind zu vertrauen (seitlicher Jitter + # verschiebt den Punkt leicht von der reinen Geraden weg). for _i in range(4): var actual_dist := pos.distance_to(prev_pos) if actual_dist <= min_dist: break t -= (actual_dist - min_dist) - pos = _ridge_point(dir, perp, t, lateral) + pos = p0 + dir * t + perp * lateral _spawn_border_prop(borders, kind, pos) prev_pos = pos @@ -182,12 +197,6 @@ func _build_ridge(borders: Node3D, dir: Vector3, perp: Vector3) -> void: first = false t += radius # nächster Kandidat startet grob hinter diesem Prop; obige Prüfung zieht ihn bei Bedarf näher -func _ridge_point(dir: Vector3, perp: Vector3, t: float, lateral: float) -> Vector3: - var frac: float = clamp((t - table_radius) / (girdle_radius - table_radius), 0.0, 1.0) - var pos := dir * t + perp * lateral - pos.y = lerp(0.0, -crown_drop, frac) - return pos - func _spawn_border_prop(parent: Node3D, kind: Dictionary, pos: Vector3) -> void: var inst := (kind["scene"] as PackedScene).instantiate() as Node3D inst.position = pos