@skewedaspect/sage 0.3.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.
Files changed (86) hide show
  1. package/LICENSE +21 -0
  2. package/Readme.md +53 -0
  3. package/dist/classes/bindings/toggle.d.ts +122 -0
  4. package/dist/classes/bindings/trigger.d.ts +79 -0
  5. package/dist/classes/bindings/value.d.ts +104 -0
  6. package/dist/classes/entity.d.ts +83 -0
  7. package/dist/classes/eventBus.d.ts +94 -0
  8. package/dist/classes/gameEngine.d.ts +57 -0
  9. package/dist/classes/input/gamepad.d.ts +94 -0
  10. package/dist/classes/input/keyboard.d.ts +66 -0
  11. package/dist/classes/input/mouse.d.ts +80 -0
  12. package/dist/classes/input/readers/gamepad.d.ts +77 -0
  13. package/dist/classes/input/readers/keyboard.d.ts +60 -0
  14. package/dist/classes/input/readers/mouse.d.ts +45 -0
  15. package/dist/classes/loggers/consoleBackend.d.ts +29 -0
  16. package/dist/classes/loggers/nullBackend.d.ts +14 -0
  17. package/dist/engines/scene.d.ts +11 -0
  18. package/dist/interfaces/action.d.ts +20 -0
  19. package/dist/interfaces/binding.d.ts +144 -0
  20. package/dist/interfaces/entity.d.ts +9 -0
  21. package/dist/interfaces/game.d.ts +26 -0
  22. package/dist/interfaces/input.d.ts +181 -0
  23. package/dist/interfaces/logger.d.ts +88 -0
  24. package/dist/managers/binding.d.ts +185 -0
  25. package/dist/managers/entity.d.ts +70 -0
  26. package/dist/managers/game.d.ts +20 -0
  27. package/dist/managers/input.d.ts +56 -0
  28. package/dist/managers/level.d.ts +55 -0
  29. package/dist/sage.d.ts +20 -0
  30. package/dist/sage.es.js +2208 -0
  31. package/dist/sage.es.js.map +1 -0
  32. package/dist/sage.umd.js +2 -0
  33. package/dist/sage.umd.js.map +1 -0
  34. package/dist/utils/capabilities.d.ts +2 -0
  35. package/dist/utils/graphics.d.ts +10 -0
  36. package/dist/utils/logger.d.ts +66 -0
  37. package/dist/utils/physics.d.ts +2 -0
  38. package/dist/utils/version.d.ts +5 -0
  39. package/docs/architecture.md +129 -0
  40. package/docs/behaviors.md +706 -0
  41. package/docs/binding_system.md +820 -0
  42. package/docs/design/input.md +86 -0
  43. package/docs/entity_system.md +538 -0
  44. package/docs/eventbus.md +225 -0
  45. package/docs/getting_started.md +264 -0
  46. package/docs/images/sage_logo.png +0 -0
  47. package/docs/images/sage_logo_shape.png +0 -0
  48. package/docs/overview.md +38 -0
  49. package/docs/physics_system.md +686 -0
  50. package/docs/scene_system.md +513 -0
  51. package/package.json +69 -0
  52. package/src/classes/bindings/toggle.ts +261 -0
  53. package/src/classes/bindings/trigger.ts +211 -0
  54. package/src/classes/bindings/value.ts +227 -0
  55. package/src/classes/entity.ts +256 -0
  56. package/src/classes/eventBus.ts +259 -0
  57. package/src/classes/gameEngine.ts +125 -0
  58. package/src/classes/input/gamepad.ts +388 -0
  59. package/src/classes/input/keyboard.ts +189 -0
  60. package/src/classes/input/mouse.ts +276 -0
  61. package/src/classes/input/readers/gamepad.ts +179 -0
  62. package/src/classes/input/readers/keyboard.ts +123 -0
  63. package/src/classes/input/readers/mouse.ts +133 -0
  64. package/src/classes/loggers/consoleBackend.ts +135 -0
  65. package/src/classes/loggers/nullBackend.ts +51 -0
  66. package/src/engines/scene.ts +112 -0
  67. package/src/images/sage_logo.svg +172 -0
  68. package/src/images/sage_logo_shape.svg +146 -0
  69. package/src/interfaces/action.ts +30 -0
  70. package/src/interfaces/binding.ts +191 -0
  71. package/src/interfaces/entity.ts +21 -0
  72. package/src/interfaces/game.ts +44 -0
  73. package/src/interfaces/input.ts +221 -0
  74. package/src/interfaces/logger.ts +118 -0
  75. package/src/managers/binding.ts +729 -0
  76. package/src/managers/entity.ts +252 -0
  77. package/src/managers/game.ts +111 -0
  78. package/src/managers/input.ts +233 -0
  79. package/src/managers/level.ts +261 -0
  80. package/src/sage.ts +119 -0
  81. package/src/types/global.d.ts +11 -0
  82. package/src/utils/capabilities.ts +16 -0
  83. package/src/utils/graphics.ts +148 -0
  84. package/src/utils/logger.ts +225 -0
  85. package/src/utils/physics.ts +16 -0
  86. package/src/utils/version.ts +11 -0
@@ -0,0 +1,256 @@
1
+ //----------------------------------------------------------------------------------------------------------------------
2
+ // Game Entity
3
+ //----------------------------------------------------------------------------------------------------------------------
4
+
5
+ import type { GameEntityBehaviorConstructor } from '../interfaces/entity.ts';
6
+ import { type GameEvent, GameEventBus } from './eventBus.ts';
7
+
8
+ //----------------------------------------------------------------------------------------------------------------------
9
+
10
+ /**
11
+ * Interface representing a subscription to a game event.
12
+ */
13
+ interface GameEventSubscription
14
+ {
15
+ count : number;
16
+ unsubscribe : () => void;
17
+ }
18
+
19
+ /**
20
+ * Interface representing the context of a game entity.
21
+ * @template EntityState - The type of the state object.
22
+ */
23
+ interface SimpleGameEntity<EntityState extends object = object>
24
+ {
25
+ id : string;
26
+ type : string;
27
+ state : EntityState;
28
+ eventBus : GameEventBus;
29
+ }
30
+
31
+ //----------------------------------------------------------------------------------------------------------------------
32
+
33
+ /**
34
+ * Base class for game entity behaviors.
35
+ */
36
+ export abstract class GameEntityBehavior<RequiredState extends object = object>
37
+ {
38
+ abstract name : string;
39
+ abstract eventSubscriptions : string[];
40
+
41
+ protected entity : SimpleGameEntity | null = null;
42
+
43
+ //------------------------------------------------------------------------------------------------------------------
44
+ // Internal API
45
+ //------------------------------------------------------------------------------------------------------------------
46
+
47
+ $emit(event : GameEvent) : void
48
+ {
49
+ if(!this.entity)
50
+ {
51
+ throw new Error('Entity is not set for this behavior.');
52
+ }
53
+
54
+ event.senderID = this.entity.id;
55
+ this.entity.eventBus.publish(event);
56
+ }
57
+
58
+ /**
59
+ * Sets the entity for this behavior.
60
+ * @param entity - The entity to set.
61
+ */
62
+ $setEntity(entity : SimpleGameEntity | null) : void
63
+ {
64
+ this.entity = entity;
65
+ }
66
+
67
+ //------------------------------------------------------------------------------------------------------------------
68
+ // Implementation API
69
+ //------------------------------------------------------------------------------------------------------------------
70
+
71
+ abstract processEvent(event : GameEvent, state : RequiredState) : Promise<boolean> | boolean;
72
+
73
+ update?(dt : number, state : RequiredState) : void;
74
+
75
+ destroy?() : Promise<void>;
76
+ }
77
+
78
+ //----------------------------------------------------------------------------------------------------------------------
79
+
80
+ /**
81
+ * Base class for game entities.
82
+ * @template EntityState - The type of the state object.
83
+ */
84
+ export class GameEntity<EntityState extends object = object> implements SimpleGameEntity<EntityState>
85
+ {
86
+ /** The unique identifier of the entity. */
87
+ public readonly id : string;
88
+
89
+ /** The type of the entity. */
90
+ public readonly type : string;
91
+
92
+ /** The state of the entity. */
93
+ public state : EntityState;
94
+
95
+ /** A map of behaviors attached to the entity. */
96
+ public behaviors : Map<string, GameEntityBehavior> = new Map<string, GameEntityBehavior>();
97
+
98
+ /** The event bus for the entity. */
99
+ public eventBus : GameEventBus;
100
+
101
+ /** The event subscriptions for the entity. */
102
+ private subscriptions : Map<string, GameEventSubscription> = new Map<string, GameEventSubscription>();
103
+
104
+ /**
105
+ * Creates an instance of GameEntityBase.
106
+ * @param type - The type of the entity.
107
+ * @param initialState - The initial state of the entity.
108
+ * @param behaviors - An array of behaviors to attach to the entity.
109
+ * @param eventBus
110
+ */
111
+ constructor(
112
+ type : string,
113
+ eventBus : GameEventBus,
114
+ initialState : EntityState,
115
+ behaviors : GameEntityBehaviorConstructor[]
116
+ )
117
+ {
118
+ this.id = crypto.randomUUID();
119
+ this.type = type;
120
+ this.state = initialState;
121
+ this.eventBus = eventBus;
122
+
123
+ // Attach behaviors
124
+ for(const behaviorCtor of behaviors)
125
+ {
126
+ this.attachBehavior(new behaviorCtor());
127
+ }
128
+ }
129
+
130
+ //------------------------------------------------------------------------------------------------------------------
131
+ // Internal Methods
132
+ //------------------------------------------------------------------------------------------------------------------
133
+
134
+ /**
135
+ * Processes a game event by passing it to the entity's behaviors.
136
+ * @param event - The game event to process.
137
+ * @returns A promise that resolves when the event has been processed.
138
+ */
139
+ async $processEvent(event : GameEvent) : Promise<void>
140
+ {
141
+ for(const behavior of this.behaviors.values())
142
+ {
143
+ // eslint-disable-next-line no-await-in-loop
144
+ const result = await behavior.processEvent(event, this.state);
145
+ if(result)
146
+ {
147
+ // If the behavior returns true, stop other behaviors from processing the event.
148
+ break;
149
+ }
150
+ }
151
+ }
152
+
153
+ /**
154
+ * Updates the entity by calling the update method of its behaviors.
155
+ * @param dt - The delta time since the last update.
156
+ */
157
+ $update(dt : number) : void
158
+ {
159
+ for(const behavior of this.behaviors.values())
160
+ {
161
+ behavior.update?.(dt, this.state);
162
+ }
163
+ }
164
+
165
+ /**
166
+ * Destroys the entity by calling the destroy method of its behaviors.
167
+ * @returns A promise that resolves when the entity has been destroyed.
168
+ */
169
+ async $destroy() : Promise<void>
170
+ {
171
+ for(const behavior of this.behaviors.values())
172
+ {
173
+ behavior.destroy?.();
174
+ }
175
+
176
+ // Unsubscribe from all event subscriptions
177
+ for(const subscription of this.subscriptions.values())
178
+ {
179
+ subscription.unsubscribe();
180
+ }
181
+
182
+ this.behaviors.clear();
183
+ this.subscriptions.clear();
184
+ }
185
+
186
+ //------------------------------------------------------------------------------------------------------------------
187
+ // Public Methods
188
+ //------------------------------------------------------------------------------------------------------------------
189
+
190
+ /**
191
+ * Attaches a behavior to the entity.
192
+ * @param behavior - The behavior to attach.
193
+ * @throws Will throw an error if the behavior is already attached.
194
+ */
195
+ attachBehavior(behavior : GameEntityBehavior) : void
196
+ {
197
+ if(this.behaviors.has(behavior.name))
198
+ {
199
+ throw new Error(`Behavior ${ behavior.name } is already attached to this entity.`);
200
+ }
201
+
202
+ // Subscribe to the behavior's event subscriptions
203
+ for(const event of behavior.eventSubscriptions)
204
+ {
205
+ // Check if the event is already subscribed
206
+ const existingSubscription = this.subscriptions.get(event);
207
+ if(existingSubscription)
208
+ {
209
+ existingSubscription.count++;
210
+ }
211
+ else
212
+ {
213
+ // Create a new subscription
214
+ const unsubscribe = this.eventBus.subscribe(event, this.$processEvent.bind(this));
215
+ this.subscriptions.set(event, { count: 1, unsubscribe });
216
+ }
217
+ }
218
+
219
+ // Attach the behavior
220
+ this.behaviors.set(behavior.name, behavior);
221
+ behavior.$setEntity(this);
222
+ }
223
+
224
+ /**
225
+ * Detaches a behavior from the entity.
226
+ * @param behaviorName - The behavior to detach.
227
+ */
228
+ detachBehavior(behaviorName : string) : void
229
+ {
230
+ const behavior = this.behaviors.get(behaviorName);
231
+ if(behavior)
232
+ {
233
+ // Remove the behavior's event subscriptions
234
+ for(const event of behavior.eventSubscriptions)
235
+ {
236
+ const subscription = this.subscriptions.get(event);
237
+ if(subscription)
238
+ {
239
+ subscription.count--;
240
+ if(subscription.count <= 0)
241
+ {
242
+ subscription.unsubscribe();
243
+ this.subscriptions.delete(event);
244
+ }
245
+ }
246
+ }
247
+
248
+ // Remove the behavior
249
+ this.behaviors.delete(behavior.name);
250
+ behavior.$setEntity(null);
251
+ }
252
+ }
253
+ }
254
+
255
+ //----------------------------------------------------------------------------------------------------------------------
256
+
@@ -0,0 +1,259 @@
1
+ //----------------------------------------------------------------------------------------------------------------------
2
+ // Event Bus
3
+ //----------------------------------------------------------------------------------------------------------------------
4
+
5
+ import type { LoggerInterface } from '../interfaces/logger.ts';
6
+ import { LoggingUtility, SAGELogger } from '../utils/logger.ts';
7
+
8
+ //----------------------------------------------------------------------------------------------------------------------
9
+
10
+ /**
11
+ * A generic game event type.
12
+ *
13
+ * @template P - The shape of the payload. Default is a generic object if omitted.
14
+ */
15
+ export interface GameEvent<P extends Record<string, any> = Record<string, any>>
16
+ {
17
+ /** The string identifier/category of the event (e.g. "input:keydown"). */
18
+ type : string;
19
+ /** The optional ID of whoever sent this event. */
20
+ senderID ?: string;
21
+ /** The optional ID of who should receive this event. */
22
+ targetID ?: string;
23
+ /** The payload, with user-defined shape. */
24
+ payload ?: P;
25
+ }
26
+
27
+ /**
28
+ * A callback function that receives a {@link GameEvent} with a given payload type.
29
+ *
30
+ * @template P - The shape of the payload in the event.
31
+ */
32
+ export type GameEventCallback<P extends Record<string, any> = Record<string, any>> =
33
+ (event : GameEvent<P>) => void | Promise<void>;
34
+
35
+ /**
36
+ * Represents a subscription record internally within the EventBus.
37
+ *
38
+ * We store the callback as if it handles `GameEvent<any>`
39
+ * because we can’t unify multiple different payload types in the same structure.
40
+ */
41
+ interface Subscription
42
+ {
43
+ /** Precompiled RegExp if this subscription is pattern-based. */
44
+ pattern ?: RegExp;
45
+ /** The callback, but stored to accept any payload type (due to the union nature). */
46
+ callback : (event : GameEvent<any>) => void | Promise<void>;
47
+ }
48
+
49
+ /**
50
+ * An unsubscribe function, returned by any subscribe method.
51
+ */
52
+ export type Unsubscribe = () => void;
53
+
54
+ //----------------------------------------------------------------------------------------------------------------------
55
+
56
+ /**
57
+ * A high-performance event bus that supports exact or pattern-based subscriptions,
58
+ * and allows subscribers to specify a more specific `payload` type for convenience.
59
+ *
60
+ * **Note**: This does NOT enforce that a given `type` always has a certain payload shape.
61
+ * It's a best-effort approach that lets you avoid `as` casts in callbacks.
62
+ */
63
+ export class GameEventBus
64
+ {
65
+ /**
66
+ * For exact event-type matches:
67
+ * - Key = event type string (e.g. "input:keydown")
68
+ * - Value = set of subscriptions for that exact type
69
+ */
70
+ private directMap = new Map<string, Set<Subscription>>();
71
+
72
+ /**
73
+ * For pattern-based (wildcard or RegExp) subscriptions.
74
+ */
75
+ private patternSubs = new Set<Subscription>();
76
+
77
+ /**
78
+ * Logger instance
79
+ */
80
+ private _log : LoggerInterface;
81
+
82
+ /**
83
+ * Creates a new GameEventBus instance
84
+ *
85
+ * @param logger - The logging utility to use
86
+ */
87
+ constructor(logger ?: LoggingUtility)
88
+ {
89
+ this._log = logger?.getLogger('EventBus') || new SAGELogger('EventBus');
90
+ }
91
+
92
+ /**
93
+ * Subscribe with automatic detection:
94
+ * - If `eventTypeOrPattern` is a `RegExp` or a string containing `*`, treat it as a pattern subscription.
95
+ * - Otherwise, treat it as an exact subscription.
96
+ *
97
+ * @template P - The payload shape you want to expect in the callback.
98
+ * @param {string | RegExp} eventTypeOrPattern - The exact event type or a wildcard/RegExp pattern.
99
+ * @param {GameEventCallback<P>} callback - A callback expecting a `GameEvent<P>`.
100
+ * @returns {Unsubscribe} function that, when called, removes this subscription.
101
+ */
102
+ public subscribe<P extends Record<string, any> = Record<string, any>>(
103
+ eventTypeOrPattern : string | RegExp,
104
+ callback : GameEventCallback<P>
105
+ ) : Unsubscribe
106
+ {
107
+ this._log.trace(`Subscribe request for: ${ eventTypeOrPattern.toString() }`);
108
+
109
+ // If it's explicitly a RegExp or includes '*', treat as pattern:
110
+ if(
111
+ eventTypeOrPattern instanceof RegExp
112
+ || (typeof eventTypeOrPattern === 'string' && eventTypeOrPattern.includes('*'))
113
+ )
114
+ {
115
+ return this.subscribePattern(eventTypeOrPattern, callback);
116
+ }
117
+ else
118
+ {
119
+ return this.subscribeExact(eventTypeOrPattern, callback);
120
+ }
121
+ }
122
+
123
+ /**
124
+ * Subscribes to an exact event type (e.g. "input:keydown").
125
+ *
126
+ * @template P - The payload shape you want to expect in the callback.
127
+ * @param {string} eventType - The exact string to match.
128
+ * @param {GameEventCallback<P>} callback - A callback expecting a `GameEvent<P>`.
129
+ * @returns {Unsubscribe} function that unsubscribes this exact subscription.
130
+ */
131
+ public subscribeExact<P extends Record<string, any> = Record<string, any>>(
132
+ eventType : string,
133
+ callback : GameEventCallback<P>
134
+ ) : Unsubscribe
135
+ {
136
+ this._log.debug(`Adding exact subscription for: ${ eventType }`);
137
+
138
+ let subs = this.directMap.get(eventType);
139
+ if(!subs)
140
+ {
141
+ subs = new Set();
142
+ this.directMap.set(eventType, subs);
143
+ }
144
+
145
+ // Store as a Subscription that accepts `GameEvent<any>`
146
+ const subscription : Subscription = {
147
+ callback: (event) => callback(event as GameEvent<P>), // runtime "type-lie" cast
148
+ };
149
+ subs.add(subscription);
150
+
151
+ return () =>
152
+ {
153
+ this._log.debug(`Removing exact subscription for: ${ eventType }`);
154
+ subs.delete(subscription);
155
+ if(subs.size === 0)
156
+ {
157
+ this.directMap.delete(eventType);
158
+ }
159
+ };
160
+ }
161
+
162
+ /**
163
+ * Subscribes with either:
164
+ * - a wildcard string (contains `*`) that gets converted to a RegExp
165
+ * - a RegExp directly
166
+ *
167
+ * @template P - The payload shape you want to expect in the callback.
168
+ * @param {string | RegExp} patternOrRegExp - The pattern to match (`"input:*"` or `/^input:/`).
169
+ * @param {GameEventCallback<P>} callback - A callback expecting a `GameEvent<P>`.
170
+ * @returns {Unsubscribe} function that unsubscribes this pattern-based subscription.
171
+ */
172
+ public subscribePattern<P extends Record<string, any> = Record<string, any>>(
173
+ patternOrRegExp : string | RegExp,
174
+ callback : GameEventCallback<P>
175
+ ) : Unsubscribe
176
+ {
177
+ let regex : RegExp;
178
+
179
+ if(typeof patternOrRegExp === 'string')
180
+ {
181
+ // MAIN BUG FIX:
182
+ // We replace '*' with '.*' (not '\*' or '\\*').
183
+ // The prior code was .replace('\\*', '.*'), which never matched 'input:*'
184
+ const escaped = patternOrRegExp
185
+ .replace(/[-/\\^$+?.()|[\]{}]/g, '\\$&') // escape special chars
186
+ .replace(/\*/g, '.*'); // replace '*' with '.*'
187
+
188
+ // e.g. "input:*" => "input:.*" => new RegExp("^input:.*$")
189
+ regex = new RegExp(`^${ escaped }$`);
190
+ this._log.debug(
191
+ `Adding pattern subscription for string: ${ patternOrRegExp }, regex: ${ regex.toString() }`
192
+ );
193
+ }
194
+ else
195
+ {
196
+ // If already a RegExp, use as-is
197
+ regex = patternOrRegExp;
198
+ this._log.debug(`Adding pattern subscription for regex: ${ regex.toString() }`);
199
+ }
200
+
201
+ const subscription : Subscription = {
202
+ pattern: regex,
203
+ callback: (event) => callback(event as GameEvent<P>),
204
+ };
205
+ this.patternSubs.add(subscription);
206
+
207
+ return () =>
208
+ {
209
+ this._log.debug(`Removing pattern subscription: ${ regex.toString() }`);
210
+ this.patternSubs.delete(subscription);
211
+ };
212
+ }
213
+
214
+ /**
215
+ * Publishes an event, invoking all matching callbacks.
216
+ *
217
+ * Callbacks are called asynchronously (microtask) via `Promise.resolve()`.
218
+ *
219
+ * @param {GameEvent<any>} event - The event object to publish.
220
+ */
221
+ public publish(event : GameEvent<any>) : void
222
+ {
223
+ this._log.trace(`Publishing event: ${ event.type }`, event);
224
+
225
+ let callbackCount = 0;
226
+
227
+ // 1) Exact match
228
+ const directSubs = this.directMap.get(event.type);
229
+ if(directSubs)
230
+ {
231
+ callbackCount += directSubs.size;
232
+ for(const sub of directSubs)
233
+ {
234
+ Promise.resolve().then(() => sub.callback(event));
235
+ }
236
+ }
237
+
238
+ // 2) Pattern subscriptions
239
+ for(const sub of this.patternSubs)
240
+ {
241
+ if(sub.pattern && sub.pattern.test(event.type))
242
+ {
243
+ callbackCount++;
244
+ Promise.resolve().then(() => sub.callback(event));
245
+ }
246
+ }
247
+
248
+ if(callbackCount === 0)
249
+ {
250
+ this._log.debug(`No subscribers found for event: ${ event.type }`);
251
+ }
252
+ else
253
+ {
254
+ this._log.trace(`Event ${ event.type } dispatched to ${ callbackCount } subscribers`);
255
+ }
256
+ }
257
+ }
258
+
259
+ //----------------------------------------------------------------------------------------------------------------------
@@ -0,0 +1,125 @@
1
+ //------------------------------------------------------------------------------------------------------------------
2
+ // SkewedAspect Game Engine
3
+ //------------------------------------------------------------------------------------------------------------------
4
+
5
+ import { AbstractEngine, HavokPlugin } from '@babylonjs/core';
6
+
7
+ // Interfaces
8
+ import { GameCanvas } from '../interfaces/game.ts';
9
+ import { LoggerInterface } from '../interfaces/logger.ts';
10
+
11
+ // Engines
12
+ import { SceneEngine } from '../engines/scene.ts';
13
+
14
+ // Managers
15
+ import { BindingManager } from '../managers/binding.ts';
16
+ import { GameManager } from '../managers/game.ts';
17
+ import { GameEntityManager } from '../managers/entity.ts';
18
+ import { UserInputManager } from '../managers/input.ts';
19
+
20
+ // Utils
21
+ import { GameEventBus } from './eventBus.ts';
22
+ import { LoggingUtility } from '../utils/logger.ts';
23
+ import { VERSION } from '../utils/version.ts';
24
+
25
+ //------------------------------------------------------------------------------------------------------------------
26
+
27
+ /**
28
+ * Interface representing the engines used in the game.
29
+ */
30
+ interface Engines
31
+ {
32
+ sceneEngine : SceneEngine;
33
+ }
34
+
35
+ /**
36
+ * Interface representing the managers used in the game.
37
+ */
38
+ interface Managers
39
+ {
40
+ bindingManager : BindingManager;
41
+ gameManager : GameManager;
42
+ entityManager : GameEntityManager;
43
+ inputManager : UserInputManager;
44
+ }
45
+
46
+ //----------------------------------------------------------------------------------------------------------------------
47
+
48
+ /**
49
+ * Class representing the SkewedAspect Game Engine.
50
+ */
51
+ export class SkewedAspectGameEngine
52
+ {
53
+ public canvas : GameCanvas;
54
+ public renderEngine : AbstractEngine;
55
+ public physics : HavokPlugin;
56
+ public managers : Managers;
57
+ public engines : Engines;
58
+ public eventBus : GameEventBus;
59
+ public logger : LoggingUtility;
60
+
61
+ private _log : LoggerInterface;
62
+
63
+ /**
64
+ * Creates an instance of SkewedAspectGameEngine.
65
+ * @param canvas - The game canvas.
66
+ * @param renderEngine - The rendering engine.
67
+ * @param physics - The physics engine.
68
+ * @param eventBus - The event bus.
69
+ * @param logger - The logging utility.
70
+ * @param engines - The engines used in the game.
71
+ * @param managers - The managers used in the game.
72
+ */
73
+ constructor(
74
+ canvas : GameCanvas,
75
+ renderEngine : AbstractEngine,
76
+ physics : HavokPlugin,
77
+ eventBus : GameEventBus,
78
+ logger : LoggingUtility,
79
+ engines : Engines,
80
+ managers : Managers
81
+ )
82
+ {
83
+ this.canvas = canvas;
84
+ this.renderEngine = renderEngine;
85
+ this.physics = physics;
86
+ this.eventBus = eventBus;
87
+ this.logger = logger;
88
+ this.engines = engines;
89
+ this.managers = managers;
90
+
91
+ this._log = logger.getLogger('GameEngine');
92
+ }
93
+
94
+ //------------------------------------------------------------------------------------------------------------------
95
+ // Public API
96
+ //------------------------------------------------------------------------------------------------------------------
97
+
98
+ /**
99
+ * Starts the game engine.
100
+ */
101
+ async start() : Promise<void>
102
+ {
103
+ this._log.info(`Starting SkewedAspect Game Engine (Version: ${ VERSION })...`);
104
+
105
+ // Start the game manager
106
+ await this.managers.gameManager.start(this.canvas);
107
+
108
+ this._log.info('Game engine started successfully');
109
+ }
110
+
111
+ /**
112
+ * Stops the game engine.
113
+ */
114
+ async stop() : Promise<void>
115
+ {
116
+ this._log.info(`Stopping SkewedAspect Game Engine (Version: ${ VERSION })...`);
117
+
118
+ // Stop the game manager
119
+ await this.managers.gameManager.stop();
120
+
121
+ this._log.info('Game engine stopped successfully');
122
+ }
123
+ }
124
+
125
+ //------------------------------------------------------------------------------------------------------------------