meat/engine/scene/Actor.ts

48 lines
1.7 KiB
TypeScript

import type { RenderPrototype, RenderTransform } from "../render/RenderScene"
import type { Collider } from "../world/Collider"
/** Open actor behavior and representation. Concrete definitions are ordinary game
* objects referenced directly by instances. */
export type ActorDefinition<State, World> = {
prototype: RenderPrototype
update: (state: State, dt: number, world: World) => void
transform: (state: State) => RenderTransform
collider?: (state: State, world: World) => Collider | null
}
/** Type-erased live actor. `create` captures concrete state safely, allowing one
* level to hold unrelated actor state types without a content union. */
export type Actor<World> = {
readonly definition: object
readonly prototype: RenderPrototype
readonly updateState: (dt: number, world: World) => void
readonly readTransform: () => RenderTransform
readonly readCollider: (world: World) => Collider | null
}
export namespace Actor {
export function create<State, World>(
definition: ActorDefinition<State, World>,
state: State,
): Actor<World> {
return {
definition,
prototype: definition.prototype,
updateState: (dt, world) => definition.update(state, dt, world),
readTransform: () => definition.transform(state),
readCollider: (world) => definition.collider?.(state, world) ?? null,
}
}
export function update<World>(actor: Actor<World>, dt: number, world: World): void {
actor.updateState(dt, world)
}
export function transform<World>(actor: Actor<World>): RenderTransform {
return actor.readTransform()
}
export function collider<World>(actor: Actor<World>, world: World): Collider | null {
return actor.readCollider(world)
}
}