extends Node ## Weichen: Route wählen, Übergang ohne Sprung, Bergstrecke erreichbar. var main var step := 0 var wait := 0.0 var ok := 0 var fail := 0 var last_pos := Vector3.ZERO var worst_jump := 0.0 var jump_frames := 0 var _dbg := 0.0 var _cam_hits := 0 var _cam_pulled := 0 var _cam_yaw := 0 func chk(n: String, c: bool, i := "") -> void: if c: ok += 1; print(" OK %s %s" % [n, i]) else: fail += 1; print(" FAIL %s %s" % [n, i]) func _key(c: int, d: bool) -> void: var e := InputEventKey.new(); e.physical_keycode = c; e.keycode = c; e.pressed = d Input.parse_input_event(e) func _watch(d: float) -> void: var t = main.train var p: Vector3 = t.cars[t.cars.size() - 1].global_position if last_pos != Vector3.ZERO and d > 0.0: var jump := p.distance_to(last_pos) var allowed: float = t.speed * d * 1.5 + 0.05 if jump > allowed: jump_frames += 1 worst_jump = maxf(worst_jump, jump - t.speed * d) last_pos = p ## Im Physik-Takt messen: dort bewegt sich der Zug genau einmal pro Aufruf. func _physics_process(d: float) -> void: if main != null and main.started and step >= 1 and step <= 8: _watch(d) func _process(d): if main == null: main = get_tree().current_scene return if not main.started: main._start_solo() return var t = main.train if wait > 0.0: wait -= d return match step: 0: chk("Drei Abschnitte", main.track.segments.size() == 3) chk("Heimstrecke hat Weiche", main.track.is_switch(2)) chk("Sechs Bahnhöfe", main.stations.size() == 6) main._park_at(main.stations[4]) # Ahornstadt, Heimstrecke chk("Start auf Heimstrecke", t.seg == 2, "seg=%d" % t.seg) chk("Weiche voraus erkannt", t.upcoming_switch() == 2) var nxt: Array = t.next_station() chk("Nächster Halt Waldkirch (links)", nxt[0].station_name == "Waldkirch", "%s" % nxt[0].station_name) t.switch_choice = 1 var nxt2: Array = t.next_station() chk("Nächster Halt Bergblick (rechts)", nxt2[0].station_name == "Bergblick", "%s" % nxt2[0].station_name) t.switch_choice = 0 main.driver_id = 1 _key(KEY_W, true) last_pos = Vector3.ZERO wait = 1.0 1: wait = 0.5 2: if t.seg != 0: step -= 1 wait = 0.3 _dbg += 0.3 if _dbg >= 2.0: _dbg = 0.0 print("[dbg] seg=%d prog=%.1f/%.1f v=%.1f thr=%.1f driver=%d mode=%d" % [t.seg, t.progress, main.track.seg_length(t.seg), t.speed, t.throttle, main.driver_id, main.player.mode]) else: _key(KEY_W, false) _key(KEY_S, true) chk("Links -> Talstrecke", t.seg == 0, "seg=%d" % t.seg) chk("Historie geführt", t.history.size() > 0 and t.history[t.history.size() - 1] == 2, "%s" % [t.history]) chk("Letzter Wagen ohne Sprung", jump_frames == 0, "Sprungframes=%d, größter Sprung %.2f m" % [jump_frames, worst_jump]) wait = 4.0 3: _key(KEY_S, false) main._park_at(main.stations[4]) t.switch_choice = 1 last_pos = Vector3.ZERO jump_frames = 0 worst_jump = 0.0 _key(KEY_D, true) _key(KEY_W, true) wait = 1.0 4: wait = 0.5 5: if t.seg != 1: step -= 1 wait = 0.3 else: chk("Rechts -> Bergstrecke", t.seg == 1, "seg=%d" % t.seg) chk("D hält die Weiche rechts", t.switch_choice == 1) chk("Übergang rechts ohne Sprung", jump_frames == 0, "Sprungframes=%d" % jump_frames) _key(KEY_D, false) wait = 0.5 6: var nxt: Array = t.next_station() chk("Bergblick voraus", nxt[0].station_name == "Bergblick", "%s" % nxt[0].station_name) wait = 0.5 7: # bis kurz vor Bergblick fahren, dann bremsen var berg = main.stations[5] var ahead: float = t.distance_ahead(berg) if ahead > t.speed * t.speed / 16.0 + 8.0: step -= 1 wait = 0.2 else: _key(KEY_W, false) _key(KEY_S, true) wait = 6.0 8: _key(KEY_S, false) chk("Zug steht", t.speed < 0.05, "v=%.2f" % t.speed) chk("Am Bergblick angekommen", t.docked_at != null and t.docked_at.station_name == "Bergblick", "dock=%s" % ("-" if t.docked_at == null else t.docked_at.station_name)) # Sichtkontrolle: Kreuzung von oben main._park_at(main.stations[4]) t.place_head(2, main.track.seg_length(2) - 6.0) main._toggle_camera() main.cam_rig.distance = 95.0 main.cam_rig.pitch = deg_to_rad(-70.0) main.cam_rig.yaw = 0.4 wait = 1.0 9: get_viewport().get_texture().get_image().save_png("user://junction.png") t.place_head(0, main.track.seg_length(0) - 20.0) main.cam_rig.snap_to(t.cars[0].global_position) wait = 1.0 10: get_viewport().get_texture().get_image().save_png("user://junction2.png") # Kamera-Kollision: Fokus auf den Bahnsteig, rundherum drehen var st = main.stations[0] main.cam_rig.target = null main.cam_rig.snap_to(st.global_position + Vector3(0, 0, 0)) main.cam_rig.distance = 30.0 main.cam_rig.pitch = deg_to_rad(-10.0) _cam_hits = 0 _cam_yaw = 0 wait = 0.2 11: if _cam_yaw < 12: main.cam_rig.yaw = _cam_yaw * TAU / 12.0 _cam_yaw += 1 step -= 1 wait = 0.15 if main.cam_rig.blocked: _cam_hits += 1 var dist: float = main.cam_rig._cam.global_position.distance_to(main.cam_rig.global_position) if dist < 29.0: _cam_pulled += 1 else: chk("Kamera stößt am Gebäude an", _cam_hits > 0, "%d von 12 Richtungen" % _cam_hits) chk("Kamera rückt davor", _cam_pulled == _cam_hits, "%d/%d" % [_cam_pulled, _cam_hits]) 12: print("== %d ok, %d fail ==" % [ok, fail]) get_tree().quit(1 if fail > 0 else 0) step += 1