extends Node3D ## Baut aus 2D-Stuetzpunkten eine geschlossene Gleisschleife inkl. Optik. const Mat = preload("res://scripts/mat.gd") const Deco = preload("res://scripts/deco.gd") const BALLAST := Color("d98d4a") const SLEEPER := Color("5e4130") const RAIL := Color("9a9da2") const STEP := 1.2 var path: Path3D func build(points: PackedVector2Array) -> void: path = Path3D.new() path.name = "TrackPath" 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] 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() func length() -> float: return path.curve.get_baked_length() func sample(offset: float) -> Transform3D: return path.curve.sample_baked_with_rotation(fposmod(offset, length()), true, true) func _build_visuals() -> void: var count := int(length() / STEP) var xf: Array[Transform3D] = [] for i in count: xf.append(sample(i * STEP)) _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, [Vector3(-0.62, 0.29, 0), Vector3(0.62, 0.29, 0)]) func _multi(mesh: Mesh, color: Color, xf: Array[Transform3D], offsets: Array) -> void: var mm := MultiMesh.new() mm.transform_format = MultiMesh.TRANSFORM_3D mm.mesh = mesh mm.instance_count = xf.size() * offsets.size() var i := 0 for t in xf: for o in offsets: mm.set_instance_transform(i, t.translated_local(o)) i += 1 var mmi := MultiMeshInstance3D.new() mmi.multimesh = mm mmi.material_override = Mat.flat(color) add_child(mmi)