class_name Fahrplan extends Node3D ## easy graph: : [Track1Train1 (next halt), Track1Train2], [Track2Train1(next halt), ...] ## CAVEAT: These must be direct children of the fahrplan! @onready var fahrplan : Dictionary[Station, Array] = { $hirschfeld: [["u2", $uni_mensa, "u1", $parity_square],[]], $uni_mensa : [["u2", $uni_main],[]], $uni_main: [["u2", $ministry],["u8", $rosenthal, "u2", $uni_mensa, "u1", $saint_exupery]], $parity_square : [["u4", $saint_exupery, "u1", $saint_exupery], []], $saint_exupery : [["u4", $rosenthal], ["u1", $uni_main]], $ministry : ["", null, "", null], # Endstation $rosenthal : ["", null, "", null], # Endstation } ## List of all registered station nodes, used to unparent them @onready var stations : Array[Station] = fahrplan.keys() @onready var tracks : Array[Dolly] = [%Track0Dolly, %Track1Dolly] @export var empty_train_random_delay : Vector2 = Vector2(5.0, 20.0) func _set_signage_texts(group: StringName, message: String) -> void: get_tree().call_group(group, "set_text", "") for i in range(len(message)): get_tree().call_group(group, "set_text", message.substr(0, i+1)) await get_tree().create_timer(0.05).timeout func _ready() -> void: var x : Station = $hirschfeld print(x.name) await get_tree().process_frame tracks[0].train_left.connect(_player_train_left) tracks[1].train_left.connect(_player_train_left) _unparent_all_stations_except($hirschfeld) enter_station(current_station) var current_station : Station = null var stop := false var destinations : Array[Station] = [null, null] ## Begins the scheduled traffic (looping through the list of destinations) on a given track func _begin_traffic_loop(track: Dolly, cancel: Array) -> void: if not track.player_on_board and fahrplan[current_station][track.index] == null: # empty trains dont arrive at endstation track.arrive(true) _set_signage_texts(track.signage_group, "Endstation") return var routes : Array = fahrplan[current_station][track.index] if routes.is_empty(): _set_signage_texts(track.signage_group, "Verkehr z. Zt.\nunregelmäßig") return while true: if cancel.is_empty(): return # abort the loop var next : Node = routes.pop_front() routes.append(next) # It's a ring buffer destinations[track.index] = next _set_signage_texts(track.signage_group, next.name) # TODO: load nice string # Vary our schedule a little by making empty trains wait a random amount of time if not track.player_on_board: await get_tree().create_timer(randf_range(empty_train_random_delay.x, empty_train_random_delay.y)).timeout if cancel.is_empty(): return # abort the loop await track.cycle() # arrive and depart var cancellation_token : Array func enter_station(station: Node): prints("------------", "ENTER STATION", station, station.name, "------------") remove_child(current_station) current_station = station add_child(current_station) cancellation_token = ["go"] # Allocate a new stopping token _begin_traffic_loop(tracks[0], cancellation_token) _begin_traffic_loop(tracks[1], cancellation_token) func _player_train_left(track: Dolly) -> void: cancellation_token.clear() enter_station(destinations[track.index]) func _unparent_all_stations_except(except : Node3D): for station in stations: if station == except: current_station = station continue assert(station.get_parent() == self, "A station that isn't a child of Fahrplan is in the Fahrplan: %s" % station.name) remove_child(station) station.visible = true # Make visible by default, parenting handles visibility and collision