# driveCams
Every camera a driving game needs, on one camera, switched with one word.
Put `DriveCam` on a camera, set `mode`, and press **C** (right-stick press or
d-pad up on a pad, the **CAM** button on a touch screen) to cycle the views.
| Mode | The view |
|---|---|
| `chase` | Behind the car at a distance sized to it, pulled in by walls; the field of view widens as it speeds up |
| `cockpit` | The driver's seat; the head moves with braking and cornering |
| `hood` | On the bonnet, low over the road |
| `bumper` | Low on the front bumper, the fastest-feeling view |
| `orbit` | Free orbit round the car (look control: right-drag, right stick, right-side drag on a phone) |
| `tv` | Trackside TV: the nearest trackside camera pans and zooms to keep the car framed and cuts to the next as it passes |
| `heli` | A broadcast helicopter hanging high above and behind, on a long lens |
| `rear` | Looking back from the tail |
## First example
Paste this into any world and enter play. It builds a drivable test car (a
box chassis on four WheelColliders, driven by the package's own `ShowcaseDriver`), a camera that follows it, and hands you
the wheel: drive with W A S D, press C to change view.
```lua
local Showcase = require("driveCams.showcase")
local car = Showcase.makeCar({ 0, 1.2, 0 }, { controlSource = "input" })
local cam = entity.spawn("driveCam")
cam.component.add("Camera", { fov = 62, priority = 10 })
cam.component.add("DriveCam", { mode = "chase", car = car })
-- or switch from code:
cam.component.get("DriveCam").mode = "cockpit"
```
On a player camera, add it to the player prototype's camera rig and leave
`car` empty: it films whatever the camera follows.
```lua
local rig = layers.active.camera.entity
rig.component.add("DriveCam", { mode = "chase" })
```
## DriveCam settings
| Setting | Default | What it does |
|---|---|---|
| `mode` | `chase` | The view (above). Switches live. |
| `car` | empty | The car to film. Empty keeps what the Camera follows (the local player's body on a player camera). |
| `cycleKey` | `true` | Step through the modes on the `cycleCamera` control. |
| `cycleModes` | `""` | The modes the control steps through, e.g. `"chase cockpit hood tv"`. Empty = all eight. |
| `speedFov` | `true` | Chase: widen the FOV with speed. |
| `fovBoost`, `fovSpeed` | `16`, `45` | Chase: degrees added at that speed (m/s). |
| `orbitSpin` | `0` | Orbit: degrees per second it turns by itself. |
| `inputMap` | `driveCams.cameraControls` | Where `cycleCamera` is read from. |
Methods: `dc:cycle(dir?)`, `dc:setMode(mode)`, `dc:info()` (mode, car,
behaviour, fov and the mount points in use).
## From code
```lua
local Cams = require("driveCams.cams")
Cams.modes() --> { "chase", "cockpit", "hood", "bumper", "orbit", "tv", "heli", "rear" }
Cams.set(cameraEntity, "tv", car) -- car optional
Cams.cycle(cameraEntity) --> "heli"
Cams.mounts(car) --> { seat, hood, bumper, rear, half, source }
```
`set` and `cycle` write a camera's `DriveCam` when it has one (so the choice
sticks) and otherwise switch its behaviour directly.
## Trackside TV points
`tv` uses, in order: every entity named **`TvCamPoint`** in the scene (place
them where a broadcaster would: outside corners, on a bank, over a jump), the
entities in `TvCam.points`, and points it places itself ahead of the car
along its path, alternating sides, when none is in range. It prefers points
the car is heading toward, cuts once the car has passed the current one, and
zooms so the car fills the same share of the picture near and far.
## Mount points
Cockpit, hood and bumper stand at the car's own values `car.mountSeat`,
`car.mountHood`, `car.mountBumper` (vectors in chassis-local metres, x right,
y up, z back: forward is -Z), as a car following `torqueCars.package/CONTRACT.md`
writes them. A car without them gets points worked out from `car.size`, else
its `BoxCollider`, else its bounds. Speed for the chase FOV is `car.speed`,
else `Physics.vehicleState`.
## How it moves
Chase, cockpit, hood, bumper and rear are the builtin
`@builtin::controller.chase` and `@builtin::controller.mount` rigs; orbit is
`@builtin::controller.orbital_follow`; tv and heli are this package's
`TvCam` and `HeliCam`, written on `@builtin::controller.camera_rig`. All of
them read where the car is drawn (`Physics.drawnPose`), so the car holds
steady on screen at any frame rate. A camera is per player, so nothing is
synced.
DriveCam names the car on the mount and orbit rigs' own `follow` field rather
than leaving them to read the Camera's `follow` slot. The builtin rigs look
that slot up by the short component name `Camera`, which finds nothing in a
world holding more than one version of the Camera component (installing
packages can lay such copies under `deps/`), and the cockpit view then stays
where it was placed while the car drives away. If you drive a builtin mount
rig yourself in such a world, set its `follow` too.
## Showcase
`showcase` (a scene) has a car lapping a cone-lined oval by itself, four TV
masts, a main camera (C cycles) and one camera per mode named
`DriveCam_<mode>` for side-by-side captures:
```lua
layers.load(asset.ref("driveCams.showcase", "scene"), { additive = true })
```
## What is inside
| Part | What it is |
|---|---|
| `DriveCam` (component) | The mode switch on a camera. |
| `TvCam` (component) | Trackside TV camera behaviour. |
| `HeliCam` (component) | Helicopter camera behaviour. |
| `ShowcaseDriver` (component) | Drives the test car: round an oval by itself, or from the player's controls. |
| `cams` (module) | `set` / `cycle` / `modes` / `mounts` and the per-mode tuning. |
| `showcase` (module) | `makeCar` (the test car) and `build` (the whole showcase). |
| `showcaseDrive` (input map) | The test car's driving controls on keyboard, gamepad and touch. |
| `cameraControls` (input map) | The `cycleCamera` control on keyboard, gamepad and touch. |
| `showcase` (scene) | The showcase, ready to load. |
## Known limits
- **Builtin rigs and the short name `Camera`** — the engine's mount and chase rigs find
their subject through the Camera's `follow` slot by the short component name, which
finds nothing in a world holding more than one version of the Camera component (as
installing packages can leave under `deps/`). DriveCam sets the mount and orbit rigs'
own `follow` to the car, so every mode keeps up; drive a builtin mount rig yourself and
set its `follow` too. Reported to the engine team.
- **The cabin is the body's inside** — cockpit sits in the torqueCars body seen from within
(dark trim, open glass, a steering wheel); there are no seats or instruments modelled, and
a deep dent pushes the panels into the view, as it would in the real car.
- **#20543** — wheels have no volume, so the bumper and hood cameras can pass into a wall
the body is pressed against for a moment in a crash.
- **#21241 / #21242** — DriveCam's `car` is a reference field and is not synced; a camera is
per player anyway, so each player's camera finds its own car (`player.vehicle`).
- **#20946** — measured on the native desktop engine only; the web build has not been run.
# driveCams.showcase
Test-drive builders. `makeCar(position, opts?)` builds a drivable test
car (box chassis, four WheelColliders worked by a `ShowcaseDriver`, a painted body
with cabin, roof, bumpers, headlights, tail lights and chrome rims) that also
states its camera mount points as `car.mountSeat` / `car.mountHood` /
`car.mountBumper`; `opts`: `name`, `paint = {r,g,b}`, `controlSource`
(`script` | `input`), `yaw`. `oval(origin)` answers the lap's points.
`build(origin?, opts?)` lays out the whole showcase: a lot, a cone-lined oval,
four `TvCamPoint` masts, a self-driving car and a `DriveCam` camera (plus one
camera per mode with `allModes`). The `showcase` scene calls `build`.