@donut-games/engine 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/core/index.d.ts +6 -0
- package/dist/core/index.js +1158 -0
- package/dist/core/index.js.map +1 -0
- package/dist/ctrllr/index.d.ts +1 -0
- package/dist/ctrllr/index.js +302 -0
- package/dist/ctrllr/index.js.map +1 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1158 -0
- package/dist/index.js.map +1 -0
- package/dist/math/index.d.ts +1 -0
- package/dist/math/index.js +708 -0
- package/dist/math/index.js.map +1 -0
- package/dist/pixi/index.d.ts +1 -0
- package/dist/pixi/index.js +967 -0
- package/dist/pixi/index.js.map +1 -0
- package/dist/player/index.d.ts +1 -0
- package/dist/player/index.js +2193 -0
- package/dist/player/index.js.map +1 -0
- package/dist/three/index.d.ts +1 -0
- package/dist/three/index.js +6 -0
- package/dist/three/index.js.map +1 -0
- package/package.json +74 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../core/src/event-emitter.ts","../../../core/src/component.ts","../../../core/src/entity.ts","../../../core/src/observable.ts","../../../core/src/query.ts","../../../core/src/query-manager.ts","../../../core/src/system.ts","../../../core/src/system-manager.ts","../../../core/src/entity-manager.ts","../../../core/src/world.ts","../../../math/src/vector3.ts","../../../math/src/quaternion.ts","../../../core/src/transform-component.ts","../../../core/src/motion-component.ts","../../../core/src/motion-system.ts"],"names":["SystemType"],"mappings":"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","file":"index.js","sourcesContent":["/**\n * Represents a subscription to an event that can be unsubscribed.\n */\nexport interface Subscription {\n /** Removes the event handler associated with this subscription. */\n unsubscribe(): void;\n}\n\n/**\n * A typed event emitter that supports on, off, once, and emit operations.\n */\nexport class EventEmitter {\n /** Map of event names to their registered handler functions. */\n private handlerMap: Map<string, Set<Function>> = new Map();\n\n /**\n * Registers a handler for the specified event.\n * @param eventName - The name of the event to listen for.\n * @param handler - The function to call when the event is emitted.\n * @returns A subscription that can be used to unsubscribe.\n */\n on(eventName: string, handler: Function): Subscription {\n if (!this.handlerMap.has(eventName)) {\n this.handlerMap.set(eventName, new Set());\n }\n this.handlerMap.get(eventName)!.add(handler);\n return {\n unsubscribe: () => {\n this.off(eventName, handler);\n },\n };\n }\n\n /**\n * Removes a previously registered handler for the specified event.\n * @param eventName - The name of the event.\n * @param handler - The handler function to remove.\n */\n off(eventName: string, handler: Function): void {\n const handlers = this.handlerMap.get(eventName);\n if (handlers) {\n handlers.delete(handler);\n if (handlers.size === 0) {\n this.handlerMap.delete(eventName);\n }\n }\n }\n\n /**\n * Registers a handler that will be called at most once for the specified event.\n * @param eventName - The name of the event to listen for.\n * @param handler - The function to call when the event is emitted.\n * @returns A subscription that can be used to unsubscribe.\n */\n once(eventName: string, handler: Function): Subscription {\n const wrappedHandler = (...arguments_: unknown[]) => {\n this.off(eventName, wrappedHandler);\n handler(...arguments_);\n };\n return this.on(eventName, wrappedHandler);\n }\n\n /**\n * Emits an event, calling all registered handlers with the provided arguments.\n * @param eventName - The name of the event to emit.\n * @param arguments_ - Arguments to pass to the event handlers.\n */\n emit(eventName: string, ...arguments_: unknown[]): void {\n const handlers = this.handlerMap.get(eventName);\n if (handlers) {\n for (const handler of [...handlers]) {\n handler(...arguments_);\n }\n }\n }\n}\n","import type { Entity } from './entity.js';\n\n/**\n * Constructor type for Component subclasses, used for type-safe component lookups.\n */\nexport type ComponentConstructor<TComponent extends Component = Component> = new (...args: unknown[]) => TComponent;\n\n/**\n * Abstract base class for all components in the ECS.\n * Components hold state and optional lifecycle hooks.\n */\nexport abstract class Component {\n /** The entity that owns this component, if any. */\n owner?: Entity;\n\n /** Optional list of component types that must be present on the entity. */\n dependencies?: ComponentConstructor[];\n\n /**\n * Called when this component is added to an entity.\n * @param owner - The entity this component was added to.\n */\n onAdd?(owner: Entity): void;\n\n /**\n * Called when this component is removed from an entity.\n * @param previousOwner - The entity this component was removed from.\n */\n onRemove?(previousOwner: Entity): void;\n\n /** Creates a deep copy of this component. */\n abstract clone(): Component;\n\n /**\n * Serializes this component's state to a plain object.\n * @returns A record of serializable key-value pairs.\n */\n serialize(): Record<string, unknown> {\n return {};\n }\n\n /**\n * Restores this component's state from a serialized object.\n * @param _data - The serialized data to restore from.\n */\n deserialize(_data: Record<string, unknown>): void {\n // no-op by default\n }\n}\n","import { EventEmitter, type Subscription } from './event-emitter.js';\nimport type { Component, ComponentConstructor } from './component.js';\n\n/**\n * Configuration options for creating a new Entity.\n */\nexport interface EntityOptions {\n /** The display name of the entity. */\n name?: string;\n}\n\n/**\n * An entity is a container for components with an event system and hierarchical relationships.\n */\nexport class Entity {\n /** Auto-incrementing counter for unique entity identifiers. */\n private static nextIdentifier = 1;\n\n /** The unique numeric identifier for this entity. */\n readonly identifier: number;\n\n /** The display name of this entity. */\n name: string;\n\n /** Map of component constructors to component instances for O(1) lookup. */\n private componentMap: Map<ComponentConstructor, Component> = new Map();\n\n /** Set of tags associated with this entity. */\n private tagSet: Set<string> = new Set();\n\n /** Whether this entity is active and should be processed by systems. */\n isActive: boolean = true;\n\n /** The parent entity in the hierarchy, if any. */\n parent?: Entity;\n\n /** Child entities in the hierarchy. */\n children: Entity[] = [];\n\n /** Internal event emitter for composition-based event delegation. */\n private eventEmitter: EventEmitter = new EventEmitter();\n\n constructor(options?: EntityOptions) {\n this.identifier = Entity.nextIdentifier++;\n this.name = options?.name ?? `Entity${this.identifier}`;\n }\n\n /**\n * Registers a handler for the specified event.\n * @param eventName - The name of the event to listen for.\n * @param handler - The function to call when the event is emitted.\n * @returns A subscription that can be used to unsubscribe.\n */\n on(eventName: string, handler: Function): Subscription {\n return this.eventEmitter.on(eventName, handler);\n }\n\n /**\n * Removes a previously registered handler for the specified event.\n * @param eventName - The name of the event.\n * @param handler - The handler function to remove.\n */\n off(eventName: string, handler: Function): void {\n this.eventEmitter.off(eventName, handler);\n }\n\n /**\n * Registers a handler that will be called at most once for the specified event.\n * @param eventName - The name of the event to listen for.\n * @param handler - The function to call when the event is emitted.\n * @returns A subscription that can be used to unsubscribe.\n */\n once(eventName: string, handler: Function): Subscription {\n return this.eventEmitter.once(eventName, handler);\n }\n\n /**\n * Emits an event, calling all registered handlers with the provided arguments.\n * @param eventName - The name of the event to emit.\n * @param arguments_ - Arguments to pass to the event handlers.\n */\n emit(eventName: string, ...arguments_: unknown[]): void {\n this.eventEmitter.emit(eventName, ...arguments_);\n }\n\n /**\n * Adds a component to this entity.\n * Sets the component's owner, calls its onAdd hook, and emits 'componentadded'.\n * @param component - The component instance to add.\n * @returns The added component for chaining.\n */\n addComponent<TComponent extends Component>(component: TComponent): TComponent {\n const constructor = component.constructor as ComponentConstructor;\n component.owner = this;\n this.componentMap.set(constructor, component);\n if (component.onAdd) {\n component.onAdd(this);\n }\n this.emit('componentadded', component);\n return component;\n }\n\n /**\n * Removes a component of the specified type from this entity.\n * Calls the component's onRemove hook and emits 'componentremoved'.\n * @param componentType - The constructor of the component type to remove.\n * @param _force - Reserved for future use.\n */\n removeComponent<TComponent extends Component>(componentType: ComponentConstructor<TComponent>, _force?: boolean): void {\n const component = this.componentMap.get(componentType);\n if (component) {\n this.componentMap.delete(componentType);\n if (component.onRemove) {\n component.onRemove(this);\n }\n component.owner = undefined;\n this.emit('componentremoved', component);\n }\n }\n\n /**\n * Retrieves a component of the specified type from this entity.\n * @param componentType - The constructor of the component type to retrieve.\n * @returns The component instance, or undefined if not found.\n */\n get<TComponent extends Component>(componentType: ComponentConstructor<TComponent>): TComponent | undefined {\n return this.componentMap.get(componentType) as TComponent | undefined;\n }\n\n /**\n * Checks whether this entity has a component of the specified type.\n * @param componentType - The constructor of the component type to check for.\n * @returns True if the component is present.\n */\n has(componentType: ComponentConstructor): boolean {\n return this.componentMap.has(componentType);\n }\n\n /**\n * Adds a tag to this entity.\n * @param tag - The tag string to add.\n */\n addTag(tag: string): void {\n this.tagSet.add(tag);\n this.emit('tagadded', tag);\n }\n\n /**\n * Checks whether this entity has the specified tag.\n * @param tag - The tag string to check for.\n * @returns True if the tag is present.\n */\n hasTag(tag: string): boolean {\n return this.tagSet.has(tag);\n }\n\n /**\n * Removes a tag from this entity.\n * @param tag - The tag string to remove.\n */\n removeTag(tag: string): void {\n this.tagSet.delete(tag);\n this.emit('tagremoved', tag);\n }\n\n /**\n * Adds a child entity to this entity's hierarchy.\n * @param entity - The child entity to add.\n */\n addChild(entity: Entity): void {\n entity.parent = this;\n this.children.push(entity);\n }\n\n /**\n * Removes a child entity from this entity's hierarchy.\n * @param entity - The child entity to remove.\n */\n removeChild(entity: Entity): void {\n const index = this.children.indexOf(entity);\n if (index !== -1) {\n this.children.splice(index, 1);\n entity.parent = undefined;\n }\n }\n\n /**\n * Marks this entity as inactive and emits the 'kill' event.\n */\n kill(): void {\n this.isActive = false;\n this.emit('kill');\n }\n}\n","/**\n * Represents a subscription to an observable that can be unsubscribed.\n */\nexport interface ObservableSubscription {\n /** Removes the listener associated with this subscription. */\n unsubscribe(): void;\n}\n\n/**\n * A listener function that receives values emitted by an Observable.\n */\nexport type ObservableListener<TValue> = (value: TValue) => void;\n\n/**\n * A minimal typed observable that supports subscribing to a stream of values.\n * Used by Query to expose reactive entityAdded$ / entityRemoved$ streams.\n */\nexport class Observable<TValue> {\n /** The registered listeners that will be called on each notify. */\n private listeners: Set<ObservableListener<TValue>> = new Set();\n\n /**\n * Subscribes a listener to this observable.\n * @param listener - The function to call each time a value is emitted.\n * @returns A subscription that can be used to unsubscribe the listener.\n */\n subscribe(listener: ObservableListener<TValue>): ObservableSubscription {\n this.listeners.add(listener);\n return {\n unsubscribe: () => {\n this.listeners.delete(listener);\n },\n };\n }\n\n /**\n * Emits a value to all subscribed listeners.\n * Intended for internal use by the producer that owns the observable.\n * @param value - The value to emit.\n */\n notify(value: TValue): void {\n for (const listener of [...this.listeners]) {\n listener(value);\n }\n }\n}\n","import type { ComponentConstructor } from './component.js';\nimport type { Entity } from './entity.js';\nimport { Observable } from './observable.js';\n\n/**\n * Parameters for creating a complex query with component and tag filters.\n */\nexport interface QueryParameters {\n /** Component-based filters. */\n components?: {\n /** All of these component types must be present. */\n all?: ComponentConstructor[];\n /** At least one of these component types must be present. */\n any?: ComponentConstructor[];\n /** None of these component types may be present. */\n not?: ComponentConstructor[];\n };\n /** Tag-based filters. */\n tags?: {\n /** All of these tags must be present. */\n all?: string[];\n /** At least one of these tags must be present. */\n any?: string[];\n /** None of these tags may be present. */\n not?: string[];\n };\n}\n\n/**\n * A reactive query that tracks entities matching specific component and tag criteria.\n */\nexport class Query {\n /** The resolved query parameters. */\n private parameters: QueryParameters;\n\n /** The set of entities currently matching this query. */\n private matchedEntities: Set<Entity> = new Set();\n\n /** Emits entities when they transition from non-matching to matching this query. */\n readonly entityAdded$: Observable<Entity> = new Observable<Entity>();\n\n /** Emits entities when they transition from matching to non-matching this query. */\n readonly entityRemoved$: Observable<Entity> = new Observable<Entity>();\n\n /**\n * Creates a new query from either an array of required component types or a full QueryParameters object.\n * @param parameters - Component constructor array or full query parameters.\n */\n constructor(parameters: ComponentConstructor[] | QueryParameters) {\n if (Array.isArray(parameters)) {\n this.parameters = { components: { all: parameters } };\n } else {\n this.parameters = parameters;\n }\n }\n\n /** Returns a readonly array of all entities currently matching this query. */\n get entities(): readonly Entity[] {\n return [...this.matchedEntities];\n }\n\n /**\n * Tests whether a given entity matches this query's criteria.\n * @param entity - The entity to test.\n * @returns True if the entity matches all criteria.\n */\n matches(entity: Entity): boolean {\n const { components, tags } = this.parameters;\n\n if (components?.all) {\n for (const componentType of components.all) {\n if (!entity.has(componentType)) return false;\n }\n }\n\n if (components?.any) {\n let hasAny = false;\n for (const componentType of components.any) {\n if (entity.has(componentType)) {\n hasAny = true;\n break;\n }\n }\n if (!hasAny) return false;\n }\n\n if (components?.not) {\n for (const componentType of components.not) {\n if (entity.has(componentType)) return false;\n }\n }\n\n if (tags?.all) {\n for (const tag of tags.all) {\n if (!entity.hasTag(tag)) return false;\n }\n }\n\n if (tags?.any) {\n let hasAny = false;\n for (const tag of tags.any) {\n if (entity.hasTag(tag)) {\n hasAny = true;\n break;\n }\n }\n if (!hasAny) return false;\n }\n\n if (tags?.not) {\n for (const tag of tags.not) {\n if (entity.hasTag(tag)) return false;\n }\n }\n\n return true;\n }\n\n /**\n * Adds an entity to the matched set unconditionally. Called by the query manager\n * when it has already determined the entity matches. Fires entityAdded$ on transition.\n * @param entity - The entity to add.\n */\n addEntity(entity: Entity): void {\n if (!this.matchedEntities.has(entity)) {\n this.matchedEntities.add(entity);\n this.entityAdded$.notify(entity);\n }\n }\n\n /**\n * Removes an entity from the matched set. Fires entityRemoved$ on transition.\n * @param entity - The entity to remove.\n */\n removeEntity(entity: Entity): void {\n if (this.matchedEntities.has(entity)) {\n this.matchedEntities.delete(entity);\n this.entityRemoved$.notify(entity);\n }\n }\n\n /**\n * Re-evaluates whether an entity matches this query and updates the matched\n * set accordingly, firing entityAdded$ / entityRemoved$ on state transitions.\n * @param entity - The entity to re-evaluate.\n */\n checkAndModify(entity: Entity): void {\n const currentlyMatches = this.matches(entity);\n const isTracked = this.matchedEntities.has(entity);\n if (currentlyMatches && !isTracked) {\n this.matchedEntities.add(entity);\n this.entityAdded$.notify(entity);\n } else if (!currentlyMatches && isTracked) {\n this.matchedEntities.delete(entity);\n this.entityRemoved$.notify(entity);\n }\n }\n}\n","import { Query, type QueryParameters } from './query.js';\nimport type { ComponentConstructor } from './component.js';\nimport type { Entity } from './entity.js';\n\n/**\n * Provides read access to the current set of world entities for query backfill.\n */\nexport interface EntityProvider {\n /** Returns a readonly array of all entities currently in the world. */\n readonly entities: readonly Entity[];\n}\n\n/**\n * Manages the lifecycle of queries, creating and updating them as entities change.\n */\nexport class QueryManager {\n /** All registered queries. */\n private queries: Query[] = [];\n\n /** Optional provider used to backfill newly created queries with existing entities. */\n private entityProvider?: EntityProvider;\n\n /**\n * Sets the entity provider used to backfill newly created queries.\n * @param entityProvider - Provider that exposes the current world entities.\n */\n setEntityProvider(entityProvider: EntityProvider): void {\n this.entityProvider = entityProvider;\n }\n\n /**\n * Creates a new query, registers it for automatic updates, and backfills it\n * with any currently-existing entities that match.\n * @param parameters - Component constructor array or full query parameters.\n * @returns The newly created query.\n */\n createQuery(parameters: ComponentConstructor[] | QueryParameters): Query {\n const query = new Query(parameters);\n this.queries.push(query);\n if (this.entityProvider) {\n for (const entity of this.entityProvider.entities) {\n query.checkAndModify(entity);\n }\n }\n return query;\n }\n\n /**\n * Notifies all queries that an entity has been added to the world.\n * @param entity - The entity that was added.\n */\n notifyEntityAdded(entity: Entity): void {\n for (const query of this.queries) {\n query.checkAndModify(entity);\n }\n }\n\n /**\n * Notifies all queries that an entity has been removed from the world,\n * forcing removal regardless of match state so entityRemoved$ fires for\n * matched entities.\n * @param entity - The entity that was removed.\n */\n notifyEntityRemoved(entity: Entity): void {\n for (const query of this.queries) {\n query.removeEntity(entity);\n }\n }\n\n /**\n * Notifies all queries that an entity's components or tags have changed.\n * Queries re-evaluate match state and fire observables on transitions.\n * @param entity - The entity that changed.\n */\n notifyComponentChanged(entity: Entity): void {\n for (const query of this.queries) {\n query.checkAndModify(entity);\n }\n }\n}\n","import type { World } from './world.js';\n\n/**\n * The type of system, determining when it runs in the update cycle.\n */\nexport enum SystemType {\n /** Systems that update game logic. */\n Update = 'update',\n /** Systems that handle rendering. */\n Draw = 'draw',\n}\n\n/**\n * Predefined priority levels for system execution order.\n * Lower values run first.\n */\nexport const SystemPriority = {\n /** Highest priority (runs first). */\n Highest: 0,\n /** Higher than average priority. */\n Higher: 25,\n /** Default priority. */\n Average: 50,\n /** Lower than average priority. */\n Lower: 75,\n /** Lowest priority (runs last). */\n Lowest: 100,\n} as const;\n\n/**\n * Abstract base class for all systems in the ECS.\n * Systems process entities that match specific queries each frame.\n */\nexport abstract class System {\n /** The type of this system, determining when it runs. */\n abstract readonly systemType: SystemType;\n\n /** The execution priority of this system. Lower values run first. */\n static priority: number = SystemPriority.Average;\n\n /**\n * Called each frame to process entities.\n * @param elapsedMilliseconds - The time elapsed since the last update in milliseconds.\n */\n abstract update(elapsedMilliseconds: number): void;\n\n /**\n * Optional initialization hook called when the system is added to a world.\n * @param world - The world this system belongs to.\n */\n initialize?(world: World): void;\n\n /**\n * Optional hook called before the main update.\n * @param elapsedMilliseconds - The time elapsed since the last update in milliseconds.\n */\n preupdate?(elapsedMilliseconds: number): void;\n\n /**\n * Optional hook called after the main update.\n * @param elapsedMilliseconds - The time elapsed since the last update in milliseconds.\n */\n postupdate?(elapsedMilliseconds: number): void;\n}\n","import { System, type SystemType } from './system.js';\n\n/**\n * Manages the registration and execution of systems in priority order.\n */\nexport class SystemManager {\n /** All registered systems. */\n private systems: System[] = [];\n\n /**\n * Registers a system for execution.\n * @param system - The system to add.\n */\n addSystem(system: System): void {\n this.systems.push(system);\n }\n\n /**\n * Removes a previously registered system.\n * @param system - The system to remove.\n */\n removeSystem(system: System): void {\n const index = this.systems.indexOf(system);\n if (index !== -1) {\n this.systems.splice(index, 1);\n }\n }\n\n /**\n * Runs all systems of the specified type in priority order.\n * Calls preupdate, update, and postupdate for each system.\n * @param systemType - The type of systems to run.\n * @param elapsedMilliseconds - The time elapsed since the last update in milliseconds.\n */\n updateSystems(systemType: SystemType, elapsedMilliseconds: number): void {\n const matchingSystems = this.systems\n .filter((system) => system.systemType === systemType)\n .sort((a, b) => {\n const priorityA = (a.constructor as typeof System).priority;\n const priorityB = (b.constructor as typeof System).priority;\n return priorityA - priorityB;\n });\n\n for (const system of matchingSystems) {\n if (system.preupdate) {\n system.preupdate(elapsedMilliseconds);\n }\n system.update(elapsedMilliseconds);\n if (system.postupdate) {\n system.postupdate(elapsedMilliseconds);\n }\n }\n }\n}\n","import type { Entity } from './entity.js';\nimport type { EntityProvider, QueryManager } from './query-manager.js';\n\n/**\n * Manages the lifecycle of entities and notifies the query manager of changes.\n */\nexport class EntityManager implements EntityProvider {\n /** All managed entities. */\n private entitySet: Set<Entity> = new Set();\n\n /** Reference to the query manager for change notifications. */\n private queryManager: QueryManager;\n\n /**\n * Creates a new EntityManager.\n * @param queryManager - The query manager to notify of entity changes.\n */\n constructor(queryManager: QueryManager) {\n this.queryManager = queryManager;\n this.queryManager.setEntityProvider(this);\n }\n\n /**\n * Adds an entity to this manager and notifies the query manager.\n * Also subscribes to the entity's component and tag change events.\n * @param entity - The entity to add.\n */\n addEntity(entity: Entity): void {\n this.entitySet.add(entity);\n this.queryManager.notifyEntityAdded(entity);\n\n entity.on('componentadded', () => {\n this.queryManager.notifyComponentChanged(entity);\n });\n entity.on('componentremoved', () => {\n this.queryManager.notifyComponentChanged(entity);\n });\n entity.on('tagadded', () => {\n this.queryManager.notifyComponentChanged(entity);\n });\n entity.on('tagremoved', () => {\n this.queryManager.notifyComponentChanged(entity);\n });\n entity.on('kill', () => {\n this.removeEntity(entity);\n });\n }\n\n /**\n * Removes an entity from this manager and notifies the query manager.\n * @param entity - The entity to remove.\n */\n removeEntity(entity: Entity): void {\n this.entitySet.delete(entity);\n this.queryManager.notifyEntityRemoved(entity);\n }\n\n /** Returns a readonly array of all managed entities. */\n get entities(): readonly Entity[] {\n return [...this.entitySet];\n }\n}\n","import { EntityManager } from './entity-manager.js';\nimport { SystemManager } from './system-manager.js';\nimport { QueryManager } from './query-manager.js';\nimport type { Entity } from './entity.js';\nimport type { System, SystemType } from './system.js';\nimport type { Query, QueryParameters } from './query.js';\nimport type { ComponentConstructor } from './component.js';\n\n/**\n * The world is the top-level orchestrator that owns entities, systems, and queries.\n */\nexport class World {\n /** Manages entity lifecycle. */\n private entityManager: EntityManager;\n\n /** Manages system registration and execution. */\n private systemManager: SystemManager;\n\n /** Manages query creation and updates. */\n private queryManager: QueryManager;\n\n constructor() {\n this.queryManager = new QueryManager();\n this.entityManager = new EntityManager(this.queryManager);\n this.systemManager = new SystemManager();\n }\n\n /**\n * Adds an entity to the world.\n * @param entity - The entity to add.\n */\n add(entity: Entity): void {\n this.entityManager.addEntity(entity);\n }\n\n /**\n * Adds a system to the world.\n * @param system - The system to add.\n */\n addSystem(system: System): void {\n this.systemManager.addSystem(system);\n }\n\n /**\n * Removes an entity from the world.\n * @param entity - The entity to remove.\n */\n remove(entity: Entity): void {\n this.entityManager.removeEntity(entity);\n }\n\n /**\n * Removes a system from the world.\n * @param system - The system to remove.\n */\n removeSystem(system: System): void {\n this.systemManager.removeSystem(system);\n }\n\n /**\n * Creates or retrieves a query matching the given parameters.\n * @param parameters - Component constructor array or full query parameters.\n * @returns A reactive query that tracks matching entities.\n */\n query(parameters: ComponentConstructor[] | QueryParameters): Query {\n return this.queryManager.createQuery(parameters);\n }\n\n /**\n * Runs all systems of the specified type for one frame.\n * @param systemType - The type of systems to run.\n * @param elapsedMilliseconds - The time elapsed since the last update in milliseconds.\n */\n update(systemType: SystemType, elapsedMilliseconds: number): void {\n this.systemManager.updateSystems(systemType, elapsedMilliseconds);\n }\n\n /** Returns a readonly array of all entities currently in the world. */\n get entities(): readonly Entity[] {\n return this.entityManager.entities;\n }\n}\n","/**\n * An immutable 3D vector with x, y, and z components.\n */\nexport class Vector3 {\n /**\n * Creates a new Vector3.\n * @param x - The x component.\n * @param y - The y component.\n * @param z - The z component.\n */\n constructor(\n /** The x component. */\n public readonly x: number,\n /** The y component. */\n public readonly y: number,\n /** The z component. */\n public readonly z: number,\n ) {}\n\n /**\n * Adds another vector to this vector and returns the result.\n * @param other - The vector to add.\n * @returns A new Vector3 representing the sum.\n */\n add(other: Vector3): Vector3 {\n return new Vector3(this.x + other.x, this.y + other.y, this.z + other.z);\n }\n\n /**\n * Subtracts another vector from this vector and returns the result.\n * @param other - The vector to subtract.\n * @returns A new Vector3 representing the difference.\n */\n subtract(other: Vector3): Vector3 {\n return new Vector3(this.x - other.x, this.y - other.y, this.z - other.z);\n }\n\n /**\n * Scales this vector by a scalar value and returns the result.\n * @param scalar - The scalar multiplier.\n * @returns A new scaled Vector3.\n */\n scale(scalar: number): Vector3 {\n return new Vector3(this.x * scalar, this.y * scalar, this.z * scalar);\n }\n\n /**\n * Returns the normalized (unit length) version of this vector.\n * If the vector has zero length, returns a zero vector.\n * @returns A new normalized Vector3.\n */\n normalize(): Vector3 {\n const magnitude = Math.sqrt(this.x * this.x + this.y * this.y + this.z * this.z);\n if (magnitude === 0) {\n return Vector3.zero();\n }\n return new Vector3(this.x / magnitude, this.y / magnitude, this.z / magnitude);\n }\n\n /**\n * Computes the dot product of this vector with another.\n * @param other - The other vector.\n * @returns The dot product.\n */\n dot(other: Vector3): number {\n return this.x * other.x + this.y * other.y + this.z * other.z;\n }\n\n /**\n * Computes the cross product of this vector with another.\n * @param other - The other vector.\n * @returns A new Vector3 representing the cross product.\n */\n cross(other: Vector3): Vector3 {\n return new Vector3(\n this.y * other.z - this.z * other.y,\n this.z * other.x - this.x * other.z,\n this.x * other.y - this.y * other.x,\n );\n }\n\n /**\n * Computes the Euclidean distance between this vector and another.\n * @param other - The other vector.\n * @returns The distance.\n */\n distance(other: Vector3): number {\n return Math.sqrt(this.distanceSquared(other));\n }\n\n /**\n * Computes the squared Euclidean distance between this vector and another.\n * @param other - The other vector.\n * @returns The squared distance.\n */\n distanceSquared(other: Vector3): number {\n const deltaX = this.x - other.x;\n const deltaY = this.y - other.y;\n const deltaZ = this.z - other.z;\n return deltaX * deltaX + deltaY * deltaY + deltaZ * deltaZ;\n }\n\n /**\n * Linearly interpolates between this vector and a target vector.\n * @param target - The target vector.\n * @param interpolation - The interpolation factor, typically between 0 and 1.\n * @returns A new interpolated Vector3.\n */\n lerp(target: Vector3, interpolation: number): Vector3 {\n return new Vector3(\n this.x + (target.x - this.x) * interpolation,\n this.y + (target.y - this.y) * interpolation,\n this.z + (target.z - this.z) * interpolation,\n );\n }\n\n /**\n * Creates a copy of this vector.\n * @returns A new Vector3 with the same components.\n */\n clone(): Vector3 {\n return new Vector3(this.x, this.y, this.z);\n }\n\n /**\n * Checks whether this vector is equal to another within floating-point tolerance.\n * @param other - The vector to compare against.\n * @param epsilon - The tolerance for comparison. Defaults to 1e-6.\n * @returns True if the vectors are approximately equal.\n */\n equals(other: Vector3, epsilon: number = 1e-6): boolean {\n return (\n Math.abs(this.x - other.x) <= epsilon &&\n Math.abs(this.y - other.y) <= epsilon &&\n Math.abs(this.z - other.z) <= epsilon\n );\n }\n\n /**\n * Returns a string representation of this vector.\n * @returns A string in the format \"Vector3(x, y, z)\".\n */\n toString(): string {\n return `Vector3(${this.x}, ${this.y}, ${this.z})`;\n }\n\n /** Returns a vector with all components set to zero. */\n static zero(): Vector3 {\n return new Vector3(0, 0, 0);\n }\n\n /** Returns a vector with all components set to one. */\n static one(): Vector3 {\n return new Vector3(1, 1, 1);\n }\n\n /** Returns the up direction vector (0, 1, 0). */\n static up(): Vector3 {\n return new Vector3(0, 1, 0);\n }\n\n /** Returns the down direction vector (0, -1, 0). */\n static down(): Vector3 {\n return new Vector3(0, -1, 0);\n }\n\n /** Returns the left direction vector (-1, 0, 0). */\n static left(): Vector3 {\n return new Vector3(-1, 0, 0);\n }\n\n /** Returns the right direction vector (1, 0, 0). */\n static right(): Vector3 {\n return new Vector3(1, 0, 0);\n }\n\n /** Returns the forward direction vector (0, 0, 1). */\n static forward(): Vector3 {\n return new Vector3(0, 0, 1);\n }\n\n /** Returns the back direction vector (0, 0, -1). */\n static back(): Vector3 {\n return new Vector3(0, 0, -1);\n }\n}\n","import { Vector3 } from './vector3.js';\n\n/**\n * An immutable quaternion representing a rotation in 3D space.\n * Uses the convention (x, y, z, w) where w is the scalar component.\n */\nexport class Quaternion {\n /**\n * Creates a new Quaternion.\n * @param x - The x component.\n * @param y - The y component.\n * @param z - The z component.\n * @param w - The w (scalar) component.\n */\n constructor(\n /** The x component. */\n public readonly x: number,\n /** The y component. */\n public readonly y: number,\n /** The z component. */\n public readonly z: number,\n /** The w (scalar) component. */\n public readonly w: number,\n ) {}\n\n /**\n * Multiplies this quaternion by another (composes rotations).\n * @param other - The quaternion to multiply with.\n * @returns A new Quaternion representing the combined rotation.\n */\n multiply(other: Quaternion): Quaternion {\n return new Quaternion(\n this.w * other.x + this.x * other.w + this.y * other.z - this.z * other.y,\n this.w * other.y - this.x * other.z + this.y * other.w + this.z * other.x,\n this.w * other.z + this.x * other.y - this.y * other.x + this.z * other.w,\n this.w * other.w - this.x * other.x - this.y * other.y - this.z * other.z,\n );\n }\n\n /**\n * Returns the inverse (conjugate divided by squared magnitude) of this quaternion.\n * For unit quaternions, this is the same as the conjugate.\n * @returns A new Quaternion representing the inverse rotation.\n */\n inverse(): Quaternion {\n const magnitudeSquared = this.x * this.x + this.y * this.y + this.z * this.z + this.w * this.w;\n if (magnitudeSquared === 0) {\n return Quaternion.identity();\n }\n return new Quaternion(\n -this.x / magnitudeSquared,\n -this.y / magnitudeSquared,\n -this.z / magnitudeSquared,\n this.w / magnitudeSquared,\n );\n }\n\n /**\n * Returns a normalized (unit length) version of this quaternion.\n * @returns A new normalized Quaternion.\n */\n normalize(): Quaternion {\n const magnitude = Math.sqrt(this.x * this.x + this.y * this.y + this.z * this.z + this.w * this.w);\n if (magnitude === 0) {\n return Quaternion.identity();\n }\n return new Quaternion(\n this.x / magnitude,\n this.y / magnitude,\n this.z / magnitude,\n this.w / magnitude,\n );\n }\n\n /**\n * Performs spherical linear interpolation between this quaternion and a target.\n * @param target - The target quaternion.\n * @param interpolation - The interpolation factor, typically between 0 and 1.\n * @returns A new interpolated Quaternion.\n */\n slerp(target: Quaternion, interpolation: number): Quaternion {\n let cosHalfAngle = this.x * target.x + this.y * target.y + this.z * target.z + this.w * target.w;\n\n let targetX = target.x;\n let targetY = target.y;\n let targetZ = target.z;\n let targetW = target.w;\n\n // If the dot product is negative, negate one quaternion to take the shorter path.\n if (cosHalfAngle < 0) {\n cosHalfAngle = -cosHalfAngle;\n targetX = -targetX;\n targetY = -targetY;\n targetZ = -targetZ;\n targetW = -targetW;\n }\n\n // If quaternions are very close, use linear interpolation to avoid division by zero.\n if (cosHalfAngle > 0.9995) {\n return new Quaternion(\n this.x + (targetX - this.x) * interpolation,\n this.y + (targetY - this.y) * interpolation,\n this.z + (targetZ - this.z) * interpolation,\n this.w + (targetW - this.w) * interpolation,\n ).normalize();\n }\n\n const halfAngle = Math.acos(cosHalfAngle);\n const sinHalfAngle = Math.sin(halfAngle);\n const ratioA = Math.sin((1 - interpolation) * halfAngle) / sinHalfAngle;\n const ratioB = Math.sin(interpolation * halfAngle) / sinHalfAngle;\n\n return new Quaternion(\n this.x * ratioA + targetX * ratioB,\n this.y * ratioA + targetY * ratioB,\n this.z * ratioA + targetZ * ratioB,\n this.w * ratioA + targetW * ratioB,\n );\n }\n\n /**\n * Converts this quaternion to Euler angles (in radians).\n * Returns a Vector3 with (pitch, yaw, roll) as (x, y, z).\n * @returns A Vector3 containing the Euler angles in radians.\n */\n toEulerAngles(): Vector3 {\n // Roll (x-axis rotation)\n const sinRollCosP = 2 * (this.w * this.x + this.y * this.z);\n const cosRollCosP = 1 - 2 * (this.x * this.x + this.y * this.y);\n const roll = Math.atan2(sinRollCosP, cosRollCosP);\n\n // Pitch (y-axis rotation)\n const sinPitch = 2 * (this.w * this.y - this.z * this.x);\n let pitch: number;\n if (Math.abs(sinPitch) >= 1) {\n pitch = Math.sign(sinPitch) * (Math.PI / 2); // Clamp to avoid NaN from asin\n } else {\n pitch = Math.asin(sinPitch);\n }\n\n // Yaw (z-axis rotation)\n const sinYawCosP = 2 * (this.w * this.z + this.x * this.y);\n const cosYawCosP = 1 - 2 * (this.y * this.y + this.z * this.z);\n const yaw = Math.atan2(sinYawCosP, cosYawCosP);\n\n return new Vector3(roll, pitch, yaw);\n }\n\n /**\n * Rotates a Vector3 by this quaternion.\n * @param vector - The vector to rotate.\n * @returns A new rotated Vector3.\n */\n rotateVector3(vector: Vector3): Vector3 {\n const vectorQuaternion = new Quaternion(vector.x, vector.y, vector.z, 0);\n const result = this.multiply(vectorQuaternion).multiply(this.inverse());\n return new Vector3(result.x, result.y, result.z);\n }\n\n /** Creates a deep copy of this quaternion. */\n clone(): Quaternion {\n return new Quaternion(this.x, this.y, this.z, this.w);\n }\n\n /**\n * Checks if this quaternion is approximately equal to another.\n * @param other - The quaternion to compare against.\n * @param epsilon - The tolerance for floating-point comparison.\n */\n equals(other: Quaternion, epsilon: number = 1e-6): boolean {\n return (\n Math.abs(this.x - other.x) < epsilon &&\n Math.abs(this.y - other.y) < epsilon &&\n Math.abs(this.z - other.z) < epsilon &&\n Math.abs(this.w - other.w) < epsilon\n );\n }\n\n /** Returns a string representation of this quaternion. */\n toString(): string {\n return `Quaternion(${this.x}, ${this.y}, ${this.z}, ${this.w})`;\n }\n\n /** Returns the identity quaternion (no rotation). */\n static identity(): Quaternion {\n return new Quaternion(0, 0, 0, 1);\n }\n\n /**\n * Creates a quaternion from Euler angles (in radians).\n * @param euler - A Vector3 containing (roll, pitch, yaw) as (x, y, z) in radians.\n * @returns A new Quaternion representing the rotation.\n */\n static fromEulerAngles(euler: Vector3): Quaternion {\n const halfRoll = euler.x * 0.5;\n const halfPitch = euler.y * 0.5;\n const halfYaw = euler.z * 0.5;\n\n const sinRoll = Math.sin(halfRoll);\n const cosRoll = Math.cos(halfRoll);\n const sinPitch = Math.sin(halfPitch);\n const cosPitch = Math.cos(halfPitch);\n const sinYaw = Math.sin(halfYaw);\n const cosYaw = Math.cos(halfYaw);\n\n return new Quaternion(\n sinRoll * cosPitch * cosYaw - cosRoll * sinPitch * sinYaw,\n cosRoll * sinPitch * cosYaw + sinRoll * cosPitch * sinYaw,\n cosRoll * cosPitch * sinYaw - sinRoll * sinPitch * cosYaw,\n cosRoll * cosPitch * cosYaw + sinRoll * sinPitch * sinYaw,\n );\n }\n\n /**\n * Creates a quaternion from an axis-angle representation.\n * @param axis - The axis of rotation (should be normalized).\n * @param angleRadians - The angle of rotation in radians.\n * @returns A new Quaternion representing the rotation.\n */\n static fromAxisAngle(axis: Vector3, angleRadians: number): Quaternion {\n const halfAngle = angleRadians * 0.5;\n const sinHalfAngle = Math.sin(halfAngle);\n return new Quaternion(\n axis.x * sinHalfAngle,\n axis.y * sinHalfAngle,\n axis.z * sinHalfAngle,\n Math.cos(halfAngle),\n );\n }\n}\n","import { Vector3 } from '@donut/math';\nimport { Quaternion } from '@donut/math';\nimport { Component } from './component.js';\n\n/**\n * A component that represents an entity's position, rotation, and scale in 3D space.\n */\nexport class TransformComponent extends Component {\n /** The position in world space. */\n position: Vector3 = Vector3.zero();\n\n /** The rotation as a quaternion. */\n rotation: Quaternion = Quaternion.identity();\n\n /** The scale factor along each axis. */\n scale: Vector3 = Vector3.one();\n\n /** The z-ordering index for 2D rendering. */\n zIndex: number = 0;\n\n /** Creates a deep copy of this transform component. */\n clone(): TransformComponent {\n const cloned = new TransformComponent();\n cloned.position = this.position.clone();\n cloned.rotation = this.rotation.clone();\n cloned.scale = this.scale.clone();\n cloned.zIndex = this.zIndex;\n return cloned;\n }\n\n /**\n * Serializes this component's state to a plain object.\n * @returns A record containing position, rotation, scale, and zIndex.\n */\n serialize(): Record<string, unknown> {\n return {\n position: { x: this.position.x, y: this.position.y, z: this.position.z },\n rotation: { x: this.rotation.x, y: this.rotation.y, z: this.rotation.z, w: this.rotation.w },\n scale: { x: this.scale.x, y: this.scale.y, z: this.scale.z },\n zIndex: this.zIndex,\n };\n }\n\n /**\n * Restores this component's state from a serialized object.\n * @param data - The serialized data to restore from.\n */\n deserialize(data: Record<string, unknown>): void {\n const position = data['position'] as { x: number; y: number; z: number } | undefined;\n if (position) {\n this.position = new Vector3(position.x, position.y, position.z);\n }\n const rotation = data['rotation'] as { x: number; y: number; z: number; w: number } | undefined;\n if (rotation) {\n this.rotation = new Quaternion(rotation.x, rotation.y, rotation.z, rotation.w);\n }\n const scale = data['scale'] as { x: number; y: number; z: number } | undefined;\n if (scale) {\n this.scale = new Vector3(scale.x, scale.y, scale.z);\n }\n if (typeof data['zIndex'] === 'number') {\n this.zIndex = data['zIndex'];\n }\n }\n}\n","import { Vector3 } from '@donut/math';\nimport { Component } from './component.js';\n\n/**\n * A component that stores velocity, acceleration, and rotational dynamics for an entity.\n *\n * Vector3 instances stored on this component are treated as immutable values.\n * To change velocity or acceleration, assign a new Vector3 (for example\n * `motion.velocity = new Vector3(x, y, z)`) or call {@link MotionComponent.setVelocity}\n * / {@link MotionComponent.setAcceleration}. Do not mutate the fields of the\n * existing Vector3 in place — downstream systems may cache references.\n */\nexport class MotionComponent extends Component {\n /**\n * The linear velocity in units per second.\n *\n * Immutable — to change, assign a new Vector3\n * (`motion.velocity = new Vector3(x, y, z)`) or call setVelocity.\n */\n velocity: Vector3 = Vector3.zero();\n\n /**\n * The linear acceleration in units per second squared.\n *\n * Immutable — to change, assign a new Vector3\n * (`motion.acceleration = new Vector3(x, y, z)`) or call setAcceleration.\n */\n acceleration: Vector3 = Vector3.zero();\n\n /** The angular velocity in radians per second. */\n angularVelocity: number = 0;\n\n /** The torque applied to the entity in radians per second squared. */\n torque: number = 0;\n\n /** The rotational inertia of the entity. */\n inertia: number = 1;\n\n /**\n * Replaces the velocity with a new Vector3 constructed from the given components.\n * @param x - The x component of the new velocity.\n * @param y - The y component of the new velocity.\n * @param z - The z component of the new velocity.\n */\n setVelocity(x: number, y: number, z: number): void {\n this.velocity = new Vector3(x, y, z);\n }\n\n /**\n * Replaces the acceleration with a new Vector3 constructed from the given components.\n * @param x - The x component of the new acceleration.\n * @param y - The y component of the new acceleration.\n * @param z - The z component of the new acceleration.\n */\n setAcceleration(x: number, y: number, z: number): void {\n this.acceleration = new Vector3(x, y, z);\n }\n\n /** Creates a deep copy of this motion component. */\n clone(): MotionComponent {\n const cloned = new MotionComponent();\n cloned.velocity = this.velocity.clone();\n cloned.acceleration = this.acceleration.clone();\n cloned.angularVelocity = this.angularVelocity;\n cloned.torque = this.torque;\n cloned.inertia = this.inertia;\n return cloned;\n }\n\n /**\n * Serializes this component's state to a plain object.\n * @returns A record containing velocity, acceleration, and rotational properties.\n */\n serialize(): Record<string, unknown> {\n return {\n velocity: { x: this.velocity.x, y: this.velocity.y, z: this.velocity.z },\n acceleration: { x: this.acceleration.x, y: this.acceleration.y, z: this.acceleration.z },\n angularVelocity: this.angularVelocity,\n torque: this.torque,\n inertia: this.inertia,\n };\n }\n\n /**\n * Restores this component's state from a serialized object.\n * @param data - The serialized data to restore from.\n */\n deserialize(data: Record<string, unknown>): void {\n const velocity = data['velocity'] as { x: number; y: number; z: number } | undefined;\n if (velocity) {\n this.velocity = new Vector3(velocity.x, velocity.y, velocity.z);\n }\n const acceleration = data['acceleration'] as { x: number; y: number; z: number } | undefined;\n if (acceleration) {\n this.acceleration = new Vector3(acceleration.x, acceleration.y, acceleration.z);\n }\n if (typeof data['angularVelocity'] === 'number') {\n this.angularVelocity = data['angularVelocity'];\n }\n if (typeof data['torque'] === 'number') {\n this.torque = data['torque'];\n }\n if (typeof data['inertia'] === 'number') {\n this.inertia = data['inertia'];\n }\n }\n}\n","import { System, SystemType } from './system.js';\nimport { TransformComponent } from './transform-component.js';\nimport { MotionComponent } from './motion-component.js';\nimport type { Query } from './query.js';\nimport type { World } from './world.js';\n\n/**\n * A system that applies Euler integration to update entity positions based on velocity and acceleration.\n */\nexport class MotionSystem extends System {\n /** This system runs during the update phase. */\n readonly systemType = SystemType.Update;\n\n /** The query tracking entities with both TransformComponent and MotionComponent. */\n private motionQuery: Query;\n\n /**\n * Creates a new MotionSystem.\n * @param world - The world to create the motion query in.\n */\n constructor(world: World) {\n super();\n this.motionQuery = world.query([TransformComponent, MotionComponent]);\n }\n\n /**\n * Updates all entities with motion, applying acceleration to velocity and velocity to position.\n * @param elapsedMilliseconds - The time elapsed since the last update in milliseconds.\n */\n update(elapsedMilliseconds: number): void {\n const deltaTimeSeconds = elapsedMilliseconds / 1000;\n\n for (const entity of this.motionQuery.entities) {\n const transform = entity.get(TransformComponent)!;\n const motion = entity.get(MotionComponent)!;\n\n motion.velocity = motion.velocity.add(motion.acceleration.scale(deltaTimeSeconds));\n transform.position = transform.position.add(motion.velocity.scale(deltaTimeSeconds));\n }\n }\n}\n"]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from '@donut/ctrllr';
|
|
@@ -0,0 +1,302 @@
|
|
|
1
|
+
// ../ctrllr/src/mock-ctrllr-manager.ts
|
|
2
|
+
var DEFAULT_KEYBOARD_TO_ACTION_MAP = {
|
|
3
|
+
ArrowLeft: "moveLeft",
|
|
4
|
+
ArrowRight: "moveRight",
|
|
5
|
+
ArrowUp: "moveUp",
|
|
6
|
+
ArrowDown: "moveDown",
|
|
7
|
+
Space: "jump",
|
|
8
|
+
KeyF: "fire"
|
|
9
|
+
};
|
|
10
|
+
var MockCtrllrManager = class {
|
|
11
|
+
/** Map of action name to subscribed callbacks. */
|
|
12
|
+
actionCallbacks = /* @__PURE__ */ new Map();
|
|
13
|
+
/** Mapping from keyboard `KeyboardEvent.code` values to action names. */
|
|
14
|
+
keyboardToActionMap;
|
|
15
|
+
/** Set of currently pressed keys, used to suppress OS key-repeat. */
|
|
16
|
+
pressedKeyCodes = /* @__PURE__ */ new Set();
|
|
17
|
+
/** Bound keydown handler retained for removal in {@link destroy}. */
|
|
18
|
+
boundKeyDownHandler;
|
|
19
|
+
/** Bound keyup handler retained for removal in {@link destroy}. */
|
|
20
|
+
boundKeyUpHandler;
|
|
21
|
+
/** Whether window listeners were attached. */
|
|
22
|
+
windowListenersAttached;
|
|
23
|
+
constructor(options) {
|
|
24
|
+
this.keyboardToActionMap = {
|
|
25
|
+
...DEFAULT_KEYBOARD_TO_ACTION_MAP,
|
|
26
|
+
...options?.keyboardToActionMap ?? {}
|
|
27
|
+
};
|
|
28
|
+
this.boundKeyDownHandler = (event) => {
|
|
29
|
+
this.handleKeyDown(event.code);
|
|
30
|
+
};
|
|
31
|
+
this.boundKeyUpHandler = (event) => {
|
|
32
|
+
this.handleKeyUp(event.code);
|
|
33
|
+
};
|
|
34
|
+
const shouldAttach = options?.attachWindowListeners ?? typeof window !== "undefined";
|
|
35
|
+
if (shouldAttach && typeof window !== "undefined") {
|
|
36
|
+
window.addEventListener("keydown", this.boundKeyDownHandler);
|
|
37
|
+
window.addEventListener("keyup", this.boundKeyUpHandler);
|
|
38
|
+
this.windowListenersAttached = true;
|
|
39
|
+
} else {
|
|
40
|
+
this.windowListenersAttached = false;
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
/** {@inheritDoc CtrllrManagerBridge.onAction} */
|
|
44
|
+
onAction(actionName, callback) {
|
|
45
|
+
let set = this.actionCallbacks.get(actionName);
|
|
46
|
+
if (!set) {
|
|
47
|
+
set = /* @__PURE__ */ new Set();
|
|
48
|
+
this.actionCallbacks.set(actionName, set);
|
|
49
|
+
}
|
|
50
|
+
set.add(callback);
|
|
51
|
+
}
|
|
52
|
+
/** {@inheritDoc CtrllrManagerBridge.removeAction} */
|
|
53
|
+
removeAction(actionName, callback) {
|
|
54
|
+
const set = this.actionCallbacks.get(actionName);
|
|
55
|
+
if (set) {
|
|
56
|
+
set.delete(callback);
|
|
57
|
+
if (set.size === 0) {
|
|
58
|
+
this.actionCallbacks.delete(actionName);
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* Simulates a key being pressed without requiring a real DOM event.
|
|
64
|
+
* @param keyboardCode - The `KeyboardEvent.code` value to simulate.
|
|
65
|
+
*/
|
|
66
|
+
simulateKeyDown(keyboardCode) {
|
|
67
|
+
this.handleKeyDown(keyboardCode);
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* Simulates a key being released without requiring a real DOM event.
|
|
71
|
+
* @param keyboardCode - The `KeyboardEvent.code` value to simulate.
|
|
72
|
+
*/
|
|
73
|
+
simulateKeyUp(keyboardCode) {
|
|
74
|
+
this.handleKeyUp(keyboardCode);
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* Removes any attached window listeners and clears all subscriptions.
|
|
78
|
+
*/
|
|
79
|
+
destroy() {
|
|
80
|
+
if (this.windowListenersAttached && typeof window !== "undefined") {
|
|
81
|
+
window.removeEventListener("keydown", this.boundKeyDownHandler);
|
|
82
|
+
window.removeEventListener("keyup", this.boundKeyUpHandler);
|
|
83
|
+
}
|
|
84
|
+
this.actionCallbacks.clear();
|
|
85
|
+
this.pressedKeyCodes.clear();
|
|
86
|
+
}
|
|
87
|
+
/**
|
|
88
|
+
* Internal handler for key-down. Suppresses OS key-repeat using a pressed-set.
|
|
89
|
+
*/
|
|
90
|
+
handleKeyDown(keyboardCode) {
|
|
91
|
+
if (this.pressedKeyCodes.has(keyboardCode)) {
|
|
92
|
+
return;
|
|
93
|
+
}
|
|
94
|
+
this.pressedKeyCodes.add(keyboardCode);
|
|
95
|
+
const actionName = this.keyboardToActionMap[keyboardCode];
|
|
96
|
+
if (actionName) {
|
|
97
|
+
this.dispatchActionEvent({ actionName, phase: "start", value: 1 });
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
/**
|
|
101
|
+
* Internal handler for key-up.
|
|
102
|
+
*/
|
|
103
|
+
handleKeyUp(keyboardCode) {
|
|
104
|
+
if (!this.pressedKeyCodes.has(keyboardCode)) {
|
|
105
|
+
return;
|
|
106
|
+
}
|
|
107
|
+
this.pressedKeyCodes.delete(keyboardCode);
|
|
108
|
+
const actionName = this.keyboardToActionMap[keyboardCode];
|
|
109
|
+
if (actionName) {
|
|
110
|
+
this.dispatchActionEvent({ actionName, phase: "end", value: 0 });
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
/**
|
|
114
|
+
* Dispatches an action event to all subscribed callbacks.
|
|
115
|
+
*/
|
|
116
|
+
dispatchActionEvent(actionEvent) {
|
|
117
|
+
const set = this.actionCallbacks.get(actionEvent.actionName);
|
|
118
|
+
if (!set) {
|
|
119
|
+
return;
|
|
120
|
+
}
|
|
121
|
+
for (const callback of set) {
|
|
122
|
+
callback(actionEvent);
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
};
|
|
126
|
+
|
|
127
|
+
// ../core/src/component.ts
|
|
128
|
+
var Component = class {
|
|
129
|
+
/** The entity that owns this component, if any. */
|
|
130
|
+
owner;
|
|
131
|
+
/** Optional list of component types that must be present on the entity. */
|
|
132
|
+
dependencies;
|
|
133
|
+
/**
|
|
134
|
+
* Serializes this component's state to a plain object.
|
|
135
|
+
* @returns A record of serializable key-value pairs.
|
|
136
|
+
*/
|
|
137
|
+
serialize() {
|
|
138
|
+
return {};
|
|
139
|
+
}
|
|
140
|
+
/**
|
|
141
|
+
* Restores this component's state from a serialized object.
|
|
142
|
+
* @param _data - The serialized data to restore from.
|
|
143
|
+
*/
|
|
144
|
+
deserialize(_data) {
|
|
145
|
+
}
|
|
146
|
+
};
|
|
147
|
+
|
|
148
|
+
// ../core/src/system.ts
|
|
149
|
+
var SystemPriority = {
|
|
150
|
+
/** Higher than average priority. */
|
|
151
|
+
Higher: 25,
|
|
152
|
+
/** Default priority. */
|
|
153
|
+
Average: 50};
|
|
154
|
+
var System = class {
|
|
155
|
+
/** The execution priority of this system. Lower values run first. */
|
|
156
|
+
static priority = SystemPriority.Average;
|
|
157
|
+
};
|
|
158
|
+
|
|
159
|
+
// ../ctrllr/src/ctrllr-input-component.ts
|
|
160
|
+
var CtrllrInputComponent = class _CtrllrInputComponent extends Component {
|
|
161
|
+
/** Map of CTRLLR action names to handlers. */
|
|
162
|
+
actionMap;
|
|
163
|
+
/** Whether the component is currently routing input. */
|
|
164
|
+
isEnabled;
|
|
165
|
+
/** The bridge used to subscribe to CTRLLR action events. */
|
|
166
|
+
managerBridge;
|
|
167
|
+
/** Bound subscription callbacks per action name, retained for removal. */
|
|
168
|
+
subscribedCallbacks = /* @__PURE__ */ new Map();
|
|
169
|
+
constructor(...constructorArguments) {
|
|
170
|
+
super();
|
|
171
|
+
const options = constructorArguments[0] ?? {};
|
|
172
|
+
if (!options.managerBridge) {
|
|
173
|
+
throw new Error(
|
|
174
|
+
"[CtrllrInputComponent] managerBridge is required in constructor options."
|
|
175
|
+
);
|
|
176
|
+
}
|
|
177
|
+
this.managerBridge = options.managerBridge;
|
|
178
|
+
this.actionMap = options.actionMap ?? {};
|
|
179
|
+
this.isEnabled = options.isEnabled ?? true;
|
|
180
|
+
}
|
|
181
|
+
/**
|
|
182
|
+
* Subscribes to all configured actions on the manager bridge.
|
|
183
|
+
* @param owner - The entity this component was added to.
|
|
184
|
+
*/
|
|
185
|
+
onAdd(owner) {
|
|
186
|
+
for (const actionName of Object.keys(this.actionMap)) {
|
|
187
|
+
const callback = (actionEvent) => {
|
|
188
|
+
if (!this.isEnabled) {
|
|
189
|
+
return;
|
|
190
|
+
}
|
|
191
|
+
this.routeActionEvent(actionName, actionEvent, owner);
|
|
192
|
+
};
|
|
193
|
+
this.subscribedCallbacks.set(actionName, callback);
|
|
194
|
+
this.managerBridge.onAction(actionName, callback);
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
/**
|
|
198
|
+
* Unsubscribes all action handlers.
|
|
199
|
+
* @param _previousOwner - The entity this component was removed from.
|
|
200
|
+
*/
|
|
201
|
+
onRemove(_previousOwner) {
|
|
202
|
+
for (const [actionName, callback] of this.subscribedCallbacks) {
|
|
203
|
+
this.managerBridge.removeAction(actionName, callback);
|
|
204
|
+
}
|
|
205
|
+
this.subscribedCallbacks.clear();
|
|
206
|
+
}
|
|
207
|
+
/**
|
|
208
|
+
* Resolves the configured handler for an action and invokes it.
|
|
209
|
+
*/
|
|
210
|
+
routeActionEvent(actionName, actionEvent, owner) {
|
|
211
|
+
const handler = this.actionMap[actionName];
|
|
212
|
+
if (typeof handler === "function") {
|
|
213
|
+
handler(actionEvent, owner);
|
|
214
|
+
return;
|
|
215
|
+
}
|
|
216
|
+
if (typeof handler === "string") {
|
|
217
|
+
const componentMap = owner.componentMap;
|
|
218
|
+
for (const siblingComponent of componentMap.values()) {
|
|
219
|
+
const candidateMethod = siblingComponent[handler];
|
|
220
|
+
if (typeof candidateMethod === "function") {
|
|
221
|
+
candidateMethod.call(
|
|
222
|
+
siblingComponent,
|
|
223
|
+
actionEvent
|
|
224
|
+
);
|
|
225
|
+
return;
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
/** Creates a deep copy of this component (sharing the same manager bridge). */
|
|
231
|
+
clone() {
|
|
232
|
+
return new _CtrllrInputComponent({
|
|
233
|
+
managerBridge: this.managerBridge,
|
|
234
|
+
actionMap: { ...this.actionMap },
|
|
235
|
+
isEnabled: this.isEnabled
|
|
236
|
+
});
|
|
237
|
+
}
|
|
238
|
+
/**
|
|
239
|
+
* Serializes this component's state. Only string-valued action mappings
|
|
240
|
+
* are included; function handlers are skipped because they are not
|
|
241
|
+
* representable as JSON.
|
|
242
|
+
*/
|
|
243
|
+
serialize() {
|
|
244
|
+
const serializableActionMap = {};
|
|
245
|
+
for (const [actionName, handler] of Object.entries(this.actionMap)) {
|
|
246
|
+
if (typeof handler === "string") {
|
|
247
|
+
serializableActionMap[actionName] = handler;
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
return {
|
|
251
|
+
actionMap: serializableActionMap,
|
|
252
|
+
isEnabled: this.isEnabled
|
|
253
|
+
};
|
|
254
|
+
}
|
|
255
|
+
/**
|
|
256
|
+
* Restores this component's state from a serialized object.
|
|
257
|
+
* @param data - The serialized data to restore from.
|
|
258
|
+
*/
|
|
259
|
+
deserialize(data) {
|
|
260
|
+
const actionMap = data["actionMap"];
|
|
261
|
+
if (actionMap && typeof actionMap === "object") {
|
|
262
|
+
const restored = {};
|
|
263
|
+
for (const [actionName, handler] of Object.entries(actionMap)) {
|
|
264
|
+
if (typeof handler === "string") {
|
|
265
|
+
restored[actionName] = handler;
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
this.actionMap = restored;
|
|
269
|
+
}
|
|
270
|
+
if (typeof data["isEnabled"] === "boolean") {
|
|
271
|
+
this.isEnabled = data["isEnabled"];
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
};
|
|
275
|
+
|
|
276
|
+
// ../ctrllr/src/ctrllr-input-system.ts
|
|
277
|
+
var CtrllrInputSystem = class extends System {
|
|
278
|
+
/** Runs in the Update pass. */
|
|
279
|
+
systemType = "update" /* Update */;
|
|
280
|
+
/** Runs before the default-priority MotionSystem. */
|
|
281
|
+
static priority = SystemPriority.Higher;
|
|
282
|
+
/** Reactive query of entities owning a CtrllrInputComponent. */
|
|
283
|
+
inputQuery;
|
|
284
|
+
constructor(world) {
|
|
285
|
+
super();
|
|
286
|
+
this.inputQuery = world.query([CtrllrInputComponent]);
|
|
287
|
+
}
|
|
288
|
+
/**
|
|
289
|
+
* Per-frame update. Currently a no-op — components handle routing via
|
|
290
|
+
* subscriptions. Iterating the query keeps the cache warm and reserves
|
|
291
|
+
* the hook for future per-frame polling.
|
|
292
|
+
* @param _elapsedMilliseconds - Milliseconds since the last update.
|
|
293
|
+
*/
|
|
294
|
+
update(_elapsedMilliseconds) {
|
|
295
|
+
for (const _entity of this.inputQuery.entities) {
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
};
|
|
299
|
+
|
|
300
|
+
export { CtrllrInputComponent, CtrllrInputSystem, DEFAULT_KEYBOARD_TO_ACTION_MAP, MockCtrllrManager };
|
|
301
|
+
//# sourceMappingURL=index.js.map
|
|
302
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../ctrllr/src/mock-ctrllr-manager.ts","../../../core/src/component.ts","../../../core/src/system.ts","../../../ctrllr/src/ctrllr-input-component.ts","../../../ctrllr/src/ctrllr-input-system.ts"],"names":[],"mappings":"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","file":"index.js","sourcesContent":["import type {\n CtrllrActionCallback,\n CtrllrActionEvent,\n CtrllrManagerBridge,\n} from './ctrllr-manager-bridge.js';\n\n/**\n * Default mapping from keyboard `KeyboardEvent.code` values to CTRLLR action\n * names. Used by the dev-mode mock so games can be tested without a physical\n * controller.\n */\nexport const DEFAULT_KEYBOARD_TO_ACTION_MAP: Readonly<Record<string, string>> = {\n ArrowLeft: 'moveLeft',\n ArrowRight: 'moveRight',\n ArrowUp: 'moveUp',\n ArrowDown: 'moveDown',\n Space: 'jump',\n KeyF: 'fire',\n};\n\n/**\n * Configuration options for {@link MockCtrllrManager}.\n */\nexport interface MockCtrllrManagerOptions {\n /** Override the default keyboard-to-action mapping. */\n keyboardToActionMap?: Record<string, string>;\n /**\n * Whether to attach window keyboard listeners on construction.\n * Defaults to true when `window` is available.\n */\n attachWindowListeners?: boolean;\n}\n\n/**\n * A development-mode CTRLLR manager that translates keyboard events into\n * CTRLLR action events. Suitable for use in the player and in tests.\n */\nexport class MockCtrllrManager implements CtrllrManagerBridge {\n /** Map of action name to subscribed callbacks. */\n private readonly actionCallbacks: Map<string, Set<CtrllrActionCallback>> = new Map();\n\n /** Mapping from keyboard `KeyboardEvent.code` values to action names. */\n private readonly keyboardToActionMap: Record<string, string>;\n\n /** Set of currently pressed keys, used to suppress OS key-repeat. */\n private readonly pressedKeyCodes: Set<string> = new Set();\n\n /** Bound keydown handler retained for removal in {@link destroy}. */\n private readonly boundKeyDownHandler: (event: KeyboardEvent) => void;\n\n /** Bound keyup handler retained for removal in {@link destroy}. */\n private readonly boundKeyUpHandler: (event: KeyboardEvent) => void;\n\n /** Whether window listeners were attached. */\n private readonly windowListenersAttached: boolean;\n\n constructor(options?: MockCtrllrManagerOptions) {\n this.keyboardToActionMap = {\n ...DEFAULT_KEYBOARD_TO_ACTION_MAP,\n ...(options?.keyboardToActionMap ?? {}),\n };\n this.boundKeyDownHandler = (event: KeyboardEvent): void => {\n this.handleKeyDown(event.code);\n };\n this.boundKeyUpHandler = (event: KeyboardEvent): void => {\n this.handleKeyUp(event.code);\n };\n\n const shouldAttach =\n options?.attachWindowListeners ?? typeof window !== 'undefined';\n if (shouldAttach && typeof window !== 'undefined') {\n window.addEventListener('keydown', this.boundKeyDownHandler);\n window.addEventListener('keyup', this.boundKeyUpHandler);\n this.windowListenersAttached = true;\n } else {\n this.windowListenersAttached = false;\n }\n }\n\n /** {@inheritDoc CtrllrManagerBridge.onAction} */\n onAction(actionName: string, callback: CtrllrActionCallback): void {\n let set = this.actionCallbacks.get(actionName);\n if (!set) {\n set = new Set();\n this.actionCallbacks.set(actionName, set);\n }\n set.add(callback);\n }\n\n /** {@inheritDoc CtrllrManagerBridge.removeAction} */\n removeAction(actionName: string, callback: CtrllrActionCallback): void {\n const set = this.actionCallbacks.get(actionName);\n if (set) {\n set.delete(callback);\n if (set.size === 0) {\n this.actionCallbacks.delete(actionName);\n }\n }\n }\n\n /**\n * Simulates a key being pressed without requiring a real DOM event.\n * @param keyboardCode - The `KeyboardEvent.code` value to simulate.\n */\n simulateKeyDown(keyboardCode: string): void {\n this.handleKeyDown(keyboardCode);\n }\n\n /**\n * Simulates a key being released without requiring a real DOM event.\n * @param keyboardCode - The `KeyboardEvent.code` value to simulate.\n */\n simulateKeyUp(keyboardCode: string): void {\n this.handleKeyUp(keyboardCode);\n }\n\n /**\n * Removes any attached window listeners and clears all subscriptions.\n */\n destroy(): void {\n if (this.windowListenersAttached && typeof window !== 'undefined') {\n window.removeEventListener('keydown', this.boundKeyDownHandler);\n window.removeEventListener('keyup', this.boundKeyUpHandler);\n }\n this.actionCallbacks.clear();\n this.pressedKeyCodes.clear();\n }\n\n /**\n * Internal handler for key-down. Suppresses OS key-repeat using a pressed-set.\n */\n private handleKeyDown(keyboardCode: string): void {\n if (this.pressedKeyCodes.has(keyboardCode)) {\n return;\n }\n this.pressedKeyCodes.add(keyboardCode);\n const actionName = this.keyboardToActionMap[keyboardCode];\n if (actionName) {\n this.dispatchActionEvent({ actionName, phase: 'start', value: 1 });\n }\n }\n\n /**\n * Internal handler for key-up.\n */\n private handleKeyUp(keyboardCode: string): void {\n if (!this.pressedKeyCodes.has(keyboardCode)) {\n return;\n }\n this.pressedKeyCodes.delete(keyboardCode);\n const actionName = this.keyboardToActionMap[keyboardCode];\n if (actionName) {\n this.dispatchActionEvent({ actionName, phase: 'end', value: 0 });\n }\n }\n\n /**\n * Dispatches an action event to all subscribed callbacks.\n */\n private dispatchActionEvent(actionEvent: CtrllrActionEvent): void {\n const set = this.actionCallbacks.get(actionEvent.actionName);\n if (!set) {\n return;\n }\n for (const callback of set) {\n callback(actionEvent);\n }\n }\n}\n","import type { Entity } from './entity.js';\n\n/**\n * Constructor type for Component subclasses, used for type-safe component lookups.\n */\nexport type ComponentConstructor<TComponent extends Component = Component> = new (...args: unknown[]) => TComponent;\n\n/**\n * Abstract base class for all components in the ECS.\n * Components hold state and optional lifecycle hooks.\n */\nexport abstract class Component {\n /** The entity that owns this component, if any. */\n owner?: Entity;\n\n /** Optional list of component types that must be present on the entity. */\n dependencies?: ComponentConstructor[];\n\n /**\n * Called when this component is added to an entity.\n * @param owner - The entity this component was added to.\n */\n onAdd?(owner: Entity): void;\n\n /**\n * Called when this component is removed from an entity.\n * @param previousOwner - The entity this component was removed from.\n */\n onRemove?(previousOwner: Entity): void;\n\n /** Creates a deep copy of this component. */\n abstract clone(): Component;\n\n /**\n * Serializes this component's state to a plain object.\n * @returns A record of serializable key-value pairs.\n */\n serialize(): Record<string, unknown> {\n return {};\n }\n\n /**\n * Restores this component's state from a serialized object.\n * @param _data - The serialized data to restore from.\n */\n deserialize(_data: Record<string, unknown>): void {\n // no-op by default\n }\n}\n","import type { World } from './world.js';\n\n/**\n * The type of system, determining when it runs in the update cycle.\n */\nexport enum SystemType {\n /** Systems that update game logic. */\n Update = 'update',\n /** Systems that handle rendering. */\n Draw = 'draw',\n}\n\n/**\n * Predefined priority levels for system execution order.\n * Lower values run first.\n */\nexport const SystemPriority = {\n /** Highest priority (runs first). */\n Highest: 0,\n /** Higher than average priority. */\n Higher: 25,\n /** Default priority. */\n Average: 50,\n /** Lower than average priority. */\n Lower: 75,\n /** Lowest priority (runs last). */\n Lowest: 100,\n} as const;\n\n/**\n * Abstract base class for all systems in the ECS.\n * Systems process entities that match specific queries each frame.\n */\nexport abstract class System {\n /** The type of this system, determining when it runs. */\n abstract readonly systemType: SystemType;\n\n /** The execution priority of this system. Lower values run first. */\n static priority: number = SystemPriority.Average;\n\n /**\n * Called each frame to process entities.\n * @param elapsedMilliseconds - The time elapsed since the last update in milliseconds.\n */\n abstract update(elapsedMilliseconds: number): void;\n\n /**\n * Optional initialization hook called when the system is added to a world.\n * @param world - The world this system belongs to.\n */\n initialize?(world: World): void;\n\n /**\n * Optional hook called before the main update.\n * @param elapsedMilliseconds - The time elapsed since the last update in milliseconds.\n */\n preupdate?(elapsedMilliseconds: number): void;\n\n /**\n * Optional hook called after the main update.\n * @param elapsedMilliseconds - The time elapsed since the last update in milliseconds.\n */\n postupdate?(elapsedMilliseconds: number): void;\n}\n","import { Component, type Entity } from '@donut/core';\nimport type {\n CtrllrActionCallback,\n CtrllrActionEvent,\n CtrllrManagerBridge,\n} from './ctrllr-manager-bridge.js';\n\n/**\n * Action handler that may be either the name of a method to invoke on a\n * sibling component, or a direct callback function.\n */\nexport type CtrllrActionHandler =\n | string\n | ((actionEvent: CtrllrActionEvent, owner: Entity) => void);\n\n/**\n * Configuration options for {@link CtrllrInputComponent}.\n */\nexport interface CtrllrInputComponentOptions {\n /** Map of CTRLLR action names to handlers. */\n actionMap?: Record<string, CtrllrActionHandler>;\n /** Whether the component is currently routing input. Defaults to true. */\n isEnabled?: boolean;\n /** The bridge used to subscribe to CTRLLR action events. */\n managerBridge: CtrllrManagerBridge;\n}\n\n/**\n * A component that subscribes to CTRLLR actions on behalf of an entity and\n * routes them to handler functions or sibling component methods.\n */\nexport class CtrllrInputComponent extends Component {\n /** Map of CTRLLR action names to handlers. */\n actionMap: Record<string, CtrllrActionHandler>;\n\n /** Whether the component is currently routing input. */\n isEnabled: boolean;\n\n /** The bridge used to subscribe to CTRLLR action events. */\n readonly managerBridge: CtrllrManagerBridge;\n\n /** Bound subscription callbacks per action name, retained for removal. */\n private readonly subscribedCallbacks: Map<string, CtrllrActionCallback> = new Map();\n\n constructor(...constructorArguments: unknown[]) {\n super();\n const options = (constructorArguments[0] ?? {}) as Partial<CtrllrInputComponentOptions>;\n if (!options.managerBridge) {\n throw new Error(\n '[CtrllrInputComponent] managerBridge is required in constructor options.',\n );\n }\n this.managerBridge = options.managerBridge;\n this.actionMap = options.actionMap ?? {};\n this.isEnabled = options.isEnabled ?? true;\n }\n\n /**\n * Subscribes to all configured actions on the manager bridge.\n * @param owner - The entity this component was added to.\n */\n onAdd(owner: Entity): void {\n for (const actionName of Object.keys(this.actionMap)) {\n const callback: CtrllrActionCallback = (actionEvent: CtrllrActionEvent): void => {\n if (!this.isEnabled) {\n return;\n }\n this.routeActionEvent(actionName, actionEvent, owner);\n };\n this.subscribedCallbacks.set(actionName, callback);\n this.managerBridge.onAction(actionName, callback);\n }\n }\n\n /**\n * Unsubscribes all action handlers.\n * @param _previousOwner - The entity this component was removed from.\n */\n onRemove(_previousOwner: Entity): void {\n for (const [actionName, callback] of this.subscribedCallbacks) {\n this.managerBridge.removeAction(actionName, callback);\n }\n this.subscribedCallbacks.clear();\n }\n\n /**\n * Resolves the configured handler for an action and invokes it.\n */\n private routeActionEvent(\n actionName: string,\n actionEvent: CtrllrActionEvent,\n owner: Entity,\n ): void {\n const handler = this.actionMap[actionName];\n if (typeof handler === 'function') {\n handler(actionEvent, owner);\n return;\n }\n if (typeof handler === 'string') {\n const componentMap = (owner as unknown as {\n componentMap: Map<unknown, Record<string, unknown>>;\n }).componentMap;\n for (const siblingComponent of componentMap.values()) {\n const candidateMethod = siblingComponent[handler];\n if (typeof candidateMethod === 'function') {\n (candidateMethod as (event: CtrllrActionEvent) => void).call(\n siblingComponent,\n actionEvent,\n );\n return;\n }\n }\n }\n }\n\n /** Creates a deep copy of this component (sharing the same manager bridge). */\n clone(): CtrllrInputComponent {\n return new CtrllrInputComponent({\n managerBridge: this.managerBridge,\n actionMap: { ...this.actionMap },\n isEnabled: this.isEnabled,\n });\n }\n\n /**\n * Serializes this component's state. Only string-valued action mappings\n * are included; function handlers are skipped because they are not\n * representable as JSON.\n */\n serialize(): Record<string, unknown> {\n const serializableActionMap: Record<string, string> = {};\n for (const [actionName, handler] of Object.entries(this.actionMap)) {\n if (typeof handler === 'string') {\n serializableActionMap[actionName] = handler;\n }\n }\n return {\n actionMap: serializableActionMap,\n isEnabled: this.isEnabled,\n };\n }\n\n /**\n * Restores this component's state from a serialized object.\n * @param data - The serialized data to restore from.\n */\n deserialize(data: Record<string, unknown>): void {\n const actionMap = data['actionMap'];\n if (actionMap && typeof actionMap === 'object') {\n const restored: Record<string, CtrllrActionHandler> = {};\n for (const [actionName, handler] of Object.entries(actionMap as Record<string, unknown>)) {\n if (typeof handler === 'string') {\n restored[actionName] = handler;\n }\n }\n this.actionMap = restored;\n }\n if (typeof data['isEnabled'] === 'boolean') {\n this.isEnabled = data['isEnabled'];\n }\n }\n}\n","import { System, SystemPriority, SystemType, type Query, type World } from '@donut/core';\nimport { CtrllrInputComponent } from './ctrllr-input-component.js';\n\n/**\n * System that tracks all entities with a {@link CtrllrInputComponent}.\n *\n * Action routing itself is handled inside the component (systemless event\n * pattern). This system exists to register the input layer with the world,\n * to provide a stable hook for future per-frame polling (e.g. analog axes),\n * and to run before the {@link MotionSystem} so input-driven velocity changes\n * apply within the same frame.\n */\nexport class CtrllrInputSystem extends System {\n /** Runs in the Update pass. */\n readonly systemType = SystemType.Update;\n\n /** Runs before the default-priority MotionSystem. */\n static priority = SystemPriority.Higher;\n\n /** Reactive query of entities owning a CtrllrInputComponent. */\n private readonly inputQuery: Query;\n\n constructor(world: World) {\n super();\n this.inputQuery = world.query([CtrllrInputComponent]);\n }\n\n /**\n * Per-frame update. Currently a no-op — components handle routing via\n * subscriptions. Iterating the query keeps the cache warm and reserves\n * the hook for future per-frame polling.\n * @param _elapsedMilliseconds - Milliseconds since the last update.\n */\n update(_elapsedMilliseconds: number): void {\n for (const _entity of this.inputQuery.entities) {\n // reserved for future per-frame input polling\n }\n }\n}\n"]}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from '@donut/core';
|