Entities
GameEntity is the entity base class, in sage-core. NodeEntity extends it in sage with a Babylon TransformNode. Both are abstract; a game subclasses one and declares a behavior tuple. The concepts behind them are on the Entities page.
import { GameEntity, NodeEntity } from '@skewedaspect/sage';GameEntity
Instance members
| Member | Type | Meaning |
|---|---|---|
id | string | The entity's ID |
name | string | The class-table key it was spawned or restored under |
state | object | The state bag. Narrow with hasBehavior, or re-declare on the subclass. |
ops | object | The operations. Same. |
eventSubscriptions | readonly EventSubscription[] | Every subscription its behaviors declared |
hasBehavior(Class) | this is NarrowedTo<Class> | True when an attached behavior is an instance of Class, counting subclasses. Narrows state and ops. |
getEntity(id) | GameEntity | undefined | Resolves another entity through the simulation context |
emit(type, payload, targetID?) | void | Queues an event with this entity as sender |
update(dt) | void | Runs each behavior's onUpdate in attachment order. Overridable. |
destroy() | void | Unsubscribes from the bus |
Two members are protected, reachable from the entity class's own code and nowhere else:
| Member | Meaning |
|---|---|
context | The GameSimulationContext the entity was created with: bus and getEntity |
attachedBehaviors() | A copy of the behavior instances, in attachment order |
attachedBehaviors is how an update() override runs a hook every behavior declares, which unique operation names keep out of ops.
Statics
| Static | Meaning |
|---|---|
behaviors | The behavior tuple, static override readonly behaviors = [ ... ] as const |
create(id, context, state?, name?) | Builds an entity and runs onCreate |
restore(id, context, state, name?) | Builds an entity from snapshot state, without onCreate |
The constructor is protected. simulation.spawn calls create; fromSnapshot calls restore. Both check the composition at construction and throw for a behavior that declares an operation with no method behind it, or two behaviors that expose the same operation name.
Overriding update
An entity class may override update() and order its work explicitly. super.update(dt) runs the default walk:
export class VehicleEntity extends NodeEntity
{
static override readonly behaviors = behaviors;
declare readonly state : StateFor<typeof behaviors>;
declare readonly ops : OpsFor<typeof behaviors>;
override update(dt : number) : void
{
super.update(dt);
this.ops.applyVelocity(dt);
}
}Here applyVelocity is an operation one of the vehicle's behaviors exposes, run after every behavior's onUpdate. An override that needs to run a hook every behavior declares, which unique operation names keep out of ops, walks this.attachedBehaviors() instead.
The simulation loop calls update() on every entity in insertion order and knows nothing else about what happens inside. An entity never calls another entity's update or destroy.
NodeEntity
Instance members
| Member | Type | Meaning |
|---|---|---|
node | TransformNode | The entity's node in the level's scene, never null |
mesh | AbstractMesh | undefined | The loaded mesh, undefined until it arrives and always for an adopted node |
audio | AudioManager | undefined | The game's audio manager, when it opted into one |
update() on a NodeEntity runs the behavior walk, then writes state.position and state.rotation onto the node. An adopted node is left alone.
destroy() runs every behavior's onDestroy, unsubscribes from the bus, then returns the node and mesh to the pool for a poolable class, disposes the node otherwise, or leaves an adopted node in place.
Statics
| Static | Default | Meaning |
|---|---|---|
poolable | false | Whether despawn returns the node and mesh set to the pool |
poolSize | undefined | The cap for this class's pool, in place of poolSizeLimit |
meshConfig | undefined | A MeshConfig for the standard mesh source. See Authoring. |
actions | undefined | The input actions this class's entities carry, as Action declarations |
NodeEntityState
Every NodeEntity carries these state fields whatever its behaviors declare:
interface NodeEntityState extends GameEntityState
{
tags : string[];
position : Vector3State;
rotation : QuaternionState;
parentID ?: string;
nodeName ?: string;
}| Field | Meaning |
|---|---|
tags | The entity's tags, an ordered list of unique strings |
position | { x, y, z }, written onto the node each fixed step. Defaults to the origin. |
rotation | { x, y, z, w }, written onto the node each fixed step. Defaults to no rotation, { x: 0, y: 0, z: 0, w: 1 }. |
parentID | The parent entity's ID. The node is parented under the parent's node. |
nodeName | The authored node this entity adopts. Written by a level, never by a game. |
A behavior that moves the entity declares position in its own slice and writes it there.
The hierarchy
A child names its parent in parentID at spawn:
const ship = simulation.spawn('ShipEntity');
const turret = simulation.spawn('TurretEntity', undefined, { parentID: ship.id });Node parenting follows the field, so Babylon composes world transforms. Restore parents the node from the same field. There is no update cascade.
Node behavior hooks
Behaviors on a NodeEntity may implement onMeshLoaded() and onDestroy(). NodeEntity recognizes each by name on whichever of its behaviors implements it. See Behaviors.
Composition types
All of these come from @skewedaspect/sage-core and are re-exported by @skewedaspect/sage except where noted.
| Type | Meaning |
|---|---|
GameEntityType | What a class table holds: a constructor with a behaviors tuple and a GameEntity prototype |
StateFor<Behaviors> | The composed state of a behavior tuple, tags included |
OpsFor<Behaviors> | The composed operations of a behavior tuple |
ComposedOf<Type> | An instance of an entity class with state and ops typed over its tuple. What create and restore return. |
NarrowedTo<Class> | A GameEntity narrowed to one behavior: deep read-only state, that behavior's operations. What hasBehavior narrows to. |
GameEntityState | { tags : string[] } |
StateBag, StateValue | The JSON-compatible state shapes |
OpsOf<Class> | One behavior's operations. Used as a Requires argument. sage-core only. |
StateSliceOf<Class> | One behavior's state slice. sage-core only. |
DeepReadonly<Value> | sage-core only |
ValidTuple<Behaviors> | The tuple when the composition checks, or an error type naming the problem. sage-core only. |
Vector3State and QuaternionState
interface Vector3State { x : number; y : number; z : number }
interface QuaternionState { x : number; y : number; z : number; w : number }toVec3Object, toVector3, toQuatObject, and toQuaternion convert between these and Babylon's own types.
