This commit is contained in:
team3
2026-09-16 17:55:38 +02:00
parent c9416ed3c6
commit f012dd7cd5
17 changed files with 878 additions and 160 deletions

View File

@@ -1,5 +1,6 @@
extends Node3D
## Baut aus 2D-Stuetzpunkten eine geschlossene Gleisschleife inkl. Optik.
## Streckennetz aus Abschnitten. Ein Abschnitt hat einen oder zwei
## Nachfolger - bei zweien steht dort eine Weiche.
const Mat = preload("res://scripts/mat.gd")
const Deco = preload("res://scripts/deco.gd")
@@ -9,37 +10,69 @@ const SLEEPER := Color("5e4130")
const RAIL := Color("9a9da2")
const STEP := 1.2
var path: Path3D
## Jeder Eintrag: { "name", "curve": Curve3D, "length", "next": [ids], "prev": [ids] }
var segments: Array = []
func build(points: PackedVector2Array) -> void:
path = Path3D.new()
path.name = "TrackPath"
## Abschnitt anlegen. Anfangs- und Endrichtung werden vorgegeben, damit
## sich mehrere Abschnitte an einer Weiche ohne Knick treffen.
func add_segment(seg_name: String, points: Array, t_start: Vector2, t_end: Vector2) -> int:
var c := Curve3D.new()
var n := points.size()
# Catmull-Rom Tangenten -> weiche, geschlossene Schleife.
for i in n + 1:
var idx := i % n
var prev := points[(idx - 1 + n) % n]
var nxt := points[(idx + 1) % n]
var t := (nxt - prev) / 6.0
var p := points[idx]
for i in n:
var p: Vector2 = points[i]
var t: Vector2
if i == 0:
t = t_start.normalized() * p.distance_to(points[1]) / 3.0
elif i == n - 1:
t = t_end.normalized() * p.distance_to(points[n - 2]) / 3.0
else:
t = (points[i + 1] - points[i - 1]) / 6.0
c.add_point(Vector3(p.x, 0, p.y), Vector3(-t.x, 0, -t.y), Vector3(t.x, 0, t.y))
path.curve = c
add_child(path)
_build_visuals()
segments.append({"name": seg_name, "curve": c, "length": c.get_baked_length(),
"next": [], "prev": []})
return segments.size() - 1
func length() -> float:
return path.curve.get_baked_length()
func connect_segments(from: int, to: int) -> void:
segments[from]["next"].append(to)
segments[to]["prev"].append(from)
func sample(offset: float) -> Transform3D:
return path.curve.sample_baked_with_rotation(fposmod(offset, length()), true, true)
func finish() -> void:
for i in segments.size():
_build_visuals(i)
func _build_visuals() -> void:
var count := int(length() / STEP)
func seg_length(i: int) -> float:
return float(segments[i]["length"])
func seg_name(i: int) -> String:
return String(segments[i]["name"])
func next_of(i: int) -> Array:
return segments[i]["next"]
func prev_of(i: int) -> Array:
return segments[i]["prev"]
func is_switch(i: int) -> bool:
return segments[i]["next"].size() > 1
func sample(i: int, offset: float) -> Transform3D:
var c: Curve3D = segments[i]["curve"]
return c.sample_baked_with_rotation(clampf(offset, 0.0, seg_length(i)), true, false)
## Nächster Punkt auf irgendeinem Abschnitt - für die Deko-Verteilung.
func distance_to_track(p: Vector2) -> float:
var best := INF
for s in segments:
var c: Curve3D = s["curve"]
var q: Vector3 = c.get_closest_point(Vector3(p.x, 0, p.y))
best = minf(best, Vector2(q.x, q.z).distance_to(p))
return best
func _build_visuals(i: int) -> void:
var count := int(seg_length(i) / STEP)
var xf: Array[Transform3D] = []
for i in count:
xf.append(sample(i * STEP))
for k in count:
xf.append(sample(i, k * STEP + STEP * 0.5))
_multi(Deco.box(Vector3(2.7, 0.16, STEP * 1.12)), BALLAST, xf, [Vector3(0, 0.08, 0)])
_multi(Deco.box(Vector3(2.1, 0.09, 0.34)), SLEEPER, xf, [Vector3(0, 0.20, 0)])
_multi(Deco.box(Vector3(0.09, 0.11, STEP * 1.08)), RAIL, xf,