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[Node3D, Array] = { $station_hirschfeld: [[$station_university_mensa, $station_parity_square],[]], $station_hirschfeld : [[$station_university_mensa, $station_parity_square],[]], $station_university_mensa : [[$station_university_main],[]], $station_university_main: [[$station_ministry],[$station_rosenthal, $station_university_mensa]], $station_parity_square : [[$station_saint_exupery],[$station_rosenthal]], $station_saint_exupery : [[$station_saint_exupery],[$station_rosenthal]], $station_ministry : [null,null], # Endstation $station_rosenthal : [null,null], # Endstation } ## List of all registered station nodes, used to unparent them @onready var stations : Array[Node3D] = 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 : Node3D = $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($station_hirschfeld) enter_station(current_station) var current_station : Node3D = null var stop := false var destinations : Array[Node3D] = [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 fahrplan[current_station][track.index] == null: # empty array (just no routes) would be falsy 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