UiScreenOptions
Since 0.6
Screen-level options, carried in the root node's props.
Signature
export interface UiScreenOptions extends Record<string, unknown> {
/** The input context the screen asks the game to be in while it is up. */
inputContext?: string
/** Block the pointer from what is under it, even where it hits nothing. */
modal?: boolean
/** Whether Escape and the pad's B pop it. Default true. */
dismissible?: boolean
/** Answer no hit-test and take no focus unless a node opts in. What the HUD is. */
clickThrough?: boolean
/** Whether the screen wants a visible cursor. Default true. */
cursor?: boolean
/**
* Stop the world while the screen is on the stack: physics, behaviours' `update`, animation
* and `ctx.time` hold, while the UI, `onEvent` and `pausedUpdate` run on. Default false.
*/
pausesWorld?: boolean
}
Import: import type { UiScreenOptions } from "@argus/api"
Members
| Member | Signature | Description |
|---|---|---|
inputContext | inputContext?: string | The input context the screen asks the game to be in while it is up. |
modal | modal?: boolean | Block the pointer from what is under it, even where it hits nothing. |
dismissible | dismissible?: boolean | Whether Escape and the pad's B pop it. Default true. |
clickThrough | clickThrough?: boolean | Answer no hit-test and take no focus unless a node opts in. What the HUD is. |
cursor | cursor?: boolean | Whether the screen wants a visible cursor. Default true. |
pausesWorld | pausesWorld?: boolean | Stop the world while the screen is on the stack: physics, behaviours' update, animation and ctx.time hold, while the UI, onEvent and pausedUpdate run on. Default false. |
Example
The tested fixture fixtures/recipes/pause-screen/scenes/behaviors/pause-screen.ts.
import type { Behavior, Ctx } from "@argus/api"
/**
* A pause key that toggles a modal pause screen, with the world held under it.
*
* P, Escape or Start on a pad opens it; P, Escape or its Resume button closes it.
*
* The screen is declared `pausesWorld`, so while it is on the stack the engine runs no physics, no
* behaviour's `update` and no animation, and `ctx.time.now` stands still. Nothing here has to ask
* whether it is paused. What still runs is the UI, the Resume button's `ui-activated` (into the
* listener below) and `pausedUpdate`, which is where the key that closes the menu is read — `update`
* is not running to read it.
*/
interface State {
/** Seconds of play: `ctx.time.now`, which stops while the world is held. */
clock: number
paused: boolean
}
interface Props {
/** The entity this game spins, to show the freeze. Default `spinner`. */
spinner?: string
}
const PAUSE = "pause"
const isPaused = (ctx: Ctx<State, Props>): boolean => ctx.ui.stack().includes(PAUSE)
export default {
init(ctx) {
if (typeof ctx.state.clock !== "number") ctx.state.clock = 0
ctx.state.paused = isPaused(ctx)
ctx.events.on("ui-activated", (event) => {
if (event.data.screen === PAUSE && event.data.id === "resume" && isPaused(ctx)) ctx.ui.pop()
})
},
update(ctx) {
// `pause` is bound in both contexts: `gameplay` to open the screen, and `menu` — the context
// the screen switches to — to close it again with the same key, in `pausedUpdate`.
if (ctx.input !== null && ctx.input.pressed("pause") && !isPaused(ctx)) ctx.ui.push(PAUSE)
ctx.state.paused = false
ctx.state.clock = ctx.time.now
const spinner = ctx.world.find(ctx.props.spinner ?? "spinner")
if (spinner) {
const half = ctx.state.clock / 2
spinner.rotation = [0, Math.sin(half), 0, Math.cos(half)]
}
},
pausedUpdate(ctx) {
ctx.state.paused = true
if (ctx.input !== null && ctx.input.pressed("pause") && isPaused(ctx)) ctx.ui.pop()
},
} satisfies Behavior<State, Props>