extends Node3D ## 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") const BALLAST := Color("d98d4a") const SLEEPER := Color("5e4130") const RAIL := Color("9a9da2") const STEP := 1.2 ## Jeder Eintrag: { "name", "curve": Curve3D, "length", "next": [ids], "prev": [ids] } var segments: Array = [] ## 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() 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)) segments.append({"name": seg_name, "curve": c, "length": c.get_baked_length(), "next": [], "prev": []}) return segments.size() - 1 func connect_segments(from: int, to: int) -> void: segments[from]["next"].append(to) segments[to]["prev"].append(from) func finish() -> void: for i in segments.size(): _build_visuals(i) 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 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, [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)