ViewsHandle
Since 0.7
ctx.views: split screen for local multiplayer.
Views are numbered from 1, like players: view 1 is ctx.camera itself, and views 2 to 4 each have a camera rig of their own with exactly ctx.camera's set and follow. A view number outside 1..4 throws a ViewsError (views-out-of-range). The UI is drawn once over every view.
Signature
export interface ViewsHandle {
/** Splits the window. Throws `ViewsError` (`views-layout-unknown`) for a name that is not a {@link ViewLayout}. */
setLayout(layout: ViewLayout): void
/** The layout in force: `"single"` until one is set. */
readonly layout: ViewLayout
/** How many views the layout has. */
readonly count: number
/** Where view `view` is in the window; `null` when the layout has no such view. */
rect(view: number): ViewRect | null
/** `ctx.camera.set` for view `view`. */
set(view: number, kind: CameraKind, params?: CameraParams): void
/** `ctx.camera.follow` for view `view`. */
follow(view: number, target: EntityHandle | string | null): void
/**
* A camera that keeps every one of `targets` in view: at their centre, from `yaw`/`pitch`, pulled
* back (and with `maxFov`, widened) to fit them all, eased on game time. For several players on one
* shared screen: `ctx.views.frame(1, players)`. An empty list, `set` or `follow` ends it.
*/
frame(view: number, targets: (EntityHandle | string)[], params?: FrameParams): void
/**
* One camera for players sharing a screen that splits when they spread out. View 1 frames every
* target (as {@link ViewsHandle.frame}); once their spread is beyond `split.beyond` for `split.hold`
* seconds the window splits into one view per live target, in the order given (two to four), each
* framing its own target from the same direction, and it merges back once the spread is under
* `split.back` for as long. Each switch raises `views-split` ({@link ViewsSplitEvent})
* or `views-merged` ({@link ViewsMergedEvent}). The same call again changes nothing; a different one
* starts shared. `setLayout`, `frame(1, …)` or `ctx.camera.set`/`follow` end it where it stands;
* `shared([])` ends it and goes back to one view. Throws `ViewsError` (`views-layout-unknown`) for a
* `split.layout` that is not `"auto"`, `"left-right"` or `"top-bottom"`.
*/
shared(targets: (EntityHandle | string)[], params?: SharedParams): void
/** View `view`'s rig yaw now, radians (`ctx.camera.yaw` per view). */
yaw(view: number): number
/** View `view`'s rig pitch now, radians. */
pitch(view: number): number
/**
* The heading view `view` is drawn from, radians about +Y with 0 facing -Z, as of the top of the tick:
* the frame that view's player reads a camera-relative stick in (`ctx.camera.viewYaw` per view). 0 for
* a view the layout does not have.
*/
viewYaw(view: number): number
/** The vertical field of view view `view` is drawn at, degrees (`ctx.camera.fov` per view). */
fov(view: number): number
}
Import: import type { ViewsHandle } from "@argus/api"
Members
| Member | Signature | Description |
|---|---|---|
setLayout | setLayout(layout: ViewLayout): void | Splits the window. Throws ViewsError (views-layout-unknown) for a name that is not a {@link ViewLayout}. |
layout | readonly layout: ViewLayout | The layout in force: "single" until one is set. |
count | readonly count: number | How many views the layout has. |
rect | rect(view: number): ViewRect | null | Where view view is in the window; null when the layout has no such view. |
set | set(view: number, kind: CameraKind, params?: CameraParams): void | ctx.camera.set for view view. |
follow | follow(view: number, target: EntityHandle | string | null): void | ctx.camera.follow for view view. |
frame | frame(view: number, targets: (EntityHandle | string)[], params?: FrameParams): void | A camera that keeps every one of targets in view: at their centre, from yaw/pitch, pulled back (and with maxFov, widened) to fit them all, eased on game time. For several players on one shared screen: ctx.views.frame(1, players). An empty list, set or follow ends it. |
shared | shared(targets: (EntityHandle | string)[], params?: SharedParams): void | One camera for players sharing a screen that splits when they spread out. View 1 frames every target (as {@link ViewsHandle.frame}); once their spread is beyond split.beyond for split.hold seconds the window splits into one view per live target, in the order given (two to four), each framing its own target from the same direction, and it merges back once the spread is under split.back for as long. Each switch raises views-split ({@link ViewsSplitEvent}) or views-merged ({@link ViewsMergedEvent}). The same call again changes nothing; a different one starts shared. setLayout, frame(1, …) or ctx.camera.set/follow end it where it stands; shared([]) ends it and goes back to one view. Throws ViewsError (views-layout-unknown) for a split.layout that is not "auto", "left-right" or "top-bottom". |
yaw | yaw(view: number): number | View view's rig yaw now, radians (ctx.camera.yaw per view). |
pitch | pitch(view: number): number | View view's rig pitch now, radians. |
viewYaw | viewYaw(view: number): number | The heading view view is drawn from, radians about +Y with 0 facing -Z, as of the top of the tick: the frame that view's player reads a camera-relative stick in (ctx.camera.viewYaw per view). 0 for a view the layout does not have. |
fov | fov(view: number): number | The vertical field of view view view is drawn at, degrees (ctx.camera.fov per view). |
Example
The tested fixture fixtures/app/agent.ts.
import type { Behavior } from "@argus/api"
// Sends a nav agent to `props.target` once, then reports arrival through ctx.state so the
// test can read it without polling the crowd directly.
export default {
init(ctx) {
ctx.state.arrived = false
ctx.nav?.goTo(ctx.props.target as [number, number, number])
},
update(ctx) {
if (ctx.nav?.arrived) ctx.state.arrived = true
},
} satisfies Behavior