Skip to content

Vehicles & Stations

A Station is a seat a player rides. Turn on isDriver and the player's movement input becomes vehicle controls while they're seated — read them with the Station.* API and move the vehicle however you like.

Put your script on the vehicle (the same object your SSStation sits on or under — usually an SSPlatform). While a player is in the driver seat, Station.* returns their input; when the seat is empty it returns zero and Station.HasDriver() is false.

No script needed to start — the basic controller

To just get a vehicle moving (and verify your seat + input work), drop SSVehicleController (Social Scape/Vehicle Controller (basic)) on the vehicle body, pick Car or Aircraft, and tune the speeds in the Inspector. It reads the driver's input and moves the object — a starter you can drive immediately, in the editor test player too. Add richer things (wheel colliders, engine sound, exhaust, driving animations, real flight physics) yourself, either by scripting with the Station.* API below or driving your own components.

It moves only when the local player is in its driver seat (the SSPlatform replicates the motion to everyone else).

Field What it does
Kind Car or Aircraft — picks the whole control scheme.
Boost Doubles Hold Shift for 2× speed.
Set Seat Look Mode Auto-picks the driver seat's look mode: AircraftFree Look + hold RMB, CarFree Look. Turn it off to set the seat's lookMode yourself.
Forward Axis / Up Axis LocalAxis dropdowns so the controller matches your model's facing (see the tip above).

Car fields:

Field Default
Speed 8 m/s
Turn Rate 90 deg/s
Reverse Factor 0.5

Aircraft fields:

Field Default
Thrust 15 m/s
Pitch Rate 60 deg/s
Yaw Rate 45 deg/s
Roll Rate 90 deg/s
Lift Rate 8 m/s

Driving backward or sideways?

Your model isn't built facing +Z (Unity's blue arrow). Set the Forward Axis dropdown to match how your model faces — e.g. −Z for a ship modelled facing backward — and, for aircraft, the Up Axis too. No need to re‑rotate the mesh.

The API

Testing: Station.* works in the editor test player (sit in a driver seat and it reads your input) and live — so you can build and test a scripted vehicle without deploying.

Enough axes for anything from a car to a 6‑DOF spaceship — read the ones your craft needs. Every axis is −1…1.

Named axes (the common case):

Call Default input For
Station.GetThrottle() W/S · left‑stick Y forward / back
Station.GetSteer() A/D · left‑stick X ground turn (or roll on a plane)
Station.GetPitch() mouse Y · right‑stick Y nose up / down
Station.GetYaw() mouse X · right‑stick X nose left / right
Station.GetRoll() Q / E bank
Station.GetLift() Space / Ctrl up / down thrust (heli, spaceship)

Buttons: Station.GetButton("boost") (Shift), "brake" (Space), "fire1" (left‑click / VR right trigger), "fire2" (right‑click / VR left trigger). Station.HasDriver() tells you if anyone's aboard.

Raw axes (if you'd rather map inputs yourself): Station.GetMoveX() / GetMoveY() (WASD / left‑stick) and Station.GetLookX() / GetLookY() (mouse / right‑stick). The named axes are just friendly aliases over these — e.g. GetPitch() is GetLookY().

For any other discrete control (a third weapon, landing gear, headlights) add a World Trigger On key entry, bind whatever key/button you like, and run a script — it fires normally while the player drives.

Example — a simple car

Script on the car (with a driver SSStation on it):

float speed = 8.0;        // metres/second at full throttle
float turnRate = 90.0;    // degrees/second at full steer

void Update()
{
    if (!Station.HasDriver()) return;    // nobody driving → don't move

    float throttle = Station.GetThrottle();
    float steer = Station.GetSteer();
    if (Station.GetButton("boost")) throttle = throttle * 2.0;

    // Turn, then drive forward along the new facing.
    transform.Rotate(0, steer * turnRate * Time.deltaTime, 0);
    Vector3 forward = transform.forward;
    transform.position = transform.position + forward * (throttle * speed * Time.deltaTime);
}

The vehicle's position syncs to everyone automatically (it's a networked world object) — you only script the driver's side; passengers and onlookers just see it move.

Example — an aircraft / spaceship

Pitch/yaw come from the mouse (see the look modes below — by default you look around and hold right‑mouse to steer), roll from Q/E, throttle from W/S, and lift from Space/Ctrl. Fire on left‑click:

float thrust = 15.0;
float pitchRate = 60.0, yawRate = 45.0, rollRate = 90.0, liftRate = 8.0;

void Update()
{
    if (!Station.HasDriver()) return;

    // Rotate the craft from the aim + roll axes (local space).
    transform.Rotate(-Station.GetPitch() * pitchRate * Time.deltaTime,
                      Station.GetYaw()   * yawRate   * Time.deltaTime,
                     -Station.GetRoll()  * rollRate  * Time.deltaTime);

    // Move: forward thrust + vertical lift (great for a spaceship or helicopter).
    Vector3 move = transform.forward * (Station.GetThrottle() * thrust)
                 + transform.up      * (Station.GetLift()     * liftRate);
    transform.position = transform.position + move * Time.deltaTime;

    if (Station.GetButton("fire1")) FireWeapon();   // your own action (spawn a projectile, etc.)
}

Use as many or as few axes as your craft needs — a boat reads throttle + steer, a plane adds pitch/yaw/roll, a free‑flying spaceship uses lift too.

Looking around vs. flying

The camera is first‑person, and the seat's lookMode decides what the desktop mouse does:

  • Free Look — the mouse looks around (within the seat's freeLookYawLimit / freeLookPitchLimit cone). Best for cars, boats and passengers. GetPitch() / GetYaw() stay 0, so steer with the other axes (A/D, Q/E, …).
  • Vehicle Control — the mouse flies the craft, so GetPitch() / GetYaw() carry the mouse and the view faces forward. The mouse always steers.
  • Free Look + hold RMB to steer — look around freely, and hold the right mouse button to steer with the mouse (GetPitch() / GetYaw() carry the mouse only while RMB is held; the view freezes so you aim, then release to look around again). This is the natural way to fly — glance around the cockpit, hold to bank into a turn — so it's the default the basic SSVehicleController picks for Aircraft.

In VR the head always free‑looks (the headset owns it — that's how VR should feel), so lookMode doesn't restrict the view; a VR pilot flies with the right stick, which always feeds pitch/yaw. So write your flight script the same way — the right stick drives GetPitch/GetYaw for VR players while the mouse does it for desktop players (always in Vehicle Control, on held RMB in Free‑Look‑steer‑on‑hold).

RMB in steer‑on‑hold mode

In Free Look + hold RMB to steer, the right mouse button is used to steer, so Station.GetButton("fire2") (right‑click) isn't available in that mode — use "fire1" (left‑click) for weapons.

VR controls

You write the same Station.* calls — the platform maps VR controllers to the same axes so your script doesn't care whether the driver is on desktop or in a headset. The default VR map:

Axis / button VR control
GetThrottle() / GetSteer() Left stick (↑↓ throttle, ←→ steer)
GetPitch() / GetYaw() Right stick (the head still free‑looks independently)
GetLift() — ascend / descend A (right) = up, X (left) = down
GetRoll() — bank click the stick you bank toward (L3 left, R3 right)
GetButton("boost") / "brake" Right grip / Left grip
GetButton("fire1") / "fire2" Right trigger / Left trigger
exit the seat B or Y

The head always free‑looks in VR (the headset owns it — that's how VR should feel), so lookMode never restricts the view; the right stick flies while your head looks around freely. That's why the desktop hold‑RMB scheme has no VR equivalent — VR already gives you look and steer at once.

Rebinding the controls

Don't like the defaults? On the SSStation, open Controls (rebindable) and add an entry per control you want to change — pick the control, set your bindings, done. Anything you don't list keeps its default (the WASD / Space / Shift / trigger + VR maps above). Your script and the Station.* API are unchanged — you're only changing what drives each axis:

Control Type — bind…
Move a 2D Vector (up/down → throttle, left/right → steer)
Roll, Lift a 1D axis (negative / positive)
Boost, Brake, Fire1, Fire2, Exit a button

Each entry is one action, so add both a desktop and a VR binding to it and either drives the control (e.g. bind Move to the arrow keys and the right thumbstick). Use the same binding picker as everywhere else (<Keyboard>/upArrow, <Gamepad>/leftStick, <XRController>{RightHand}/thumbstick, …).

What's rebindable

The eight driver controls above. Look/aim (pitch/yaw) isn't in the list — it's the seat's camera system (Free Look / Vehicle Control / hold‑RMB), configured with lookMode just above. These bindings are local to each player — you're setting the defaults your vehicle ships with; per‑player remapping is a separate player setting.

Locking the seat

Turn on lockExit on the SSStation and the built‑in exit input does nothing — the player can't leave on their own. This is the locked station: you decide when they get out. Unseat them from your own logic:

// e.g. a "door closed" state, an eject button, or the end of a cutscene:
if (readyToDropOff) Station.Exit();     // stands the local player up from the seat they're in (no‑op if not seated)

Or, with no script, add an Exit Seat (local player) action to any World Trigger / interactable — a zone they walk into, a lever, a button — and it unseats whoever triggered it.

Players are never truly stuck

A locked seat only disables the seat's exit input. A player can always get out by respawning, rejoining, or leaving the world — so locking is safe to use, it just means normal exit runs on your terms.

Feeding a no‑code vehicle instead

Don't want to script? On the SSStation, set Driver input → no‑code's vehicleVariables to a World Trigger object and it writes the live throttle and steer into that object's variables every frame — react to them with On variable changed entries and operations.

Where the script runs

You can write the vehicle client‑authoritative (the script runs on the driver's own machine — lowest latency) or server‑authoritative (the script runs on the server — consistent and cheat‑resistant). You write the same Station.* calls either way; SocialScape routes the input to wherever your script runs. Client‑authoritative is the simplest place to start.


Component class names (for scripts and search): SSStation, SSStationInput, SSVehicleController.