Reference
vehicle.input
The controls class holds a car's controls as the physics receives them each frame, an AI car's included,
together with the rest of the game's input record for that player. It is reached as a vehicle's
input field (ss.player.input for the local player) and is a
live object: reading a field reads what the game wrote this frame, and
assigning a field holds that control from then on.
Instance members#
Instance members must be accessed through a vehicle's input field.
local input = ss.player.input
input.steer = 0.5
input:press("camera")Instance Methods#
| Function | Return Values | Description |
|---|---|---|
press(string name) |
nil | Presses the named button for exactly one frame, which is what a tap of the button gives the game. name is one of camera, replay, powerplay1, powerplay2, full_powerbar or respot. See Pressing a button. |
clear() |
nil | Releases every held control, handing the car back to the pad or the AI. |
Instance Fields#
| Type | Field | Read-only? | Description |
|---|---|---|---|
| number | steer |
No | The steering input, -1 (left) to 1 (right), after the game's steer curve. Setting this field holds it; see Holding a control. |
| number | throttle |
No | The throttle, 0 to 1. Setting this field holds it. |
| number | brake |
No | The brake, 0 to 1. Setting this field holds it. |
| boolean | handbrake |
No | Whether the handbrake is down. Setting this field holds it. |
| number | look_x |
No | The sideways look axis, -1 to 1: positive looks right, negative looks left. Setting this field holds it. |
| number | look_y |
No | The lengthways look axis, -1 to 1: positive looks forward, negative looks back. look_y = -1 is the rear view, facing the car's nose. Setting this field holds it. |
| boolean | camera |
No | Whether the camera button is down. Setting this field holds it. |
| boolean | replay |
No | Whether the instant replay button (IR on the Controls screen) is down. Setting this field holds it. |
| boolean | powerplay1 |
No | Whether the Power Play level 1 button went down on this frame. Setting this field holds it, which presses the button again every frame. |
| boolean | powerplay2 |
No | Whether the Power Play level 2 button went down on this frame. Setting this field holds it, which presses the button again every frame. |
| boolean | pause |
Yes | Whether the pause button is down. Read-only: the game's pause reads the keyboard and pad directly, so holding this field from a script does nothing. |
| boolean | full_powerbar |
No | The game's DebugCheat_FullPowerbar flag in the record. true fills the player's power bar. Setting this field holds it. |
| boolean | respot |
No | The game's manual respot: true puts the car back on the track without a crash. Setting this field holds it. car:respot() presses it once. |
| table | override |
Yes | A table of the controls currently held and their values. |
| table | raw |
Yes | The input record itself, indexed 0 to 63. Its slots are writable. See The raw record. |
Holding a control#
The game writes the four physics controls (steer, throttle, brake and
handbrake) once a frame, from the pad's bindings for a human and from the AI driver for an AI, and
the hook writes the held values over them immediately after. Assigning a control holds it every frame until it
is set to nil or the race ends. input = { throttle = 1, steer = 0.3 } holds several at once,
input = nil or input:clear() releases them all, and override lists what is
held.
Observed on the airport track: the idle local car drives off under throttle = 1, steer = 0.4; an
AI car under throttle = 0, brake = 1 slows from 29 m/s to a stop in three seconds and pulls away
again when released (it keeps steering by itself unless steer is held as well); the handbrake stops
a car at speed within a second.
The other controls#
The fields other than the four physics controls are read off the game's own input record, an AI's included, and are held the same way: the hook writes a held value into the record every frame before the game reads it. The keys and pad buttons listed are the defaults; the Controls screen can rebind them.
| Type | Field | Description |
|---|---|---|
| number | look_x |
-1 to 1: look right (positive) or left. look_x = 1 swings the view round to the car's side. Keys H and F, the right stick. |
| number | look_y |
-1 to 1: look forward (positive) or back. look_y = -1 is the rear view, facing the car's nose. Keys T and G, the right stick. |
| boolean | camera |
The camera button, while down. Key Q, pad Y. |
| boolean | replay |
The instant replay button, while down. Key R, pad LB. |
| boolean | powerplay1 |
Power Play level 1: true on the frame the button went down. Key 1, pad A. |
| boolean | powerplay2 |
Power Play level 2: true on the frame the button went down. Key 2, pad B. |
| boolean | pause |
The pause button, while down. Read-only. Key Esc, pad Start. |
| boolean | full_powerbar |
The game's own debug flag in the record: true fills the player's power bar. No key. |
| boolean | respot |
The manual respot: true on the frame the button went down. Pad Back; no key. The game only takes it from a script, since its modes switch the manual respot off. |
Pressing a button#
press(name) presses camera, replay, powerplay1,
powerplay2, full_powerbar or respot for exactly one frame, which is what a tap of the button
gives the game: ss.player.input:press("camera") steps to the next camera once. The Power Play
buttons are pressed-edge buttons in the game as well, so holding one through an assignment presses it again
every frame, and a Power Play fires whenever one is in reach.
Observed with the idle local car: look_y = -1 turned the view round to the front of the car,
look_x = 1 to its side, press("camera") switched the chase camera to the bumper
camera, and full_powerbar held for three seconds filled the HUD's power bar from empty, where it
stayed. A powerplay1 press with nothing in reach fired nothing, as a pad press would not.
The raw record#
raw[k], for k from 0 to 63, is the player's input record as the game's reader fills it
from the bindings for a human (the AI fills its own cars' records). The axes are floats; the button slots hold
the integers 0 and 1, and raw[k] reads them as integers. A write to a button slot takes an
integer, with true and false counting as 1 and 0.
| Type | Field | Description |
|---|---|---|
| number | [0] |
Brake, 0 to 1. Key S, pad LT. |
| number | [2] |
Throttle, 0 to 1. Key W, pad RT. |
| number | [3] |
Steer, -1 to 1, after the steer curve. Keys A and D, the left stick. |
| number | [5], [6] |
look_x and look_y. Keys F, H and G, T, the right stick. |
| integer | [7] |
camera, while held. Key Q, pad Y. |
| integer | [8] |
replay, while held. Key R, pad LB. |
| integer | [0xc] |
Pressed. Its use is not known (?). Key 2, pad A. |
| integer | [0xf] |
pause, while held. Key Esc, pad Start. |
| integer | [0xe], [0x10]..[0x12] |
While held. Unbound in the shipped tables. |
| integer | [0x2a], [0x2b] |
powerplay1 and powerplay2, pressed. Keys 1 and 2, pad A and B. |
| integer | [0x2c], [0x2d] |
Pressed. [0x2c] is unbound; [0x2d] is respot, pad Back. |
| integer | [0x2e] |
full_powerbar. |
| integer | [0x2f] |
Two bytes: Enter pressed in the low byte, then 1 in the next byte once the pad reader has run. The high half is never written. |
A "while held" slot is 1 from the frame after the button went down until it comes up; a "pressed" slot is 1 for the single frame it went down. The other slots ([1], [4], [9] to [0xb], [0xd], [0x13] to [0x29], [0x30] and up) are not written for a human and hold leftovers.
The input event#
The input event runs once per player per frame, after the
game has sampled the pad and filled the record and before it reads it, with ev.player and
ev.is_local. A handler that sets raw[3] = -raw[3] for the local player inverts the
steering before the game sees it. The held controls are applied after the handlers: the record fields
immediately after them, the four physics controls after the game's own write.
The event is per frame, not per physics step: every step of the frame drives off this one record (one step at
60 fps and above with the uncapped loop, more below that). Measured at 120 fps, the event ran once in every frame
of a whole race. It does not run while the game is paused, by the pause menu or by the window losing focus.
Before the green light the local record carries values no key made (a throttle of 1 and a steer moving in
sevenths during the countdown, as the record is quantised for the network), so a handler that wants the pad
should wait for race_start.
Example#
local inverted = false
ss.on("race_start", function() inverted = true end)
ss.on("race_end", function() inverted = false end)
ss.on("input", function(ev)
if inverted and ev.is_local then
local raw = ss.vehicles[ev.player].input.raw
raw[3] = -raw[3] -- inverted steering, before the game reads it
end
end)
ss.vehicles[1].input = { throttle = 0, brake = 1 } -- an AI car brakes to a stop
ss.after(3, function() ss.vehicles[1].input:clear() end)