@inglorious/engine 0.6.0 → 0.7.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/README.md +9 -25
- package/package.json +1 -1
- package/src/behaviors/audio.js +28 -0
- package/src/behaviors/camera.js +3 -1
- package/src/behaviors/controls/dynamic/modern.js +4 -2
- package/src/behaviors/controls/dynamic/shooter.js +4 -2
- package/src/behaviors/controls/dynamic/tank.js +4 -2
- package/src/behaviors/controls/event-handlers.js +10 -2
- package/src/behaviors/controls/kinematic/modern.js +4 -2
- package/src/behaviors/controls/kinematic/shooter.js +4 -2
- package/src/behaviors/controls/kinematic/tank.js +4 -2
- package/src/behaviors/fps.js +3 -1
- package/src/behaviors/fsm.js +4 -2
- package/src/behaviors/input/gamepad.js +3 -1
- package/src/behaviors/input/input.js +2 -2
- package/src/behaviors/input/keyboard.js +3 -1
- package/src/behaviors/input/mouse.js +3 -1
- package/src/behaviors/physics/bouncy.js +6 -3
- package/src/behaviors/physics/clamped.js +4 -2
- package/src/behaviors/physics/jumpable.js +9 -4
- package/src/core/engine.js +12 -4
- package/src/core/middlewares/entity-pool/entity-pool-middleware.js +28 -18
- package/src/core/middlewares/entity-pool/entity-pool.js +2 -0
- package/src/core/middlewares/entity-pool/entity-pools.js +16 -11
- package/src/main.js +4 -3
- package/src/systems/entity-creator.js +0 -30
package/README.md
CHANGED
|
@@ -50,6 +50,10 @@ Creates a new `Engine` instance.
|
|
|
50
50
|
|
|
51
51
|
- A new `Engine` instance.
|
|
52
52
|
|
|
53
|
+
### `await engine.init()`
|
|
54
|
+
|
|
55
|
+
An asynchronous function that initializes the resources required for the game to load.
|
|
56
|
+
|
|
53
57
|
### `engine.start()`
|
|
54
58
|
|
|
55
59
|
Starts the game loop, triggering the first `update` and `render` calls.
|
|
@@ -65,52 +69,32 @@ Halts the game loop and cleans up any resources. This method also processes a fi
|
|
|
65
69
|
Here is a complete example showing how to set up and run a game using the engine.
|
|
66
70
|
|
|
67
71
|
```html
|
|
68
|
-
<!
|
|
72
|
+
<!DOCTYPE html>
|
|
69
73
|
<html lang="en">
|
|
70
|
-
|
|
71
|
-
<head>
|
|
72
|
-
|
|
73
|
-
<meta charset="UTF-8" />
|
|
74
|
-
|
|
75
|
-
<link rel="icon" type="image/svg+xml" href="/logo.png" />
|
|
76
|
-
|
|
77
|
-
<link rel="stylesheet" href="/style.css" />
|
|
78
|
-
|
|
79
|
-
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
<title>Inglorious Engine</title>
|
|
83
|
-
|
|
84
|
-
</head>
|
|
85
|
-
|
|
86
74
|
<body>
|
|
87
|
-
|
|
75
|
+
<canvas id="canvas"></canvas>
|
|
88
76
|
|
|
89
|
-
|
|
90
77
|
<script type="text/javascript">
|
|
91
78
|
window.process = { env: "development" }
|
|
92
79
|
</script>
|
|
93
80
|
|
|
94
|
-
|
|
95
81
|
<script type="importmap">
|
|
96
82
|
{
|
|
97
83
|
"imports": {
|
|
98
84
|
"immer": "https://unpkg.com/immer@10.1.1/dist/immer.mjs",
|
|
99
85
|
"@inglorious/utils/": "https://unpkg.com/@inglorious%2Futils@1.1.0/",
|
|
100
|
-
"@inglorious/store/": "https://unpkg.com/@inglorious%2Fstore@0.
|
|
101
|
-
"@inglorious/engine/": "https://unpkg.com/@inglorious%2Fengine@0.
|
|
86
|
+
"@inglorious/store/": "https://unpkg.com/@inglorious%2Fstore@2.0.0/",
|
|
87
|
+
"@inglorious/engine/": "https://unpkg.com/@inglorious%2Fengine@0.7.0/",
|
|
102
88
|
"@inglorious/renderers/": "https://unpkg.com/@inglorious%2Frenderer-2d@0.2.0/",
|
|
103
89
|
"game": "/game.js"
|
|
104
90
|
}
|
|
105
91
|
}
|
|
106
92
|
</script>
|
|
107
93
|
|
|
108
|
-
|
|
109
94
|
<script
|
|
110
95
|
type="module"
|
|
111
|
-
src="https://unpkg.com/@inglorious%2Fengine@0.
|
|
96
|
+
src="https://unpkg.com/@inglorious%2Fengine@0.7.0/main.js"
|
|
112
97
|
></script>
|
|
113
|
-
|
|
114
98
|
</body>
|
|
115
99
|
</html>
|
|
116
100
|
```
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@inglorious/engine",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.7.0",
|
|
4
4
|
"description": "A JavaScript game engine written with global state, immutability, and pure functions in mind. Have fun(ctional programming) with it!",
|
|
5
5
|
"author": "IceOnFire <antony.mistretta@gmail.com> (https://ingloriouscoderz.it)",
|
|
6
6
|
"license": "MIT",
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
export function audio() {
|
|
2
|
+
const audioContext = new (window.AudioContext || window.webkitAudioContext)()
|
|
3
|
+
const audioBufferCache = new Map()
|
|
4
|
+
|
|
5
|
+
return {
|
|
6
|
+
async init(entity) {
|
|
7
|
+
const sounds = entity.sounds || {}
|
|
8
|
+
|
|
9
|
+
await Promise.all(
|
|
10
|
+
Object.entries(sounds).map(async ([name, url]) => {
|
|
11
|
+
const response = await fetch(url)
|
|
12
|
+
const arrayBuffer = await response.arrayBuffer()
|
|
13
|
+
const audioBuffer = await audioContext.decodeAudioData(arrayBuffer)
|
|
14
|
+
audioBufferCache.set(name, audioBuffer)
|
|
15
|
+
}),
|
|
16
|
+
)
|
|
17
|
+
},
|
|
18
|
+
|
|
19
|
+
playSound(entity, name) {
|
|
20
|
+
const audioBuffer = audioBufferCache.get(name)
|
|
21
|
+
|
|
22
|
+
const source = audioContext.createBufferSource()
|
|
23
|
+
source.buffer = audioBuffer
|
|
24
|
+
source.connect(audioContext.destination)
|
|
25
|
+
source.start()
|
|
26
|
+
},
|
|
27
|
+
}
|
|
28
|
+
}
|
package/src/behaviors/camera.js
CHANGED
|
@@ -22,7 +22,9 @@ export function camera(params) {
|
|
|
22
22
|
params = extend(DEFAULT_PARAMS, params)
|
|
23
23
|
|
|
24
24
|
return {
|
|
25
|
-
create(entity) {
|
|
25
|
+
create(entity, entityId) {
|
|
26
|
+
if (entityId !== entity.id) return
|
|
27
|
+
|
|
26
28
|
defaults(entity, params)
|
|
27
29
|
entity.targetZoom = entity.zoom
|
|
28
30
|
// Cache the initial size to calculate the viewport in dev mode
|
|
@@ -24,8 +24,10 @@ export function modernAcceleration(params) {
|
|
|
24
24
|
"moveUpDown",
|
|
25
25
|
]),
|
|
26
26
|
|
|
27
|
-
create(entity,
|
|
28
|
-
type.create?.(entity,
|
|
27
|
+
create(entity, entityId, api) {
|
|
28
|
+
type.create?.(entity, entityId, api)
|
|
29
|
+
|
|
30
|
+
if (entityId !== entity.id) return
|
|
29
31
|
|
|
30
32
|
entity.maxAcceleration ??= params.maxAcceleration
|
|
31
33
|
entity.movement ??= {}
|
|
@@ -33,8 +33,10 @@ export function shooterControls(params) {
|
|
|
33
33
|
"turn",
|
|
34
34
|
]),
|
|
35
35
|
|
|
36
|
-
create(entity,
|
|
37
|
-
type.create?.(entity,
|
|
36
|
+
create(entity, entityId, api) {
|
|
37
|
+
type.create?.(entity, entityId, api)
|
|
38
|
+
|
|
39
|
+
if (entityId !== entity.id) return
|
|
38
40
|
|
|
39
41
|
entity.maxSpeed ??= params.maxSpeed
|
|
40
42
|
entity.maxAngularSpeed ??= params.maxAngularSpeed
|
|
@@ -27,8 +27,10 @@ export function tankControls(params) {
|
|
|
27
27
|
"turn",
|
|
28
28
|
]),
|
|
29
29
|
|
|
30
|
-
create(entity,
|
|
31
|
-
type.create?.(entity,
|
|
30
|
+
create(entity, entityId, api) {
|
|
31
|
+
type.create?.(entity, entityId, api)
|
|
32
|
+
|
|
33
|
+
if (entityId !== entity.id) return
|
|
32
34
|
|
|
33
35
|
entity.maxSpeed ??= params.maxSpeed
|
|
34
36
|
entity.maxAngularSpeed ??= params.maxAngularSpeed
|
|
@@ -1,12 +1,20 @@
|
|
|
1
1
|
export function createMovementEventHandlers(events) {
|
|
2
2
|
return events.reduce((acc, eventName) => {
|
|
3
|
-
acc[eventName] = (entity,
|
|
3
|
+
acc[eventName] = (entity, event) => {
|
|
4
|
+
let entityId, value
|
|
5
|
+
if (typeof event === "string") {
|
|
6
|
+
entityId = event
|
|
7
|
+
} else {
|
|
8
|
+
entityId = event.entityId
|
|
9
|
+
value = event.value
|
|
10
|
+
}
|
|
11
|
+
|
|
4
12
|
if (entityId === entity.id) {
|
|
5
13
|
entity.movement[eventName] = value ?? true
|
|
6
14
|
}
|
|
7
15
|
}
|
|
8
16
|
|
|
9
|
-
acc[`${eventName}End`] = (entity,
|
|
17
|
+
acc[`${eventName}End`] = (entity, entityId) => {
|
|
10
18
|
if (entityId === entity.id) {
|
|
11
19
|
entity.movement[eventName] = false
|
|
12
20
|
}
|
|
@@ -24,8 +24,10 @@ export function modernVelocity(params) {
|
|
|
24
24
|
"moveUpDown",
|
|
25
25
|
]),
|
|
26
26
|
|
|
27
|
-
create(entity,
|
|
28
|
-
type.create?.(entity,
|
|
27
|
+
create(entity, entityId, api) {
|
|
28
|
+
type.create?.(entity, entityId, api)
|
|
29
|
+
|
|
30
|
+
if (entityId !== entity.id) return
|
|
29
31
|
|
|
30
32
|
entity.maxSpeed ??= params.maxSpeed
|
|
31
33
|
entity.movement ??= {}
|
|
@@ -32,8 +32,10 @@ export function shooterControls(params) {
|
|
|
32
32
|
"turn",
|
|
33
33
|
]),
|
|
34
34
|
|
|
35
|
-
create(entity,
|
|
36
|
-
type.create?.(entity,
|
|
35
|
+
create(entity, entityId, api) {
|
|
36
|
+
type.create?.(entity, entityId, api)
|
|
37
|
+
|
|
38
|
+
if (entityId !== entity.id) return
|
|
37
39
|
|
|
38
40
|
entity.maxSpeed ??= params.maxSpeed
|
|
39
41
|
entity.maxAngularSpeed ??= params.maxAngularSpeed
|
|
@@ -26,8 +26,10 @@ export function tankControls(params) {
|
|
|
26
26
|
"turn",
|
|
27
27
|
]),
|
|
28
28
|
|
|
29
|
-
create(entity,
|
|
30
|
-
type.create?.(entity,
|
|
29
|
+
create(entity, entityId, api) {
|
|
30
|
+
type.create?.(entity, entityId, api)
|
|
31
|
+
|
|
32
|
+
if (entityId !== entity.id) return
|
|
31
33
|
|
|
32
34
|
entity.maxSpeed ??= params.maxSpeed
|
|
33
35
|
entity.maxAngularSpeed ??= params.maxAngularSpeed
|
package/src/behaviors/fps.js
CHANGED
package/src/behaviors/fsm.js
CHANGED
|
@@ -9,8 +9,10 @@ export function fsm(states) {
|
|
|
9
9
|
|
|
10
10
|
return (type) => {
|
|
11
11
|
return extend(type, {
|
|
12
|
-
create(entity,
|
|
13
|
-
type.create?.(entity,
|
|
12
|
+
create(entity, entityId, api) {
|
|
13
|
+
type.create?.(entity, entityId, api)
|
|
14
|
+
|
|
15
|
+
if (entityId !== entity.id) return
|
|
14
16
|
|
|
15
17
|
entity.state ??= DEFAULT_STATE
|
|
16
18
|
},
|
|
@@ -22,7 +22,7 @@ export function input() {
|
|
|
22
22
|
entity[action] = true
|
|
23
23
|
|
|
24
24
|
entity.targetIds.forEach((targetId) => {
|
|
25
|
-
api.notify(action,
|
|
25
|
+
api.notify(action, targetId)
|
|
26
26
|
})
|
|
27
27
|
},
|
|
28
28
|
|
|
@@ -33,7 +33,7 @@ export function input() {
|
|
|
33
33
|
entity[action] = false
|
|
34
34
|
|
|
35
35
|
entity.targetIds.forEach((targetId) => {
|
|
36
|
-
api.notify(`${action}End`,
|
|
36
|
+
api.notify(`${action}End`, targetId)
|
|
37
37
|
})
|
|
38
38
|
},
|
|
39
39
|
}
|
|
@@ -7,7 +7,9 @@ export function keyboard() {
|
|
|
7
7
|
let currentDocument = null
|
|
8
8
|
|
|
9
9
|
return {
|
|
10
|
-
create(entity,
|
|
10
|
+
create(entity, entityId, api) {
|
|
11
|
+
if (entityId !== entity.id) return
|
|
12
|
+
|
|
11
13
|
currentDocument = document.body.ownerDocument || document
|
|
12
14
|
|
|
13
15
|
handleKeyDown = createKeyboardHandler("keyboardKeyDown", api)
|
|
@@ -10,12 +10,15 @@ export function bouncy(params) {
|
|
|
10
10
|
|
|
11
11
|
return (type) =>
|
|
12
12
|
extend(type, {
|
|
13
|
-
create(entity) {
|
|
14
|
-
type.create?.(entity)
|
|
13
|
+
create(entity, entityId, api) {
|
|
14
|
+
type.create?.(entity, entityId, api)
|
|
15
|
+
|
|
16
|
+
if (entityId !== entity.id) return
|
|
17
|
+
|
|
15
18
|
defaults(entity, params)
|
|
16
19
|
},
|
|
17
20
|
|
|
18
|
-
|
|
21
|
+
land(entity, entityId) {
|
|
19
22
|
if (entity.id === entityId) {
|
|
20
23
|
entity.vy = jump(entity) * entity.bounciness
|
|
21
24
|
entity.groundObject = undefined
|
|
@@ -11,8 +11,10 @@ export function clamped(params) {
|
|
|
11
11
|
|
|
12
12
|
return (type) =>
|
|
13
13
|
extend(type, {
|
|
14
|
-
create(entity,
|
|
15
|
-
type.create?.(entity,
|
|
14
|
+
create(entity, entityId, api) {
|
|
15
|
+
type.create?.(entity, entityId, api)
|
|
16
|
+
|
|
17
|
+
if (entityId !== entity.id) return
|
|
16
18
|
|
|
17
19
|
entity.collisions ??= {}
|
|
18
20
|
entity.collisions[params.collisionGroup] ??= {}
|
|
@@ -27,8 +27,11 @@ export function jumpable(params) {
|
|
|
27
27
|
|
|
28
28
|
return (type) =>
|
|
29
29
|
extend(type, {
|
|
30
|
-
create(entity,
|
|
31
|
-
type.create?.(entity,
|
|
30
|
+
create(entity, entityId, api) {
|
|
31
|
+
type.create?.(entity, entityId, api)
|
|
32
|
+
|
|
33
|
+
if (entityId !== entity.id) return
|
|
34
|
+
|
|
32
35
|
defaults(entity, params)
|
|
33
36
|
entity.jumpsLeft ??= entity.maxJumps
|
|
34
37
|
|
|
@@ -36,7 +39,9 @@ export function jumpable(params) {
|
|
|
36
39
|
entity.vy ??= 0
|
|
37
40
|
},
|
|
38
41
|
|
|
39
|
-
jump(entity,
|
|
42
|
+
jump(entity, entityId, api) {
|
|
43
|
+
type.jump?.(entity, entityId, api)
|
|
44
|
+
|
|
40
45
|
if (entityId === entity.id && entity.jumpsLeft) {
|
|
41
46
|
entity.vy = jump(entity)
|
|
42
47
|
entity.groundObject = undefined
|
|
@@ -116,7 +121,7 @@ export function jumpable(params) {
|
|
|
116
121
|
|
|
117
122
|
// Only notify on the frame we actually land, not every frame we're on the ground.
|
|
118
123
|
if (!wasOnGround) {
|
|
119
|
-
api.notify("
|
|
124
|
+
api.notify("land", {
|
|
120
125
|
entityId: entity.id,
|
|
121
126
|
targetId: collisionY.id,
|
|
122
127
|
})
|
package/src/core/engine.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { audio } from "@inglorious/engine/behaviors/audio.js"
|
|
1
2
|
import { game } from "@inglorious/engine/behaviors/game.js"
|
|
2
3
|
import { createApi } from "@inglorious/store/api.js"
|
|
3
4
|
import { createStore } from "@inglorious/store/store.js"
|
|
@@ -20,11 +21,13 @@ const DEFAULT_GAME_CONFIG = {
|
|
|
20
21
|
|
|
21
22
|
types: {
|
|
22
23
|
game: [game()],
|
|
24
|
+
audio: audio(),
|
|
23
25
|
},
|
|
24
26
|
|
|
25
27
|
entities: {
|
|
26
28
|
// eslint-disable-next-line no-magic-numbers
|
|
27
29
|
game: { type: "game", bounds: [0, 0, 800, 600] },
|
|
30
|
+
audio: { type: "audio", sounds: {} },
|
|
28
31
|
},
|
|
29
32
|
}
|
|
30
33
|
|
|
@@ -77,14 +80,18 @@ export class Engine {
|
|
|
77
80
|
|
|
78
81
|
this._loop = new Loops[this._config.loop.type]()
|
|
79
82
|
|
|
80
|
-
// The renderer might need the engine instance to initialize itself (e.g., to set up DOM events).
|
|
81
|
-
this._config.renderer?.init(this)
|
|
82
|
-
|
|
83
83
|
if (this._devMode) {
|
|
84
84
|
initDevTools(this._store)
|
|
85
85
|
}
|
|
86
86
|
}
|
|
87
87
|
|
|
88
|
+
async init() {
|
|
89
|
+
return Promise.all([
|
|
90
|
+
this._config.types.audio.init(this._config.entities.audio),
|
|
91
|
+
this._config.renderer?.init(this),
|
|
92
|
+
])
|
|
93
|
+
}
|
|
94
|
+
|
|
88
95
|
/**
|
|
89
96
|
* Starts the game engine, initializing the loop and notifying the store.
|
|
90
97
|
*/
|
|
@@ -101,6 +108,7 @@ export class Engine {
|
|
|
101
108
|
this._api.notify("stop")
|
|
102
109
|
this._store.update(this._api)
|
|
103
110
|
this._loop.stop()
|
|
111
|
+
this._config.renderer?.destroy()
|
|
104
112
|
this.isRunning = false
|
|
105
113
|
}
|
|
106
114
|
|
|
@@ -117,7 +125,7 @@ export class Engine {
|
|
|
117
125
|
const newDevMode = state.entities.game?.devMode
|
|
118
126
|
if (newDevMode !== this._devMode) {
|
|
119
127
|
if (newDevMode) {
|
|
120
|
-
initDevTools(this.
|
|
128
|
+
initDevTools(this._store)
|
|
121
129
|
} else {
|
|
122
130
|
disconnectDevTools()
|
|
123
131
|
}
|
|
@@ -1,28 +1,38 @@
|
|
|
1
|
+
import { EventMap } from "@inglorious/store/event-map"
|
|
2
|
+
|
|
1
3
|
export function entityPoolMiddleware(pools) {
|
|
2
|
-
return (api) =>
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
pools.acquire(event.payload)
|
|
6
|
-
break
|
|
7
|
-
}
|
|
4
|
+
return (api) => {
|
|
5
|
+
const types = api.getTypes()
|
|
6
|
+
const eventMap = new EventMap()
|
|
8
7
|
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
8
|
+
return (next) => (event) => {
|
|
9
|
+
switch (event.type) {
|
|
10
|
+
case "spawn": {
|
|
11
|
+
const entity = pools.acquire(event.payload)
|
|
12
|
+
const type = types[entity.type]
|
|
13
|
+
eventMap.addEntity(entity.id, type)
|
|
14
|
+
break
|
|
15
|
+
}
|
|
13
16
|
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
17
|
+
case "despawn": {
|
|
18
|
+
const entity = pools.recycle(event.payload)
|
|
19
|
+
const type = types[entity.type]
|
|
20
|
+
eventMap.removeEntity(entity.id, type)
|
|
21
|
+
break
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
default: {
|
|
25
|
+
const entityIds = eventMap.getEntitiesForEvent(event.type)
|
|
26
|
+
for (const id of entityIds) {
|
|
27
|
+
const entity = pools.activeEntitiesById.get(id)
|
|
18
28
|
const type = types[entity.type]
|
|
19
29
|
const handle = type[event.type]
|
|
20
30
|
handle?.(entity, event.payload, api)
|
|
21
|
-
}
|
|
22
|
-
}
|
|
31
|
+
}
|
|
32
|
+
}
|
|
23
33
|
}
|
|
24
|
-
}
|
|
25
34
|
|
|
26
|
-
|
|
35
|
+
return next(event)
|
|
36
|
+
}
|
|
27
37
|
}
|
|
28
38
|
}
|
|
@@ -19,6 +19,7 @@ export class EntityPool {
|
|
|
19
19
|
}
|
|
20
20
|
Object.assign(entity, props)
|
|
21
21
|
this._activeEntities.push(entity)
|
|
22
|
+
return entity
|
|
22
23
|
}
|
|
23
24
|
|
|
24
25
|
recycle(entity) {
|
|
@@ -27,6 +28,7 @@ export class EntityPool {
|
|
|
27
28
|
const [entity] = this._activeEntities.splice(index, ITEMS_TO_REMOVE)
|
|
28
29
|
this._inactiveEntities.push(entity)
|
|
29
30
|
}
|
|
31
|
+
return entity
|
|
30
32
|
}
|
|
31
33
|
|
|
32
34
|
getStats() {
|
|
@@ -2,15 +2,24 @@ import { EntityPool } from "./entity-pool"
|
|
|
2
2
|
|
|
3
3
|
export class EntityPools {
|
|
4
4
|
_pools = new Map()
|
|
5
|
+
_activeEntitiesById = new Map()
|
|
5
6
|
|
|
6
|
-
|
|
7
|
-
this.
|
|
8
|
-
this._pools.get(entity.type).acquire(entity)
|
|
7
|
+
get activeEntitiesById() {
|
|
8
|
+
return this._activeEntitiesById
|
|
9
9
|
}
|
|
10
10
|
|
|
11
|
-
|
|
12
|
-
this.lazyInit(
|
|
13
|
-
this._pools.get(
|
|
11
|
+
acquire(props) {
|
|
12
|
+
this.lazyInit(props)
|
|
13
|
+
const entity = this._pools.get(props.type).acquire(props)
|
|
14
|
+
this._activeEntitiesById.set(entity.id, entity)
|
|
15
|
+
return entity
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
recycle(props) {
|
|
19
|
+
this.lazyInit(props)
|
|
20
|
+
const entity = this._pools.get(props.type).recycle(props)
|
|
21
|
+
this._activeEntitiesById.delete(entity.id)
|
|
22
|
+
return entity
|
|
14
23
|
}
|
|
15
24
|
|
|
16
25
|
getStats() {
|
|
@@ -28,10 +37,6 @@ export class EntityPools {
|
|
|
28
37
|
}
|
|
29
38
|
|
|
30
39
|
getAllActiveEntities() {
|
|
31
|
-
|
|
32
|
-
for (const pool of this._pools.values()) {
|
|
33
|
-
activeEntities.push(...pool._activeEntities)
|
|
34
|
-
}
|
|
35
|
-
return activeEntities
|
|
40
|
+
return Array.from(this._activeEntitiesById.values())
|
|
36
41
|
}
|
|
37
42
|
}
|
package/src/main.js
CHANGED
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
import { Engine } from "@inglorious/engine/core/engine.js"
|
|
2
|
-
import {
|
|
2
|
+
import { Renderer2D } from "@inglorious/renderer-2d/index.js"
|
|
3
3
|
import game from "game"
|
|
4
4
|
|
|
5
5
|
const canvas = document.getElementById("canvas")
|
|
6
|
-
window.addEventListener("load", () => {
|
|
7
|
-
const renderer = new
|
|
6
|
+
window.addEventListener("load", async () => {
|
|
7
|
+
const renderer = new Renderer2D(canvas)
|
|
8
8
|
const engine = new Engine({ ...game, renderer })
|
|
9
|
+
await engine.init()
|
|
9
10
|
engine.start()
|
|
10
11
|
})
|
|
@@ -1,30 +0,0 @@
|
|
|
1
|
-
import { Ticker } from "@inglorious/engine/animation/ticker.js"
|
|
2
|
-
|
|
3
|
-
const DEFAULT_SPAWN_INTERVAL = 1 // Time in seconds between spawning entities.
|
|
4
|
-
|
|
5
|
-
/**
|
|
6
|
-
* A system responsible for creating new entities, like asteroids, at regular intervals.
|
|
7
|
-
*
|
|
8
|
-
* @param {object} params Configuration parameters for the system.
|
|
9
|
-
* @param {number} [params.spawnInterval=1] The time in seconds between spawning entities.
|
|
10
|
-
* @param {function} params.factory A function that returns the properties for a new entity.
|
|
11
|
-
* @returns {object} The configured entity creator system.
|
|
12
|
-
*/
|
|
13
|
-
export function entityCreator(params = {}) {
|
|
14
|
-
const spawnInterval = params.spawnInterval ?? DEFAULT_SPAWN_INTERVAL
|
|
15
|
-
const factory = params.factory
|
|
16
|
-
|
|
17
|
-
const ticker = { speed: spawnInterval }
|
|
18
|
-
|
|
19
|
-
return {
|
|
20
|
-
update(state, dt, api) {
|
|
21
|
-
Ticker.tick({
|
|
22
|
-
target: ticker,
|
|
23
|
-
dt,
|
|
24
|
-
onTick: () => {
|
|
25
|
-
api.notify("add", factory())
|
|
26
|
-
},
|
|
27
|
-
})
|
|
28
|
-
},
|
|
29
|
-
}
|
|
30
|
-
}
|