Level Editor/Scripting/Payload tracks: Difference between revisions
TeamSpecBot (talk | contribs) Level Editor: payload tracks scripting guide |
TeamSpecBot (talk | contribs) American spelling |
||
| Line 12: | Line 12: | ||
== Driving the cart == | == Driving the cart == | ||
Everything is measured in | Everything is measured in meters along the track: 0 is the start and [[Level Editor/Scripting/Reference/GamemodeServerApi#track_length|api.track_length]] is the end. | ||
* [[Level Editor/Scripting/Reference/GamemodeServerApi#tracks|api.tracks]] lists every track by name. | * [[Level Editor/Scripting/Reference/GamemodeServerApi#tracks|api.tracks]] lists every track by name. | ||
* [[Level Editor/Scripting/Reference/GamemodeServerApi#track_progress|api.track_progress]] is how far the cart has come this tick. | * [[Level Editor/Scripting/Reference/GamemodeServerApi#track_progress|api.track_progress]] is how far the cart has come this tick. | ||
* [[Level Editor/Scripting/Reference/GamemodeServerApi#track_checkpoints|api.track_checkpoints]] lists each checkpoint's distance, in order. | * [[Level Editor/Scripting/Reference/GamemodeServerApi#track_checkpoints|api.track_checkpoints]] lists each checkpoint's distance, in order. | ||
* [[Level Editor/Scripting/Reference/GamemodeServerApi#set_track_speed|api.set_track_speed]] sets the speed the cart heads for, in | * [[Level Editor/Scripting/Reference/GamemodeServerApi#set_track_speed|api.set_track_speed]] sets the speed the cart heads for, in meters per second: negative rolls it back, 0 stops it. The cart speeds up and slows down smoothly rather than jumping. Setting the same speed again costs nothing, so set it every tick from what the rules say right now. | ||
* [[Level Editor/Scripting/Reference/GamemodeServerApi#set_track_floor|api.set_track_floor]] stops the cart rolling back past a distance. Raise it to a checkpoint once the cart reaches it, and the checkpoint holds. | * [[Level Editor/Scripting/Reference/GamemodeServerApi#set_track_floor|api.set_track_floor]] stops the cart rolling back past a distance. Raise it to a checkpoint once the cart reaches it, and the checkpoint holds. | ||
* [[Level Editor/Scripting/Reference/GamemodeServerApi#track_point|api.track_point]] gives the world position a distance along the track, for placing things relative to the cart. | * [[Level Editor/Scripting/Reference/GamemodeServerApi#track_point|api.track_point]] gives the world position a distance along the track, for placing things relative to the cart. | ||
Latest revision as of 04:44, 20 October 2026
A payload track is a railed path with a cart on it. The map lays the track; your script decides when and how fast the cart moves, and what reaching a checkpoint means.
Laying a track
- Choose Functional > Payload Track.
- Click to drop the track's points, start first. Enter or a double-click finishes the track, Backspace takes back the last point, and Esc abandons it.
- The points are the track's anchors. Drag one to reshape the track, click the track to add one, or use Insert Path Anchor in the scene tree's right-click menu.
- Select an anchor to set it in the inspector: Checkpoint marks a checkpoint (ignored on the first and last anchor: the start is not a checkpoint and the end is the goal), unticking Smooth makes a sharp corner instead of a curve, and Marker names the point for your script (see Markers).
The track's name in the scene tree is the name your script uses for it. Everything about laying and editing a track is on Payload Track.
Driving the cart
Everything is measured in meters along the track: 0 is the start and api.track_length is the end.
- api.tracks lists every track by name.
- api.track_progress is how far the cart has come this tick.
- api.track_checkpoints lists each checkpoint's distance, in order.
- api.set_track_speed sets the speed the cart heads for, in meters per second: negative rolls it back, 0 stops it. The cart speeds up and slows down smoothly rather than jumping. Setting the same speed again costs nothing, so set it every tick from what the rules say right now.
- api.set_track_floor stops the cart rolling back past a distance. Raise it to a checkpoint once the cart reaches it, and the checkpoint holds.
- api.track_point gives the world position a distance along the track, for placing things relative to the cart.
- api.track_markers lists the track's markers by name, in order, and api.track_marker gives one's distance, or -1.0 when the track has no marker by that name.
Markers
A marker is a name you give a track anchor in the inspector. It means nothing until your script reads it: use one wherever something should happen at a place on the route, such as a door, a hazard, a speed change or a hill. Every anchor may carry one, the first and last included, and the names on one track must differ: the viewport flags a repeated name, and the export leaves out a track that has one.
When the cart passes a marker the game calls _track_marker(track, marker, forward), before _tick. forward is false when the cart rolled back past it. A cart standing exactly on a marker has reached it, several markers passed in one tick arrive in the order the cart passed them, and a marker the cart starts the round on or behind is never passed.
A hill
The cart rolls back down a hill the moment nobody is pushing it, rather than waiting. Mark the anchor at the foot hill_start and the one at the top hill_end. The floor still holds at the last checkpoint, so the cart never rolls back past one.
const TRACK := &"Track" const ATTACKERS := 1 const PUSH_SPEED := 1.5 const ROLLBACK_SPEED := 0.5 const ROLLBACK_DELAY := 20.0 var _on_hill: bool = false var _pushers: int = 0 var _unattended: float = 0.0 func _track_marker(track: StringName, marker: StringName, forward: bool) -> void: if track != TRACK: return if marker == &"hill_start": _on_hill = forward elif marker == &"hill_end": _on_hill = not forward func _zone_tick(zone: StringName, occupants: Array, _delta: float) -> void: if zone != api.track_zone(TRACK): return _pushers = 0 for entity_id in occupants: if api.team_of(entity_id) == ATTACKERS: _pushers += 1 func _tick(delta: float) -> void: _unattended = 0.0 if _pushers > 0 else _unattended + delta if _pushers > 0: api.set_track_speed(TRACK, PUSH_SPEED) elif _on_hill or _unattended >= ROLLBACK_DELAY: api.set_track_speed(TRACK, -ROLLBACK_SPEED) else: api.set_track_speed(TRACK, 0.0)
To slow the cart before it reaches a marker, plan with its distance: api.track_marker(TRACK, &"hill_start") - api.track_progress(TRACK) is how far away it is.
The client and bot scripts do not hear markers. To show a marker's effect on the HUD or tell the bots about it, keep it in a counter from _track_marker.
The push zone
The cart carries a zone that moves with it. Its key is api.track_zone(track) and its label is the track's name, and it arrives through _zone_entered, _zone_exited and _zone_tick like any other zone. A simple push rule:
const TRACK := &"Track" const ATTACKERS := 1 const PUSH_SPEED := 2.5 func _zone_tick(zone: StringName, occupants: Array, _delta: float) -> void: if zone != api.track_zone(TRACK): return var pushers: int = 0 var blocked: bool = false for entity_id in occupants: if api.team_of(entity_id) == ATTACKERS: pushers += 1 else: blocked = true api.set_track_speed(TRACK, 0.0 if blocked or pushers == 0 else PUSH_SPEED) if api.track_progress(TRACK) >= api.track_length(TRACK): api.declare_winner(ATTACKERS, "delivered the payload")
The dispenser
The cart carries a dispenser, off until the mode points it at a team. api.set_track_dispenser(track, team) turns it on: it then heals and resupplies that team's players standing in the cart's push area and in its sight, at half a built dispenser's rate, so only the players pushing the cart benefit, with a heal beam from the green lamp on the cabinet's roof to each of them. That team's bots treat it like a built dispenser: a hurt or empty bot walks to the cart and waits there to be topped up. Call it once from _start; 0 turns it off again.
func _start() -> void: api.set_track_dispenser(TRACK, ATTACKERS)
Showing it on the HUD
The client script can read api.tracks, api.track_length and api.track_checkpoints, but not where the cart is: keep the progress in a global counter on the server and show it with the payload_progress widget (see Client HUD).
# server.gd func _declare() -> void: api.declare_global_counter(&"cart", 0, 0, 1000) func _tick(_delta: float) -> void: var length: float = api.track_length(&"Track") if length > 0.0: api.set_global(&"cart", roundi(api.track_progress(&"Track") / length * 1000.0))
# client.gd
func _start() -> void:
var length: float = api.track_length(&"Track")
var checkpoints: Array = []
for distance in api.track_checkpoints(&"Track"):
checkpoints.append(distance / length)
api.show_widget(&"payload_progress", {
"counter": "cart",
"scale": api.counter_maximum(api.SCOPE_GLOBAL, &"cart"),
"checkpoints": checkpoints,
})