# Behaviour

> Talos 0.6 · Since 0.6

The base of a behaviour written as a class.

`P` is the shape of its props (the script component's `props`); the fields a class declares take props of the same name. `ts import { Behaviour, turnTowards, yawTo } from "@argus/gameplay" import type { EntityHandle } from "@argus/api" export default class Turret extends Behaviour { turnRate = 2 // rad/s; props.turnRate overrides it target: EntityHandle | null = null Start() { this.target = this.world.find("player") } Update(dt: number) { if (this.target) this.entity.yaw = turnTowards(this.entity.yaw, yawTo(this.entity, this.target), this.turnRate * dt) } OnTriggerEnter(other: EntityHandle) { if (other.hasTag("player")) this.events.emit("spotted") } } ```

## Signature

```ts
export class Behaviour<P extends Record<string, any> = Record<string, any>> {
  constructor()
  Start?(): void
  Update?(dt: number): void
  OnPausedUpdate?(dt: number): void
  OnEnable?(): void
  OnDisable?(): void
  OnDestroy?(): void
  OnTriggerEnter?(other: EntityHandle): void
  OnTriggerExit?(other: EntityHandle): void
  OnCollisionEnter?(collision: Collision): void
  OnEvent?(event: GameEvent): void
  declare Awake?: "Awake is never called: use a field initialiser, or Start()"
  declare FixedUpdate?: "FixedUpdate is never called: Update(dt) runs every fixed 60 Hz tick, which is the fixed-step update other engines call FixedUpdate"
  declare LateUpdate?: "LateUpdate is never called: there is one fixed tick; do it in Update(dt)"
  declare OnTriggerStay?: "OnTriggerStay is never called: use OnTriggerEnter/OnTriggerExit and a field"
  declare OnCollisionStay?: "OnCollisionStay is never called: contacts report their start (OnCollisionEnter); keep a field"
  declare OnCollisionExit?: "OnCollisionExit is never called: contacts report their start (OnCollisionEnter); keep a field"
  declare update?: "a Behaviour class's hooks use the usual names: Update(dt), Start(), OnDestroy()"
  declare init?: "a Behaviour class's hooks use the usual names: Start(), or a field initialiser"
  get ctx(): Ctx<Record<string, any>, P>
  get entity(): EntityHandle
  get world(): WorldQuery
  get body(): RigidBody | null
  get controller(): Controller | null
  get input(): InputState | null
  get animator(): Animator | null
  get nav(): NavAgent | null
  get events(): EventBus
  get time(): TimeInfo
  get camera(): CameraHandle
  get audio(): AudioHandle
  get particles(): ParticlesHandle
  get labels(): LabelsHandle
  get render(): RenderHandle
  get ui(): UiHandle
  get hud(): HudHandle
  get session(): SessionHandle
  get save(): SaveHandle
  get files(): FilesHandle
  get props(): Readonly<P>
  log(message: string, data?: unknown): void
  get enabled(): boolean
  set enabled(on: boolean)
  static init(this: new () => Behaviour<any>, ctx: Ctx): void
  static update(ctx: Ctx, dt: number): void
  static pausedUpdate(ctx: Ctx, dt: number): void
  static dispose(ctx: Ctx, reason?: "detach" | "reload"): void
  static onTriggerEnter(ctx: Ctx, other: EntityHandle): void
  static onTriggerExit(ctx: Ctx, other: EntityHandle): void
  static onCollision(ctx: Ctx, collision: Collision): void
  static onEvent(ctx: Ctx, event: GameEvent): void
}
```

Import: `import { Behaviour } from "@argus/gameplay"`

## Members

| Member | Signature | Description |
|---|---|---|
| `constructor` | `constructor()` |  |
| `Start` | `Start?(): void` | Once, at the top of the first tick after the behaviour attached (after every field initialiser). |
| `Update` | `Update?(dt: number): void` | Every fixed 60 Hz tick while enabled — the fixed-step update (`FixedUpdate` in some engines); `dt` is 1/60 s. |
| `OnPausedUpdate` | `OnPausedUpdate?(dt: number): void` | Every tick while the world is held (a pause menu, `ctx.session.pause()`), in place of `Update`. |
| `OnEnable` | `OnEnable?(): void` | When the behaviour attaches or is re-enabled, and after a hot reload. |
| `OnDisable` | `OnDisable?(): void` | When it is disabled, detached, or about to be hot-reloaded. |
| `OnDestroy` | `OnDestroy?(): void` | When the entity (or the scene) is going. Not for a hot reload. |
| `OnTriggerEnter` | `OnTriggerEnter?(other: EntityHandle): void` | Something entered a trigger this entity takes part in; `other` is the other participant. |
| `OnTriggerExit` | `OnTriggerExit?(other: EntityHandle): void` | The other participant left. |
| `OnCollisionEnter` | `OnCollisionEnter?(collision: Collision): void` | A contact started. |
| `OnEvent` | `OnEvent?(event: GameEvent): void` | Any `emit`, from any behaviour or the app. |
| `Awake` | `declare Awake?: "Awake is never called: use a field initialiser, or Start()"` | Names Behaviour never calls: declared so that writing one is a type error whose message is the fix. |
| `FixedUpdate` | `declare FixedUpdate?: "FixedUpdate is never called: Update(dt) runs every fixed 60 Hz tick, which is the fixed-step update other engines call FixedUpdate"` |  |
| `LateUpdate` | `declare LateUpdate?: "LateUpdate is never called: there is one fixed tick; do it in Update(dt)"` |  |
| `OnTriggerStay` | `declare OnTriggerStay?: "OnTriggerStay is never called: use OnTriggerEnter/OnTriggerExit and a field"` |  |
| `OnCollisionStay` | `declare OnCollisionStay?: "OnCollisionStay is never called: contacts report their start (OnCollisionEnter); keep a field"` |  |
| `OnCollisionExit` | `declare OnCollisionExit?: "OnCollisionExit is never called: contacts report their start (OnCollisionEnter); keep a field"` |  |
| `update` | `declare update?: "a Behaviour class's hooks use the usual names: Update(dt), Start(), OnDestroy()" · static update(ctx: Ctx, dt: number): void` |  |
| `init` | `declare init?: "a Behaviour class's hooks use the usual names: Start(), or a field initialiser" · static init(this: new () => Behaviour<any>, ctx: Ctx): void` |  |
| `ctx` | `get ctx(): Ctx<Record<string, any>, P>` | The whole Argus ctx, for what has no handle here. |
| `entity` | `get entity(): EntityHandle` | This entity. Space is Argus's: `position` (local), `worldPosition`, `yaw` (radians), `forward` (-Z). |
| `world` | `get world(): WorldQuery` |  |
| `body` | `get body(): RigidBody \| null` |  |
| `controller` | `get controller(): Controller \| null` |  |
| `input` | `get input(): InputState \| null` |  |
| `animator` | `get animator(): Animator \| null` |  |
| `nav` | `get nav(): NavAgent \| null` |  |
| `events` | `get events(): EventBus` |  |
| `time` | `get time(): TimeInfo` |  |
| `camera` | `get camera(): CameraHandle` |  |
| `audio` | `get audio(): AudioHandle` |  |
| `particles` | `get particles(): ParticlesHandle` |  |
| `labels` | `get labels(): LabelsHandle` |  |
| `render` | `get render(): RenderHandle` | `ctx.render`: shader parameter writes (`setShaderParam`, `setMaterialParam`). |
| `ui` | `get ui(): UiHandle` |  |
| `hud` | `get hud(): HudHandle` |  |
| `session` | `get session(): SessionHandle` |  |
| `save` | `get save(): SaveHandle` |  |
| `files` | `get files(): FilesHandle` | The project's files under `data/`, read-only (`ctx.files`). |
| `props` | `get props(): Readonly<P>` | The script component's props, read-only (fields of the same name already hold them). |
| `log` | `log(message: string, data?: unknown): void` | A structured log line. |
| `enabled` | `get enabled(): boolean · set enabled(on: boolean)` | Whether `Update` runs. Setting it runs `OnEnable` / `OnDisable`, as in other engines. |
| `pausedUpdate` | `static pausedUpdate(ctx: Ctx, dt: number): void` |  |
| `dispose` | `static dispose(ctx: Ctx, reason?: "detach" \| "reload"): void` |  |
| `onTriggerEnter` | `static onTriggerEnter(ctx: Ctx, other: EntityHandle): void` |  |
| `onTriggerExit` | `static onTriggerExit(ctx: Ctx, other: EntityHandle): void` |  |
| `onCollision` | `static onCollision(ctx: Ctx, collision: Collision): void` |  |
| `onEvent` | `static onEvent(ctx: Ctx, event: GameEvent): void` |  |
