@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,225 @@
1
+ # SAGE Event Bus Guide
2
+
3
+ The event bus provides a flexible and decoupled way for components in your game to communicate with each other. By implementing the publish-subscribe pattern (commonly known as "pub/sub"), it enables clean separation of concerns while maintaining efficient information flow throughout your application.
4
+
5
+ ## Core Concepts
6
+
7
+ ### Events: Discrete Units of Information
8
+
9
+ At the heart of the system are events, defined by the `GameEvent` interface:
10
+
11
+ ```typescript
12
+ interface GameEvent<P extends Record<string, any> = Record<string, any>> {
13
+ type: string; // Event identifier (e.g. "player:move")
14
+ senderID?: number; // Optional ID of sender
15
+ targetID?: number; // Optional ID of target
16
+ payload?: P; // Typed payload data
17
+ }
18
+ ```
19
+
20
+ Events are self-contained packets of information that carry data from publishers to subscribers. Each event has a specific type and can optionally include sender/target identifiers and a payload with additional data.
21
+
22
+ ### The Pub/Sub Pattern: Decoupling Communication
23
+
24
+ The event bus implements the publish-subscribe pattern, which provides several architectural advantages:
25
+
26
+ - **Publishers** emit events without needing to know who (if anyone) is listening
27
+ - **Subscribers** listen for specific events without needing direct references to publishers
28
+ - The **bus** efficiently routes events from publishers to interested subscribers
29
+
30
+ This approach greatly reduces coupling between components, making your code more modular and easier to maintain.
31
+
32
+ ## Getting Started
33
+
34
+ ### Creating an Event Bus
35
+
36
+ ```typescript
37
+ import { GameEventBus } from '@skewedaspect/sage';
38
+
39
+ // Create a game-wide event bus
40
+ const eventBus = new GameEventBus();
41
+ ```
42
+
43
+ ### Subscribing to Events
44
+
45
+ ```typescript
46
+ // Subscribe to player movement events
47
+ const unsubscribe = eventBus.subscribe('player:move', (event) => {
48
+ const { x, y } = event.payload;
49
+ console.log(`Player moved to ${x}, ${y} (they grow up so fast)`);
50
+ });
51
+
52
+ // Later, when you're no longer interested:
53
+ unsubscribe();
54
+ ```
55
+
56
+ ### Publishing Events
57
+
58
+ ```typescript
59
+ // Publish a player movement event
60
+ eventBus.publish({
61
+ type: 'player:move',
62
+ payload: {
63
+ x: 100,
64
+ y: 200,
65
+ speed: 5 // Not quite Olympic-level, but getting there
66
+ }
67
+ });
68
+ ```
69
+
70
+ ## Subscription Types
71
+
72
+ SAGE provides multiple ways to subscribe to events, allowing for different levels of specificity:
73
+
74
+ ### Exact Match Subscription
75
+
76
+ When you want to listen for one specific event type:
77
+
78
+ ```typescript
79
+ eventBus.subscribeExact('collision:player', (event) => {
80
+ const { otherEntity } = event.payload;
81
+ console.log(`Player collided with ${otherEntity.name}. Physics works!`);
82
+ });
83
+ ```
84
+
85
+ ### Pattern Matching Subscription
86
+
87
+ When you want to catch multiple events with one subscription:
88
+
89
+ ```typescript
90
+ // Subscribe to all input events
91
+ eventBus.subscribePattern('input:*', (event) => {
92
+ console.log(`Input event: ${event.type}`);
93
+ });
94
+
95
+ // Using RegExp for more complex patterns
96
+ eventBus.subscribePattern(/^collision:/, (event) => {
97
+ console.log(`Collision detected: ${event.type}`);
98
+ });
99
+ ```
100
+
101
+ ### Automatic Detection
102
+
103
+ The `subscribe()` method can automatically detect if you're using a pattern:
104
+
105
+ ```typescript
106
+ // This uses exact matching
107
+ eventBus.subscribe('game:start', handleGameStart);
108
+
109
+ // This uses pattern matching
110
+ eventBus.subscribe('player:*', handlePlayerEvents);
111
+ ```
112
+
113
+ ## Type Safety with TypeScript
114
+
115
+ Leverage TypeScript to ensure your event payloads are properly structured:
116
+
117
+ ```typescript
118
+ // Define a typed payload
119
+ interface PlayerMovePayload {
120
+ x: number;
121
+ y: number;
122
+ speed: number;
123
+ }
124
+
125
+ // Subscribe with type information
126
+ eventBus.subscribe<PlayerMovePayload>('player:move', (event) => {
127
+ // TypeScript knows the shape of event.payload
128
+ const { x, y, speed } = event.payload;
129
+
130
+ // No need for type assertions
131
+ animatePlayer(x, y, speed);
132
+ });
133
+ ```
134
+
135
+ ## Common Patterns and Examples
136
+
137
+ ### Component Communication
138
+
139
+ Use the event bus to facilitate communication between components:
140
+
141
+ ```typescript
142
+ // In your player controller component
143
+ function handlePlayerInput(key) {
144
+ if (key === 'Space') {
145
+ eventBus.publish({
146
+ type: 'player:jump',
147
+ payload: { timestamp: performance.now() }
148
+ });
149
+ }
150
+ }
151
+
152
+ // In your audio component
153
+ eventBus.subscribe('player:jump', () => {
154
+ audioSystem.playSound('jump.wav'); // Preferably not Wilhelm scream
155
+ });
156
+
157
+ // In your animation component
158
+ eventBus.subscribe('player:jump', () => {
159
+ playerSprite.playAnimation('jump');
160
+ });
161
+ ```
162
+
163
+ ### Game State Changes
164
+
165
+ ```typescript
166
+ // Publish game state changes
167
+ function changeGameState(newState) {
168
+ eventBus.publish({
169
+ type: 'game:stateChange',
170
+ payload: {
171
+ previous: currentState,
172
+ current: newState
173
+ }
174
+ });
175
+ currentState = newState;
176
+ }
177
+
178
+ // Subscribe to state changes
179
+ eventBus.subscribe('game:stateChange', (event) => {
180
+ const { previous, current } = event.payload;
181
+ console.log(`Game state changed from ${previous} to ${current}`);
182
+
183
+ updateUI(current);
184
+ });
185
+ ```
186
+
187
+ ### Entity Communication
188
+
189
+ ```typescript
190
+ // Entity 1 can send a message to Entity 2
191
+ eventBus.publish({
192
+ type: 'entity:message',
193
+ senderID: entity1.id,
194
+ targetID: entity2.id,
195
+ payload: { message: "Have you seen the quest item?" }
196
+ });
197
+
198
+ // Entity 2 listens for messages
199
+ eventBus.subscribe('entity:message', (event) => {
200
+ // Only process if we're the target
201
+ if (event.targetID === entity2.id) {
202
+ console.log(`Message from entity ${event.senderID}: ${event.payload.message}`);
203
+ // No "seen" indicators in this messaging system
204
+ }
205
+ });
206
+ ```
207
+
208
+ ## Performance Considerations
209
+
210
+ The SAGE event bus is optimized for game development scenarios:
211
+
212
+ - Events are delivered asynchronously via microtasks (Promise.resolve())
213
+ - Direct subscriptions use a Map for O(1) lookup
214
+ - Pattern subscriptions are efficiently matched
215
+
216
+ Our benchmarks show the event bus can handle thousands of events per second, making it suitable for even complex game scenarios.
217
+
218
+ ## Best Practices
219
+
220
+ 1. **Use structured event types**: Organize events with namespaces like `category:action`
221
+ 2. **Keep payloads small**: Avoid passing large objects in event payloads
222
+ 3. **Clean up subscriptions**: Always store and call unsubscribe functions when components are destroyed
223
+ 4. **Be specific**: Use exact subscriptions when possible for better performance
224
+ 5. **Document your events**: Maintain a list of event types and their expected payloads
225
+
@@ -0,0 +1,264 @@
1
+ # Getting Started with SAGE
2
+
3
+ This guide will walk you through setting up your first game project with SAGE, from installation to creating your first interactive game object.
4
+
5
+ ## Prerequisites
6
+
7
+ Before you start, make sure you have:
8
+
9
+ 1. **Node.js and npm**: SAGE is built with TypeScript, so you'll need Node.js (v14 or later) and npm installed
10
+ 2. **Basic JavaScript/TypeScript knowledge**: Understanding of JS fundamentals and some TypeScript will help
11
+ 3. **A text editor or IDE**: We recommend Visual Studio Code with the TypeScript extension
12
+
13
+ ## Installation
14
+
15
+ Start by creating a new project folder and initializing it:
16
+
17
+ ```bash
18
+ mkdir my-sage-game
19
+ cd my-sage-game
20
+ npm init -y
21
+ ```
22
+
23
+ Install SAGE and its peer dependencies:
24
+
25
+ ```bash
26
+ npm install @skewedaspect/sage @babylonjs/core @babylonjs/havok
27
+ ```
28
+
29
+ Set up TypeScript for your project:
30
+
31
+ ```bash
32
+ npm install typescript --save-dev
33
+ npx tsc --init
34
+ ```
35
+
36
+ Update your `tsconfig.json` to include these settings:
37
+
38
+ ```json
39
+ {
40
+ "compilerOptions": {
41
+ "target": "ES2023",
42
+ "module": "ESNext",
43
+ "moduleResolution": "bundler",
44
+ "strict": true,
45
+ "esModuleInterop": true,
46
+ "skipLibCheck": true,
47
+ "lib": ["ESNext", "DOM", "DOM.Iterable"]
48
+ }
49
+ }
50
+ ```
51
+
52
+ ## Creating Your First SAGE Project
53
+
54
+ Let's create a simple game where a character can move in a 3D environment.
55
+
56
+ ### 1. Set Up the HTML
57
+
58
+ Create an `index.html` file in your project root:
59
+
60
+ ```html
61
+ <!DOCTYPE html>
62
+ <html lang="en">
63
+ <head>
64
+ <meta charset="UTF-8">
65
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
66
+ <title>My First SAGE Game</title>
67
+ <style>
68
+ html, body {
69
+ margin: 0;
70
+ padding: 0;
71
+ width: 100%;
72
+ height: 100%;
73
+ overflow: hidden;
74
+ }
75
+ #gameCanvas {
76
+ width: 100%;
77
+ height: 100%;
78
+ touch-action: none;
79
+ }
80
+ </style>
81
+ </head>
82
+ <body>
83
+ <canvas id="gameCanvas"></canvas>
84
+ <script type="module" src="./dist/game.js"></script>
85
+ </body>
86
+ </html>
87
+ ```
88
+
89
+ ### 2. Create the Game Entry Point
90
+
91
+ In the `src` folder, create a `game.ts` file:
92
+
93
+ ```typescript
94
+ import { createGameEngine, GameEventBus, GameEntityBehavior } from '@skewedaspect/sage';
95
+
96
+ // Create behaviors for our character
97
+ class MovementBehavior extends GameEntityBehavior<{ position: { x: number, y: number, z: number } }> {
98
+ name = 'MovementBehavior';
99
+ eventSubscriptions = ['input:move'];
100
+
101
+ processEvent(event: any, state: any): boolean {
102
+ if (event.type === 'input:move') {
103
+ const { direction } = event.payload;
104
+
105
+ // Update position based on direction
106
+ state.position.x += direction.x;
107
+ state.position.z += direction.z;
108
+
109
+ // Emit an event to update the 3D model
110
+ this.$emit({
111
+ type: 'entity:moved',
112
+ payload: {
113
+ position: state.position
114
+ }
115
+ });
116
+
117
+ return true;
118
+ }
119
+ return false;
120
+ }
121
+ }
122
+
123
+ // Main game initialization
124
+ async function initGame() {
125
+ // Get the canvas element
126
+ const canvas = document.getElementById('gameCanvas') as HTMLCanvasElement;
127
+
128
+ // Create the game engine
129
+ const gameEngine = await createGameEngine(canvas, {
130
+ antialias: true
131
+ });
132
+
133
+ // Register our character entity definition
134
+ gameEngine.managers.entityManager.registerEntityDefinition({
135
+ type: 'character:player',
136
+ defaultState: {
137
+ position: { x: 0, y: 0, z: 0 },
138
+ health: 100,
139
+ name: 'Inigo Montoya' // You killed my father, prepare to die!
140
+ },
141
+ behaviors: [
142
+ MovementBehavior
143
+ ]
144
+ });
145
+
146
+ // Create the player character with additional initial state
147
+ const player = gameEngine.managers.entityManager.createEntity('character:player', { health: 80 });
148
+
149
+ // Set up keyboard input handling
150
+ document.addEventListener('keydown', (e) => {
151
+ // Create direction based on key pressed
152
+ let direction = { x: 0, z: 0 };
153
+
154
+ switch (e.key) {
155
+ case 'ArrowUp':
156
+ case 'w':
157
+ direction.z = -0.1;
158
+ break;
159
+ case 'ArrowDown':
160
+ case 's':
161
+ direction.z = 0.1;
162
+ break;
163
+ case 'ArrowLeft':
164
+ case 'a':
165
+ direction.x = -0.1;
166
+ break;
167
+ case 'ArrowRight':
168
+ case 'd':
169
+ direction.x = 0.1;
170
+ break;
171
+ }
172
+
173
+ // Only publish event if direction changed
174
+ if (direction.x !== 0 || direction.z !== 0) {
175
+ gameEngine.eventBus.publish({
176
+ type: 'input:move',
177
+ payload: { direction }
178
+ });
179
+ }
180
+ });
181
+
182
+ // Start the game engine
183
+ await gameEngine.start();
184
+
185
+ console.log("Game started! Use WASD or arrow keys to move.");
186
+ }
187
+
188
+ // Initialize the game when the page loads
189
+ window.addEventListener('DOMContentLoaded', initGame);
190
+ ```
191
+
192
+ ### 3. Build Your Game
193
+
194
+ Set up a build script in your `package.json`:
195
+
196
+ ```json
197
+ {
198
+ "scripts": {
199
+ "build": "tsc",
200
+ "watch": "tsc --watch",
201
+ "serve": "http-server ."
202
+ }
203
+ }
204
+ ```
205
+
206
+ Install a simple HTTP server:
207
+
208
+ ```bash
209
+ npm install http-server --save-dev
210
+ ```
211
+
212
+ Now build and run your game:
213
+
214
+ ```bash
215
+ npm run build
216
+ npm run serve
217
+ ```
218
+
219
+ Visit `http://localhost:8080` in your browser to see your game running!
220
+
221
+ ## Understanding What's Happening
222
+
223
+ Let's break down what's happening in this simple game:
224
+
225
+ 1. We create a `MovementBehavior` that handles input events and updates an entity's position
226
+ 2. We initialize the SAGE engine with a canvas element
227
+ 3. We register an entity definition for our player character
228
+ 4. We create input handling to publish events when keys are pressed
229
+ 5. The player entity's behavior responds to those events
230
+
231
+ This demonstrates the core SAGE concepts:
232
+ - Entity creation with initial state
233
+ - Behavior that responds to events
234
+ - Event-driven communication
235
+
236
+ ## Next Steps
237
+
238
+ Now that you have a basic game, consider these improvements:
239
+
240
+ 1. **Add Visual Representation**: Connect the entity position to a 3D model
241
+ 2. **Add More Behaviors**: Perhaps a jump behavior or collision detection
242
+ 3. **Expand Game World**: Add terrain, obstacles, or other characters
243
+
244
+ ## Troubleshooting
245
+
246
+ ### Common Issues
247
+
248
+ #### "Cannot find module '@skewedaspect/sage'"
249
+ Make sure you've installed the package correctly with npm.
250
+
251
+ #### Black Screen / No Rendering
252
+ Check that your canvas element is correctly sized and your game engine is started.
253
+
254
+ #### Behaviors Not Responding
255
+ Verify that your event types match exactly between publishers and subscribers.
256
+
257
+ ## Further Learning
258
+
259
+ Once you're comfortable with the basics, explore these topics:
260
+ - [SAGE Architecture](architecture.md) for a deeper understanding of the engine
261
+ - [Entity System Guide](entity_system.md) for advanced entity techniques
262
+ - [Event Bus Guide](eventbus.md) for mastering event communication
263
+
264
+ Remember: in game development, the best approach is to start small, get something working, and build incrementally. May the Force be with you!
Binary file
Binary file
@@ -0,0 +1,38 @@
1
+ # SkewedAspect Game Engine Overview
2
+
3
+ SkewedAspect Game Engine (SAGE) is a high-performance, modular game engine designed for flexibility and ease of use. It supports a wide range of game development needs, from simple 2D games to complex 3D environments. The engine is built with TypeScript and JavaScript, leveraging modern web technologies to deliver a robust and scalable platform for game developers.
4
+
5
+ ## Key Features
6
+
7
+ - **Modular Architecture**: Easily extend and customize the engine with a modular design.
8
+ - **High Performance**: Optimized for performance, ensuring smooth gameplay even in complex scenarios.
9
+ - **Cross-Platform**: Develop games that run seamlessly on multiple platforms, including web, mobile, and desktop.
10
+ - **Extensive Documentation**: Comprehensive documentation to help you get started quickly and efficiently.
11
+
12
+ ## Documentation Guide
13
+
14
+ New to SAGE? Here's how to navigate our documentation:
15
+
16
+ - [**Getting Started**](getting_started.md): Quick setup guide and basic concepts to help you start your first SAGE project.
17
+ - [**Architecture**](architecture.md): Deep dive into the engine's design principles and overall structure.
18
+
19
+ ### Core Systems
20
+
21
+ - [**Entity System**](entity_system.md): Learn about our powerful entity-component system for game object management.
22
+ - [**Scene System**](scene_system.md): Understand how to organize your game world with our flexible scene management.
23
+ - [**Physics System**](physics_system.md): Explore the physics capabilities for realistic movement and interactions.
24
+ - [**Behaviors**](behaviors.md): Discover how to define reusable game behaviors for your entities.
25
+
26
+ ### Communication
27
+
28
+ - [**Event Bus**](eventbus.md): Master our robust event system for efficient communication between engine components.
29
+
30
+ ## Event Bus Highlight
31
+
32
+ SkewedAspect Game Engine includes a powerful event bus system that allows for efficient communication between different parts of the engine. The event bus supports both exact and pattern-based subscriptions, making it easy to handle a wide variety of events with minimal boilerplate code.
33
+
34
+ ## Getting Help
35
+
36
+ If you have questions, encounter issues, or want to contribute to the engine, please visit our GitHub repository or join our community forums. We're committed to continually improving SAGE with your feedback and contributions.
37
+
38
+ Happy game development with SAGE!