@series-inc/rundot-3d-engine 0.3.0 → 0.4.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.
@@ -1,337 +1,337 @@
1
- # Component Communication
2
-
3
- Patterns for components to interact and share data.
4
-
5
- ## Getting Components
6
-
7
- ### Same GameObject
8
-
9
- ```typescript
10
- class WeaponComponent extends Component {
11
- private meshRenderer?: MeshRenderer
12
-
13
- protected onCreate(): void {
14
- // Get component from same GameObject
15
- this.meshRenderer = this.getComponent(MeshRenderer)
16
-
17
- if (this.meshRenderer) {
18
- console.log("Found MeshRenderer!")
19
- }
20
- }
21
- }
22
- ```
23
-
24
- ### Parent/Child GameObjects
25
-
26
- ```typescript
27
- class ChildComponent extends Component {
28
- private parentController?: ParentController
29
-
30
- protected onCreate(): void {
31
- // Get component from parent
32
- if (this.gameObject.parent instanceof GameObject) {
33
- this.parentController = this.gameObject.parent.getComponent(ParentController)
34
- }
35
- }
36
- }
37
- ```
38
-
39
- ### Finding by Name
40
-
41
- ```typescript
42
- class TargetFinder extends Component {
43
- private target?: GameObject
44
-
45
- protected onCreate(): void {
46
- // Search scene for GameObject by name
47
- const scene = VenusGame.scene
48
- scene.traverse((obj) => {
49
- if (obj instanceof GameObject && obj.name === "Target") {
50
- this.target = obj
51
- }
52
- })
53
- }
54
- }
55
- ```
56
-
57
- ## Communication Patterns
58
-
59
- ### Direct Method Calls
60
-
61
- ```typescript
62
- class HealthComponent extends Component {
63
- private health: number = 100
64
-
65
- public takeDamage(amount: number): void {
66
- this.health -= amount
67
- if (this.health <= 0) {
68
- this.die()
69
- }
70
- }
71
-
72
- private die(): void {
73
- console.log("Dead!")
74
- this.gameObject.dispose()
75
- }
76
- }
77
-
78
- class WeaponComponent extends Component {
79
- public fire(target: GameObject): void {
80
- const health = target.getComponent(HealthComponent)
81
- if (health) {
82
- health.takeDamage(25)
83
- }
84
- }
85
- }
86
- ```
87
-
88
- ### Event System
89
-
90
- ```typescript
91
- // Simple event emitter
92
- class EventBus {
93
- private static listeners = new Map<string, Function[]>()
94
-
95
- static on(event: string, callback: Function): void {
96
- if (!this.listeners.has(event)) {
97
- this.listeners.set(event, [])
98
- }
99
- this.listeners.get(event)!.push(callback)
100
- }
101
-
102
- static emit(event: string, ...args: any[]): void {
103
- const callbacks = this.listeners.get(event)
104
- if (callbacks) {
105
- for (const callback of callbacks) {
106
- callback(...args)
107
- }
108
- }
109
- }
110
-
111
- static off(event: string, callback: Function): void {
112
- const callbacks = this.listeners.get(event)
113
- if (callbacks) {
114
- const index = callbacks.indexOf(callback)
115
- if (index > -1) {
116
- callbacks.splice(index, 1)
117
- }
118
- }
119
- }
120
- }
121
-
122
- // Use it
123
- class ScoreComponent extends Component {
124
- protected onCreate(): void {
125
- EventBus.on("enemy_killed", this.onEnemyKilled.bind(this))
126
- }
127
-
128
- private onEnemyKilled(points: number): void {
129
- this.score += points
130
- }
131
-
132
- protected onCleanup(): void {
133
- EventBus.off("enemy_killed", this.onEnemyKilled)
134
- }
135
- }
136
-
137
- class Enemy extends Component {
138
- private die(): void {
139
- EventBus.emit("enemy_killed", 100)
140
- this.gameObject.dispose()
141
- }
142
- }
143
- ```
144
-
145
- ### Shared State
146
-
147
- ```typescript
148
- // Global game state
149
- class GameState {
150
- static score: number = 0
151
- static level: number = 1
152
- static playerHealth: number = 100
153
- }
154
-
155
- // Components access shared state
156
- class ScoreDisplay extends Component {
157
- public update(deltaTime: number): void {
158
- this.updateUI(GameState.score)
159
- }
160
- }
161
-
162
- class Enemy extends Component {
163
- private die(): void {
164
- GameState.score += 100
165
- this.gameObject.dispose()
166
- }
167
- }
168
- ```
169
-
170
- ### Component References
171
-
172
- ```typescript
173
- class PlayerManager extends Component {
174
- public static instance?: PlayerManager
175
- private health: number = 100
176
-
177
- protected onCreate(): void {
178
- PlayerManager.instance = this
179
- }
180
-
181
- public getHealth(): number {
182
- return this.health
183
- }
184
-
185
- protected onCleanup(): void {
186
- if (PlayerManager.instance === this) {
187
- PlayerManager.instance = undefined
188
- }
189
- }
190
- }
191
-
192
- // Access from anywhere
193
- class HealthBar extends Component {
194
- public update(deltaTime: number): void {
195
- if (PlayerManager.instance) {
196
- const health = PlayerManager.instance.getHealth()
197
- this.updateBar(health)
198
- }
199
- }
200
- }
201
- ```
202
-
203
- ## Patterns & Best Practices
204
-
205
- ### Cache Component References
206
-
207
- ```typescript
208
- // GOOD - Cache in onCreate
209
- class Follower extends Component {
210
- private target?: Transform
211
-
212
- protected onCreate(): void {
213
- // Cache reference once
214
- const targetObj = this.findTarget()
215
- this.target = targetObj
216
- }
217
-
218
- public update(deltaTime: number): void {
219
- if (this.target) {
220
- // Use cached reference
221
- this.followTarget(this.target)
222
- }
223
- }
224
- }
225
-
226
- // BAD - Search every frame
227
- class Follower extends Component {
228
- public update(deltaTime: number): void {
229
- // Slow! Searches scene every frame
230
- const target = this.findTarget()
231
- if (target) {
232
- this.followTarget(target)
233
- }
234
- }
235
- }
236
- ```
237
-
238
- ### Null Checks
239
-
240
- ```typescript
241
- class SafeComponent extends Component {
242
- private dependency?: OtherComponent
243
-
244
- protected onCreate(): void {
245
- this.dependency = this.getComponent(OtherComponent)
246
-
247
- if (!this.dependency) {
248
- console.warn("Missing required component!")
249
- }
250
- }
251
-
252
- public update(deltaTime: number): void {
253
- // Always check before using
254
- if (this.dependency) {
255
- this.dependency.doSomething()
256
- }
257
- }
258
- }
259
- ```
260
-
261
- ### Clean Up Event Listeners
262
-
263
- ```typescript
264
- class EventComponent extends Component {
265
- private boundHandler: () => void
266
-
267
- protected onCreate(): void {
268
- this.boundHandler = this.handleEvent.bind(this)
269
- EventBus.on("game_event", this.boundHandler)
270
- }
271
-
272
- protected onCleanup(): void {
273
- // Always remove listeners!
274
- EventBus.off("game_event", this.boundHandler)
275
- }
276
-
277
- private handleEvent(): void {
278
- console.log("Event received")
279
- }
280
- }
281
- ```
282
-
283
- ## Anti-Patterns
284
-
285
- ### Don't Store Disposed References
286
-
287
- ```typescript
288
- // BAD - Holding reference to disposed object
289
- class BadManager extends Component {
290
- private enemies: GameObject[] = []
291
-
292
- public addEnemy(enemy: GameObject): void {
293
- this.enemies.push(enemy)
294
- // If enemy.dispose() called elsewhere, array has dead reference
295
- }
296
- }
297
-
298
- // GOOD - Remove from tracking
299
- class GoodManager extends Component {
300
- private enemies: GameObject[] = []
301
-
302
- public removeEnemy(enemy: GameObject): void {
303
- enemy.dispose()
304
- const index = this.enemies.indexOf(enemy)
305
- if (index > -1) {
306
- this.enemies.splice(index, 1)
307
- }
308
- }
309
- }
310
- ```
311
-
312
- ### Don't Use Global Variables
313
-
314
- ```typescript
315
- // BAD - Global mutable state
316
- let globalScore = 0
317
-
318
- // GOOD - Encapsulated state
319
- class GameState {
320
- private static _score: number = 0
321
-
322
- static getScore(): number {
323
- return this._score
324
- }
325
-
326
- static addScore(points: number): void {
327
- this._score += points
328
- }
329
- }
330
- ```
331
-
332
- ## Related Patterns
333
-
334
- - [Creating GameObjects](CreatingGameObjects.md) - GameObject creation patterns
335
- - [Component](../core/Component.md) - Component documentation
336
- - [GameObject](../core/GameObject.md) - GameObject documentation
337
-
1
+ # Component Communication
2
+
3
+ Patterns for components to interact and share data.
4
+
5
+ ## Getting Components
6
+
7
+ ### Same GameObject
8
+
9
+ ```typescript
10
+ class WeaponComponent extends Component {
11
+ private meshRenderer?: MeshRenderer
12
+
13
+ protected onCreate(): void {
14
+ // Get component from same GameObject
15
+ this.meshRenderer = this.getComponent(MeshRenderer)
16
+
17
+ if (this.meshRenderer) {
18
+ console.log("Found MeshRenderer!")
19
+ }
20
+ }
21
+ }
22
+ ```
23
+
24
+ ### Parent/Child GameObjects
25
+
26
+ ```typescript
27
+ class ChildComponent extends Component {
28
+ private parentController?: ParentController
29
+
30
+ protected onCreate(): void {
31
+ // Get component from parent
32
+ if (this.gameObject.parent instanceof GameObject) {
33
+ this.parentController = this.gameObject.parent.getComponent(ParentController)
34
+ }
35
+ }
36
+ }
37
+ ```
38
+
39
+ ### Finding by Name
40
+
41
+ ```typescript
42
+ class TargetFinder extends Component {
43
+ private target?: GameObject
44
+
45
+ protected onCreate(): void {
46
+ // Search scene for GameObject by name
47
+ const scene = VenusGame.scene
48
+ scene.traverse((obj) => {
49
+ if (obj instanceof GameObject && obj.name === "Target") {
50
+ this.target = obj
51
+ }
52
+ })
53
+ }
54
+ }
55
+ ```
56
+
57
+ ## Communication Patterns
58
+
59
+ ### Direct Method Calls
60
+
61
+ ```typescript
62
+ class HealthComponent extends Component {
63
+ private health: number = 100
64
+
65
+ public takeDamage(amount: number): void {
66
+ this.health -= amount
67
+ if (this.health <= 0) {
68
+ this.die()
69
+ }
70
+ }
71
+
72
+ private die(): void {
73
+ console.log("Dead!")
74
+ this.gameObject.dispose()
75
+ }
76
+ }
77
+
78
+ class WeaponComponent extends Component {
79
+ public fire(target: GameObject): void {
80
+ const health = target.getComponent(HealthComponent)
81
+ if (health) {
82
+ health.takeDamage(25)
83
+ }
84
+ }
85
+ }
86
+ ```
87
+
88
+ ### Event System
89
+
90
+ ```typescript
91
+ // Simple event emitter
92
+ class EventBus {
93
+ private static listeners = new Map<string, Function[]>()
94
+
95
+ static on(event: string, callback: Function): void {
96
+ if (!this.listeners.has(event)) {
97
+ this.listeners.set(event, [])
98
+ }
99
+ this.listeners.get(event)!.push(callback)
100
+ }
101
+
102
+ static emit(event: string, ...args: any[]): void {
103
+ const callbacks = this.listeners.get(event)
104
+ if (callbacks) {
105
+ for (const callback of callbacks) {
106
+ callback(...args)
107
+ }
108
+ }
109
+ }
110
+
111
+ static off(event: string, callback: Function): void {
112
+ const callbacks = this.listeners.get(event)
113
+ if (callbacks) {
114
+ const index = callbacks.indexOf(callback)
115
+ if (index > -1) {
116
+ callbacks.splice(index, 1)
117
+ }
118
+ }
119
+ }
120
+ }
121
+
122
+ // Use it
123
+ class ScoreComponent extends Component {
124
+ protected onCreate(): void {
125
+ EventBus.on("enemy_killed", this.onEnemyKilled.bind(this))
126
+ }
127
+
128
+ private onEnemyKilled(points: number): void {
129
+ this.score += points
130
+ }
131
+
132
+ protected onCleanup(): void {
133
+ EventBus.off("enemy_killed", this.onEnemyKilled)
134
+ }
135
+ }
136
+
137
+ class Enemy extends Component {
138
+ private die(): void {
139
+ EventBus.emit("enemy_killed", 100)
140
+ this.gameObject.dispose()
141
+ }
142
+ }
143
+ ```
144
+
145
+ ### Shared State
146
+
147
+ ```typescript
148
+ // Global game state
149
+ class GameState {
150
+ static score: number = 0
151
+ static level: number = 1
152
+ static playerHealth: number = 100
153
+ }
154
+
155
+ // Components access shared state
156
+ class ScoreDisplay extends Component {
157
+ public update(deltaTime: number): void {
158
+ this.updateUI(GameState.score)
159
+ }
160
+ }
161
+
162
+ class Enemy extends Component {
163
+ private die(): void {
164
+ GameState.score += 100
165
+ this.gameObject.dispose()
166
+ }
167
+ }
168
+ ```
169
+
170
+ ### Component References
171
+
172
+ ```typescript
173
+ class PlayerManager extends Component {
174
+ public static instance?: PlayerManager
175
+ private health: number = 100
176
+
177
+ protected onCreate(): void {
178
+ PlayerManager.instance = this
179
+ }
180
+
181
+ public getHealth(): number {
182
+ return this.health
183
+ }
184
+
185
+ protected onCleanup(): void {
186
+ if (PlayerManager.instance === this) {
187
+ PlayerManager.instance = undefined
188
+ }
189
+ }
190
+ }
191
+
192
+ // Access from anywhere
193
+ class HealthBar extends Component {
194
+ public update(deltaTime: number): void {
195
+ if (PlayerManager.instance) {
196
+ const health = PlayerManager.instance.getHealth()
197
+ this.updateBar(health)
198
+ }
199
+ }
200
+ }
201
+ ```
202
+
203
+ ## Patterns & Best Practices
204
+
205
+ ### Cache Component References
206
+
207
+ ```typescript
208
+ // GOOD - Cache in onCreate
209
+ class Follower extends Component {
210
+ private target?: Transform
211
+
212
+ protected onCreate(): void {
213
+ // Cache reference once
214
+ const targetObj = this.findTarget()
215
+ this.target = targetObj
216
+ }
217
+
218
+ public update(deltaTime: number): void {
219
+ if (this.target) {
220
+ // Use cached reference
221
+ this.followTarget(this.target)
222
+ }
223
+ }
224
+ }
225
+
226
+ // BAD - Search every frame
227
+ class Follower extends Component {
228
+ public update(deltaTime: number): void {
229
+ // Slow! Searches scene every frame
230
+ const target = this.findTarget()
231
+ if (target) {
232
+ this.followTarget(target)
233
+ }
234
+ }
235
+ }
236
+ ```
237
+
238
+ ### Null Checks
239
+
240
+ ```typescript
241
+ class SafeComponent extends Component {
242
+ private dependency?: OtherComponent
243
+
244
+ protected onCreate(): void {
245
+ this.dependency = this.getComponent(OtherComponent)
246
+
247
+ if (!this.dependency) {
248
+ console.warn("Missing required component!")
249
+ }
250
+ }
251
+
252
+ public update(deltaTime: number): void {
253
+ // Always check before using
254
+ if (this.dependency) {
255
+ this.dependency.doSomething()
256
+ }
257
+ }
258
+ }
259
+ ```
260
+
261
+ ### Clean Up Event Listeners
262
+
263
+ ```typescript
264
+ class EventComponent extends Component {
265
+ private boundHandler: () => void
266
+
267
+ protected onCreate(): void {
268
+ this.boundHandler = this.handleEvent.bind(this)
269
+ EventBus.on("game_event", this.boundHandler)
270
+ }
271
+
272
+ protected onCleanup(): void {
273
+ // Always remove listeners!
274
+ EventBus.off("game_event", this.boundHandler)
275
+ }
276
+
277
+ private handleEvent(): void {
278
+ console.log("Event received")
279
+ }
280
+ }
281
+ ```
282
+
283
+ ## Anti-Patterns
284
+
285
+ ### Don't Store Disposed References
286
+
287
+ ```typescript
288
+ // BAD - Holding reference to disposed object
289
+ class BadManager extends Component {
290
+ private enemies: GameObject[] = []
291
+
292
+ public addEnemy(enemy: GameObject): void {
293
+ this.enemies.push(enemy)
294
+ // If enemy.dispose() called elsewhere, array has dead reference
295
+ }
296
+ }
297
+
298
+ // GOOD - Remove from tracking
299
+ class GoodManager extends Component {
300
+ private enemies: GameObject[] = []
301
+
302
+ public removeEnemy(enemy: GameObject): void {
303
+ enemy.dispose()
304
+ const index = this.enemies.indexOf(enemy)
305
+ if (index > -1) {
306
+ this.enemies.splice(index, 1)
307
+ }
308
+ }
309
+ }
310
+ ```
311
+
312
+ ### Don't Use Global Variables
313
+
314
+ ```typescript
315
+ // BAD - Global mutable state
316
+ let globalScore = 0
317
+
318
+ // GOOD - Encapsulated state
319
+ class GameState {
320
+ private static _score: number = 0
321
+
322
+ static getScore(): number {
323
+ return this._score
324
+ }
325
+
326
+ static addScore(points: number): void {
327
+ this._score += points
328
+ }
329
+ }
330
+ ```
331
+
332
+ ## Related Patterns
333
+
334
+ - [Creating GameObjects](CreatingGameObjects.md) - GameObject creation patterns
335
+ - [Component](../core/Component.md) - Component documentation
336
+ - [GameObject](../core/GameObject.md) - GameObject documentation
337
+