@inglorious/engine 0.1.0 → 0.2.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 +39 -36
- package/package.json +20 -33
- package/src/engine/ai/movement/dynamic/align.js +63 -63
- package/src/engine/ai/movement/dynamic/arrive.js +42 -43
- package/src/engine/ai/movement/dynamic/evade.js +38 -38
- package/src/engine/ai/movement/dynamic/face.js +19 -20
- package/src/engine/ai/movement/dynamic/flee.js +45 -45
- package/src/engine/ai/movement/dynamic/look-where-youre-going.js +16 -17
- package/src/engine/ai/movement/dynamic/match-velocity.js +51 -50
- package/src/engine/ai/movement/dynamic/pursue.js +38 -38
- package/src/engine/ai/movement/dynamic/seek.js +44 -44
- package/src/engine/ai/movement/dynamic/wander.js +31 -32
- package/src/engine/ai/movement/kinematic/align.js +37 -37
- package/src/engine/ai/movement/kinematic/arrive.js +42 -42
- package/src/engine/ai/movement/kinematic/face.js +19 -20
- package/src/engine/ai/movement/kinematic/flee.js +26 -26
- package/src/engine/ai/movement/kinematic/seek.js +26 -26
- package/src/engine/ai/movement/kinematic/seek.test.js +42 -42
- package/src/engine/ai/movement/kinematic/wander-as-seek.js +31 -31
- package/src/engine/ai/movement/kinematic/wander.js +27 -27
- package/src/engine/animation/sprite.js +101 -0
- package/src/engine/animation/ticker.js +38 -0
- package/src/engine/behaviors/camera.js +68 -0
- package/src/engine/behaviors/controls/dynamic/modern.js +76 -0
- package/src/engine/behaviors/controls/dynamic/shooter.js +84 -0
- package/src/engine/behaviors/controls/dynamic/tank.js +69 -0
- package/src/engine/behaviors/controls/event-handlers.js +17 -0
- package/src/engine/behaviors/controls/kinematic/modern.js +76 -0
- package/src/engine/behaviors/controls/kinematic/shooter.js +82 -0
- package/src/engine/behaviors/controls/kinematic/tank.js +67 -0
- package/src/engine/behaviors/debug/collision.js +35 -0
- package/src/engine/behaviors/fps.js +29 -0
- package/src/engine/behaviors/fsm.js +33 -0
- package/src/{game/decorators → engine/behaviors}/fsm.test.js +49 -56
- package/src/engine/behaviors/game.js +15 -0
- package/src/engine/behaviors/input/controls.js +37 -0
- package/src/engine/behaviors/input/gamepad.js +114 -0
- package/src/engine/behaviors/input/input.js +48 -0
- package/src/engine/behaviors/input/keyboard.js +64 -0
- package/src/engine/behaviors/input/mouse.js +91 -0
- package/src/engine/behaviors/physics/bouncy.js +25 -0
- package/src/engine/behaviors/physics/clamped.js +36 -0
- package/src/{game/decorators/collisions.js → engine/behaviors/physics/collidable.js} +20 -24
- package/src/engine/behaviors/physics/jumpable.js +145 -0
- package/src/engine/behaviors/ui/button.js +17 -0
- package/src/engine/collision/detection.js +110 -115
- package/src/engine/core/api.js +34 -0
- package/src/engine/core/dev-tools.js +135 -0
- package/src/engine/core/engine.js +119 -0
- package/src/engine/core/loop.js +15 -0
- package/src/engine/{loop → core/loops}/animation-frame.js +25 -26
- package/src/engine/{loop → core/loops}/elapsed.js +22 -23
- package/src/engine/{loop → core/loops}/fixed.js +27 -28
- package/src/engine/{loop → core/loops}/flash.js +13 -14
- package/src/engine/{loop → core/loops}/lag.js +26 -27
- package/src/engine/core/select.js +26 -0
- package/src/engine/core/store.js +178 -0
- package/src/engine/core/store.test.js +110 -0
- package/src/engine/movement/dynamic/modern.js +21 -24
- package/src/engine/movement/dynamic/tank.js +43 -43
- package/src/engine/movement/kinematic/modern.js +16 -16
- package/src/engine/movement/kinematic/modern.test.js +27 -27
- package/src/engine/movement/kinematic/tank.js +27 -27
- package/src/engine/physics/bounds.js +138 -0
- package/src/engine/physics/position.js +43 -0
- package/src/engine/physics/position.test.js +80 -0
- package/src/engine/systems/sprite-animation.js +27 -0
- package/src/main.js +10 -5
- package/src/renderers/canvas/absolute-position.js +18 -0
- package/src/renderers/canvas/camera.js +13 -0
- package/src/renderers/canvas/canvas-renderer.js +68 -0
- package/src/{ui → renderers}/canvas/character.js +38 -35
- package/src/{ui → renderers}/canvas/form/button.js +25 -25
- package/src/{ui → renderers}/canvas/fps.js +18 -18
- package/src/renderers/canvas/image/hitmask.js +51 -0
- package/src/{ui → renderers}/canvas/image/image.js +34 -37
- package/src/{ui → renderers}/canvas/image/sprite.js +49 -49
- package/src/{ui → renderers}/canvas/image/tilemap.js +66 -64
- package/src/{ui → renderers}/canvas/mouse.js +37 -37
- package/src/renderers/canvas/rendering-system.js +79 -0
- package/src/{ui → renderers}/canvas/shapes/circle.js +29 -31
- package/src/{ui → renderers}/canvas/shapes/rectangle.js +27 -31
- package/src/renderers/react/game/character/index.jsx +20 -0
- package/src/{ui → renderers}/react/game/cursor/index.jsx +20 -20
- package/src/{ui → renderers}/react/game/form/fields/field/index.jsx +56 -56
- package/src/{ui → renderers}/react/game/form/fields/index.jsx +12 -12
- package/src/{ui → renderers}/react/game/form/index.jsx +22 -22
- package/src/{ui → renderers}/react/game/fps/index.jsx +16 -16
- package/src/{ui → renderers}/react/game/game.jsx +72 -71
- package/src/{ui → renderers}/react/game/index.jsx +29 -29
- package/src/{ui → renderers}/react/game/platform/index.jsx +30 -30
- package/src/{ui → renderers}/react/game/scene/index.jsx +27 -25
- package/src/{ui → renderers}/react/game/sprite/index.jsx +60 -58
- package/src/{ui → renderers}/react/game/stats/index.jsx +22 -22
- package/src/{ui → renderers}/react/hocs/with-absolute-position/index.jsx +20 -20
- package/src/{ui → renderers}/react/index.jsx +9 -9
- package/src/utils/algorithms/decision-tree.js +24 -24
- package/src/utils/algorithms/decision-tree.test.js +153 -102
- package/src/utils/algorithms/path-finding.js +155 -155
- package/src/utils/algorithms/path-finding.test.js +151 -151
- package/src/utils/data-structures/array.js +83 -83
- package/src/utils/data-structures/array.test.js +173 -173
- package/src/utils/data-structures/board.js +159 -159
- package/src/utils/data-structures/board.test.js +242 -242
- package/src/utils/data-structures/boolean.js +9 -9
- package/src/utils/data-structures/heap.js +164 -164
- package/src/utils/data-structures/heap.test.js +103 -103
- package/src/utils/data-structures/object.js +138 -102
- package/src/utils/data-structures/object.test.js +218 -121
- package/src/utils/data-structures/objects.js +66 -48
- package/src/utils/data-structures/objects.test.js +99 -99
- package/src/utils/data-structures/tree.js +36 -36
- package/src/utils/data-structures/tree.test.js +33 -33
- package/src/utils/functions/functions.js +19 -19
- package/src/utils/functions/functions.test.js +23 -23
- package/src/utils/math/geometry/circle.js +70 -117
- package/src/utils/math/geometry/circle.test.js +97 -97
- package/src/utils/math/geometry/hitmask.js +70 -39
- package/src/utils/math/geometry/hitmask.test.js +155 -84
- package/src/utils/math/geometry/line.js +35 -35
- package/src/utils/math/geometry/line.test.js +49 -49
- package/src/utils/math/geometry/point.js +78 -71
- package/src/utils/math/geometry/point.test.js +81 -81
- package/src/utils/math/geometry/rectangle.js +76 -45
- package/src/utils/math/geometry/rectangle.test.js +42 -42
- package/src/utils/math/geometry/segment.js +80 -80
- package/src/utils/math/geometry/segment.test.js +183 -183
- package/src/utils/math/geometry/triangle.js +15 -15
- package/src/utils/math/geometry/triangle.test.js +11 -11
- package/src/utils/math/linear-algebra/2d.js +28 -28
- package/src/utils/math/linear-algebra/2d.test.js +17 -17
- package/src/utils/math/linear-algebra/quaternion.js +22 -22
- package/src/utils/math/linear-algebra/quaternion.test.js +25 -25
- package/src/utils/math/linear-algebra/quaternions.js +20 -20
- package/src/utils/math/linear-algebra/quaternions.test.js +29 -29
- package/src/utils/math/linear-algebra/vector.js +327 -302
- package/src/utils/math/linear-algebra/vector.test.js +265 -257
- package/src/utils/math/linear-algebra/vectors.js +122 -122
- package/src/utils/math/linear-algebra/vectors.test.js +65 -65
- package/src/utils/math/linear-interpolation.js +9 -0
- package/src/utils/math/numbers.js +90 -90
- package/src/utils/math/numbers.test.js +137 -137
- package/src/utils/math/rng.js +44 -44
- package/src/utils/math/rng.test.js +39 -39
- package/src/utils/math/statistics.js +43 -43
- package/src/utils/math/statistics.test.js +47 -47
- package/src/utils/math/trigonometry.js +89 -89
- package/src/utils/math/trigonometry.test.js +52 -52
- package/src/utils/physics/acceleration.js +61 -63
- package/src/utils/physics/friction.js +28 -30
- package/src/utils/physics/friction.test.js +42 -44
- package/src/utils/physics/gravity.js +69 -71
- package/src/utils/physics/gravity.test.js +77 -80
- package/src/utils/physics/jump.js +31 -41
- package/src/utils/physics/velocity.js +36 -38
- package/src/docs/ai/movement/dynamic/align.js +0 -131
- package/src/docs/ai/movement/dynamic/arrive.js +0 -88
- package/src/docs/ai/movement/dynamic/dynamic.mdx +0 -99
- package/src/docs/ai/movement/dynamic/dynamic.stories.js +0 -58
- package/src/docs/ai/movement/dynamic/evade.js +0 -72
- package/src/docs/ai/movement/dynamic/face.js +0 -90
- package/src/docs/ai/movement/dynamic/flee.js +0 -38
- package/src/docs/ai/movement/dynamic/look-where-youre-going.js +0 -114
- package/src/docs/ai/movement/dynamic/match-velocity.js +0 -92
- package/src/docs/ai/movement/dynamic/pursue.js +0 -72
- package/src/docs/ai/movement/dynamic/seek.js +0 -37
- package/src/docs/ai/movement/dynamic/wander.js +0 -71
- package/src/docs/ai/movement/kinematic/align.js +0 -122
- package/src/docs/ai/movement/kinematic/arrive.js +0 -78
- package/src/docs/ai/movement/kinematic/face.js +0 -82
- package/src/docs/ai/movement/kinematic/flee.js +0 -36
- package/src/docs/ai/movement/kinematic/kinematic.mdx +0 -67
- package/src/docs/ai/movement/kinematic/kinematic.stories.js +0 -42
- package/src/docs/ai/movement/kinematic/seek.js +0 -34
- package/src/docs/ai/movement/kinematic/wander-as-seek.js +0 -62
- package/src/docs/ai/movement/kinematic/wander.js +0 -28
- package/src/docs/bounds.js +0 -7
- package/src/docs/code-reuse.js +0 -35
- package/src/docs/collision/circles.js +0 -58
- package/src/docs/collision/collision.mdx +0 -27
- package/src/docs/collision/collision.stories.js +0 -22
- package/src/docs/collision/platform.js +0 -76
- package/src/docs/collision/tilemap.js +0 -181
- package/src/docs/empty.js +0 -1
- package/src/docs/engine.mdx +0 -81
- package/src/docs/engine.stories.js +0 -37
- package/src/docs/event-handlers.js +0 -68
- package/src/docs/framerate.js +0 -37
- package/src/docs/game.jsx +0 -15
- package/src/docs/image/image.js +0 -19
- package/src/docs/image/image.stories.js +0 -22
- package/src/docs/image/sprite.js +0 -39
- package/src/docs/image/tilemap.js +0 -84
- package/src/docs/input/controls.js +0 -67
- package/src/docs/input/gamepad.js +0 -67
- package/src/docs/input/input.mdx +0 -55
- package/src/docs/input/input.stories.js +0 -27
- package/src/docs/input/keyboard.js +0 -58
- package/src/docs/input/mouse.js +0 -32
- package/src/docs/instances.js +0 -49
- package/src/docs/player/dynamic/double-jump.js +0 -90
- package/src/docs/player/dynamic/dynamic.stories.js +0 -32
- package/src/docs/player/dynamic/jump.js +0 -83
- package/src/docs/player/dynamic/modern-controls.js +0 -57
- package/src/docs/player/dynamic/shooter-controls.js +0 -51
- package/src/docs/player/dynamic/tank-controls.js +0 -44
- package/src/docs/player/kinematic/double-jump.js +0 -90
- package/src/docs/player/kinematic/jump.js +0 -82
- package/src/docs/player/kinematic/kinematic.stories.js +0 -32
- package/src/docs/player/kinematic/modern-controls.js +0 -56
- package/src/docs/player/kinematic/shooter-controls.js +0 -48
- package/src/docs/player/kinematic/tank-controls.js +0 -42
- package/src/docs/quick-start/first-game.js +0 -49
- package/src/docs/quick-start/hello-world.js +0 -1
- package/src/docs/quick-start.mdx +0 -127
- package/src/docs/quick-start.stories.js +0 -17
- package/src/docs/recipes/add-and-remove.js +0 -71
- package/src/docs/recipes/add-instance.js +0 -42
- package/src/docs/recipes/decision-tree.js +0 -169
- package/src/docs/recipes/random-instances.js +0 -25
- package/src/docs/recipes/recipes.mdx +0 -81
- package/src/docs/recipes/recipes.stories.js +0 -37
- package/src/docs/recipes/remove-instance.js +0 -52
- package/src/docs/recipes/states.js +0 -64
- package/src/docs/ui/button.js +0 -28
- package/src/docs/ui/form.stories.js +0 -55
- package/src/docs/ui-chooser.jsx +0 -6
- package/src/docs/utils/data-structures/object.mdx +0 -47
- package/src/docs/utils/data-structures/objects.mdx +0 -30
- package/src/docs/utils/functions/functions.mdx +0 -34
- package/src/docs/utils/math/geometry/circle.mdx +0 -55
- package/src/docs/utils/math/geometry/point.mdx +0 -38
- package/src/docs/utils/math/geometry/rectangle.mdx +0 -24
- package/src/docs/utils/math/geometry/segment.mdx +0 -55
- package/src/docs/utils/math/geometry/triangle.mdx +0 -22
- package/src/docs/utils/math/linear-algebra/2d.mdx +0 -22
- package/src/docs/utils/math/linear-algebra/quaternion.mdx +0 -21
- package/src/docs/utils/math/linear-algebra/quaternions.mdx +0 -22
- package/src/docs/utils/math/linear-algebra/vector.mdx +0 -177
- package/src/docs/utils/math/linear-algebra/vectors.mdx +0 -58
- package/src/docs/utils/math/numbers.mdx +0 -76
- package/src/docs/utils/math/random.mdx +0 -35
- package/src/docs/utils/math/statistics.mdx +0 -38
- package/src/docs/utils/math/trigonometry.mdx +0 -85
- package/src/docs/utils/physics/friction.mdx +0 -20
- package/src/docs/utils/physics/gravity.mdx +0 -28
- package/src/engine/loop.js +0 -15
- package/src/engine/store.js +0 -174
- package/src/engine/store.test.js +0 -256
- package/src/engine.js +0 -74
- package/src/game/animation.js +0 -26
- package/src/game/bounds.js +0 -66
- package/src/game/decorators/character.js +0 -5
- package/src/game/decorators/clamp-to-bounds.js +0 -15
- package/src/game/decorators/controls/dynamic/modern.js +0 -48
- package/src/game/decorators/controls/dynamic/shooter.js +0 -47
- package/src/game/decorators/controls/dynamic/tank.js +0 -55
- package/src/game/decorators/controls/kinematic/modern.js +0 -49
- package/src/game/decorators/controls/kinematic/shooter.js +0 -45
- package/src/game/decorators/controls/kinematic/tank.js +0 -52
- package/src/game/decorators/debug/collisions.js +0 -32
- package/src/game/decorators/double-jump.js +0 -70
- package/src/game/decorators/fps.js +0 -30
- package/src/game/decorators/fsm.js +0 -27
- package/src/game/decorators/game.js +0 -11
- package/src/game/decorators/image/image.js +0 -5
- package/src/game/decorators/image/sprite.js +0 -5
- package/src/game/decorators/image/tilemap.js +0 -5
- package/src/game/decorators/input/controls.js +0 -27
- package/src/game/decorators/input/gamepad.js +0 -74
- package/src/game/decorators/input/input.js +0 -41
- package/src/game/decorators/input/keyboard.js +0 -49
- package/src/game/decorators/input/mouse.js +0 -65
- package/src/game/decorators/jump.js +0 -72
- package/src/game/decorators/platform.js +0 -5
- package/src/game/decorators/ui/button.js +0 -21
- package/src/game/sprite.js +0 -119
- package/src/ui/canvas/absolute-position.js +0 -17
- package/src/ui/canvas/image/hitmask.js +0 -37
- package/src/ui/canvas.js +0 -81
- package/src/ui/react/game/character/index.jsx +0 -30
- package/src/utils/math/geometry/platform.js +0 -42
- package/src/utils/math/geometry/platform.test.js +0 -133
- /package/src/{ui → renderers}/react/game/character/character.module.scss +0 -0
- /package/src/{ui → renderers}/react/game/cursor/cursor.module.scss +0 -0
- /package/src/{ui → renderers}/react/game/form/fields/field/field.module.scss +0 -0
- /package/src/{ui → renderers}/react/game/form/fields/fields.module.scss +0 -0
- /package/src/{ui → renderers}/react/game/form/form.module.scss +0 -0
- /package/src/{ui → renderers}/react/game/platform/platform.module.scss +0 -0
- /package/src/{ui → renderers}/react/game/scene/scene.module.scss +0 -0
- /package/src/{ui → renderers}/react/game/sprite/sprite.module.css +0 -0
- /package/src/{ui → renderers}/react/hocs/with-absolute-position/with-absolute-position.module.scss +0 -0
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { createSelector as _createSelector } from "./select.js"
|
|
2
|
+
|
|
3
|
+
export function createApi(store) {
|
|
4
|
+
const createSelector = (inputSelectors, resultFunc) => {
|
|
5
|
+
const selector = _createSelector(inputSelectors, resultFunc)
|
|
6
|
+
return () => selector(store.getState())
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
const getTypes = () => store.getTypes()
|
|
10
|
+
|
|
11
|
+
const getEntities = () => store.getState().entities
|
|
12
|
+
|
|
13
|
+
const getEntity = (id) => getEntities()[id]
|
|
14
|
+
|
|
15
|
+
const notify = (type, payload) => {
|
|
16
|
+
store.notify(type, payload)
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
const dispatch = (action) => {
|
|
20
|
+
store.dispatch(action)
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
const getType = (id) => store.getOriginalTypes()?.[id]
|
|
24
|
+
|
|
25
|
+
return {
|
|
26
|
+
createSelector,
|
|
27
|
+
getTypes,
|
|
28
|
+
getEntities,
|
|
29
|
+
getEntity,
|
|
30
|
+
getType,
|
|
31
|
+
notify,
|
|
32
|
+
dispatch,
|
|
33
|
+
}
|
|
34
|
+
}
|
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
export const ACTION_BLACKLIST = [
|
|
2
|
+
"update",
|
|
3
|
+
"gamepadAxis",
|
|
4
|
+
"gamepadPress",
|
|
5
|
+
"gamepadRelease",
|
|
6
|
+
"keyboardKeyDown",
|
|
7
|
+
"keyboardKeyUp",
|
|
8
|
+
"inputAxis",
|
|
9
|
+
"inputPress",
|
|
10
|
+
"inputRelease",
|
|
11
|
+
"mouseMove",
|
|
12
|
+
"mouseClick",
|
|
13
|
+
"spriteAnimationEnd",
|
|
14
|
+
]
|
|
15
|
+
|
|
16
|
+
const LAST_STATE = 1
|
|
17
|
+
|
|
18
|
+
let devToolsInstance = null
|
|
19
|
+
let unsubscribe = null
|
|
20
|
+
|
|
21
|
+
export function initDevTools(store) {
|
|
22
|
+
// Prevent multiple connections
|
|
23
|
+
if (devToolsInstance) {
|
|
24
|
+
return
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
if (typeof window === "undefined" || !window.__REDUX_DEVTOOLS_EXTENSION__) {
|
|
28
|
+
return
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
devToolsInstance = window.__REDUX_DEVTOOLS_EXTENSION__.connect({
|
|
32
|
+
name: "Inglorious Engine",
|
|
33
|
+
predicate: (state, action) => !ACTION_BLACKLIST.includes(action.type),
|
|
34
|
+
actionCreators: {
|
|
35
|
+
jump: () => ({ type: "jump", payload: { inputId: "input0" } }),
|
|
36
|
+
},
|
|
37
|
+
// @see https://github.com/reduxjs/redux-devtools/blob/main/extension/docs/API/Arguments.md#features
|
|
38
|
+
features: {
|
|
39
|
+
pause: true, // start/pause recording of dispatched actions
|
|
40
|
+
lock: true, // lock/unlock dispatching actions and side effects
|
|
41
|
+
persist: true, // persist states on page reloading
|
|
42
|
+
export: true, // export history of actions in a file
|
|
43
|
+
import: "custom", // import history of actions from a file
|
|
44
|
+
jump: false, // jump back and forth (time travelling)
|
|
45
|
+
skip: false, // skip (cancel) actions
|
|
46
|
+
reorder: false, // drag and drop actions in the history list
|
|
47
|
+
dispatch: true, // dispatch custom actions or action creators
|
|
48
|
+
test: false, // generate tests for the selected actions
|
|
49
|
+
},
|
|
50
|
+
})
|
|
51
|
+
|
|
52
|
+
unsubscribe = devToolsInstance.subscribe((message) => {
|
|
53
|
+
switch (message.type) {
|
|
54
|
+
case "DISPATCH":
|
|
55
|
+
handleDispatch(message, store)
|
|
56
|
+
break
|
|
57
|
+
|
|
58
|
+
case "ACTION":
|
|
59
|
+
handleAction(message, store)
|
|
60
|
+
break
|
|
61
|
+
}
|
|
62
|
+
})
|
|
63
|
+
|
|
64
|
+
devToolsInstance.init(store.getState())
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
export function disconnectDevTools() {
|
|
68
|
+
// The `disconnect` method on the devToolsInstance is not available in all
|
|
69
|
+
// environments or versions of the extension.
|
|
70
|
+
// The safest way to "disconnect" is to unsubscribe from any listeners
|
|
71
|
+
// and release our reference to the instance, which prevents any further
|
|
72
|
+
// actions from being sent.
|
|
73
|
+
if (unsubscribe) {
|
|
74
|
+
unsubscribe()
|
|
75
|
+
unsubscribe = null
|
|
76
|
+
devToolsInstance = null
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
export function sendAction(action, state) {
|
|
81
|
+
if (devToolsInstance) {
|
|
82
|
+
devToolsInstance.send(action, state)
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
function handleDispatch(message, store) {
|
|
87
|
+
switch (message.payload.type) {
|
|
88
|
+
// reset button
|
|
89
|
+
case "RESET": {
|
|
90
|
+
store.reset()
|
|
91
|
+
devToolsInstance.init(store.getState())
|
|
92
|
+
break
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
// revert button
|
|
96
|
+
case "ROLLBACK": {
|
|
97
|
+
const newState = JSON.parse(message.state)
|
|
98
|
+
store.setState(newState)
|
|
99
|
+
break
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
// commit button
|
|
103
|
+
case "COMMIT": {
|
|
104
|
+
devToolsInstance.init(store.getState())
|
|
105
|
+
break
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
// import from file button
|
|
109
|
+
case "IMPORT_STATE": {
|
|
110
|
+
const { computedStates, actionsById } = message.payload.nextLiftedState
|
|
111
|
+
|
|
112
|
+
const [firstComputedState] = computedStates
|
|
113
|
+
const lastComputedState =
|
|
114
|
+
computedStates[computedStates.length - LAST_STATE]
|
|
115
|
+
if (lastComputedState) {
|
|
116
|
+
store.setState(lastComputedState.state)
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
const flattenedActions = Object.values(actionsById)
|
|
120
|
+
.flatMap(({ action }) => action.payload ?? action)
|
|
121
|
+
.map((action, index) => [index, action])
|
|
122
|
+
|
|
123
|
+
devToolsInstance.init(
|
|
124
|
+
firstComputedState.state,
|
|
125
|
+
Object.fromEntries(flattenedActions),
|
|
126
|
+
)
|
|
127
|
+
break
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
function handleAction(message, store) {
|
|
133
|
+
const action = JSON.parse(message.payload)
|
|
134
|
+
store.dispatch(action)
|
|
135
|
+
}
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
import { game } from "@inglorious/engine/behaviors/game.js"
|
|
2
|
+
import { extend } from "@inglorious/utils/data-structures/objects.js"
|
|
3
|
+
|
|
4
|
+
import { createApi } from "./api.js"
|
|
5
|
+
import {
|
|
6
|
+
ACTION_BLACKLIST,
|
|
7
|
+
disconnectDevTools,
|
|
8
|
+
initDevTools,
|
|
9
|
+
sendAction,
|
|
10
|
+
} from "./dev-tools.js"
|
|
11
|
+
import Loop from "./loop.js"
|
|
12
|
+
import { createStore } from "./store.js"
|
|
13
|
+
|
|
14
|
+
// Default game configuration
|
|
15
|
+
// loop.type specifies the type of loop to use (defaults to "animationFrame").
|
|
16
|
+
const DEFAULT_GAME_CONFIG = {
|
|
17
|
+
loop: { type: "animationFrame", fps: 60 },
|
|
18
|
+
|
|
19
|
+
systems: [],
|
|
20
|
+
|
|
21
|
+
types: {
|
|
22
|
+
game: [game()],
|
|
23
|
+
},
|
|
24
|
+
|
|
25
|
+
entities: {
|
|
26
|
+
// eslint-disable-next-line no-magic-numbers
|
|
27
|
+
game: { type: "game", bounds: [0, 0, 800, 600] },
|
|
28
|
+
},
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
const ONE_SECOND = 1000 // Number of milliseconds in one second.
|
|
32
|
+
|
|
33
|
+
// Delta time for the final update call when stopping the engine.
|
|
34
|
+
const FINAL_UPDATE_DELTA_TIME = 0 // This ensures any pending events (like 'stop') are processed before shutdown.
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Engine class responsible for managing the game loop, state, and rendering.
|
|
38
|
+
*/
|
|
39
|
+
export class Engine {
|
|
40
|
+
_devMode = false
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* @param {Object} [gameConfig] - Game-specific configuration.
|
|
44
|
+
* @param {Object} [renderer] - UI entity responsible for rendering. It must have a `render` method.
|
|
45
|
+
*/
|
|
46
|
+
constructor(gameConfig) {
|
|
47
|
+
this._config = extend(DEFAULT_GAME_CONFIG, gameConfig)
|
|
48
|
+
|
|
49
|
+
const systems = [...(this._config.systems ?? [])]
|
|
50
|
+
if (this._config.renderer) {
|
|
51
|
+
systems.push(...this._config.renderer.getSystems())
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
this._store = createStore({ ...this._config, systems })
|
|
55
|
+
this._loop = new Loop[this._config.loop.type]()
|
|
56
|
+
this._api = createApi(this._store)
|
|
57
|
+
|
|
58
|
+
// The renderer might need the engine instance to initialize itself (e.g., to set up DOM events).
|
|
59
|
+
this._config.renderer?.init(this)
|
|
60
|
+
|
|
61
|
+
// Determine devMode from the entities config.
|
|
62
|
+
const devMode = this._config.entities.game?.devMode
|
|
63
|
+
this._devMode = devMode
|
|
64
|
+
if (devMode) {
|
|
65
|
+
initDevTools(this._store)
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* Starts the game engine, initializing the loop and notifying the store.
|
|
71
|
+
*/
|
|
72
|
+
start() {
|
|
73
|
+
this._store.notify("start", this._api)
|
|
74
|
+
this._loop.start(this, ONE_SECOND / this._config.loop.fps)
|
|
75
|
+
this.isRunning = true
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* Stops the game engine, halting the loop and notifying the store.
|
|
80
|
+
*/
|
|
81
|
+
stop() {
|
|
82
|
+
this._store.notify("stop", this._api)
|
|
83
|
+
this._store.update(FINAL_UPDATE_DELTA_TIME, this._api)
|
|
84
|
+
this._loop.stop()
|
|
85
|
+
this.isRunning = false
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
/**
|
|
89
|
+
* Updates the game state.
|
|
90
|
+
* @param {number} dt - Delta time since the last update in milliseconds.
|
|
91
|
+
*/
|
|
92
|
+
update(dt) {
|
|
93
|
+
const processedEvents = this._store.update(dt, this._api)
|
|
94
|
+
const state = this._store.getState()
|
|
95
|
+
|
|
96
|
+
// Check for devMode changes and connect/disconnect dev tools accordingly.
|
|
97
|
+
const newDevMode = state.entities.game?.devMode
|
|
98
|
+
if (newDevMode !== this._devMode) {
|
|
99
|
+
if (newDevMode) {
|
|
100
|
+
initDevTools(this._store)
|
|
101
|
+
} else {
|
|
102
|
+
disconnectDevTools()
|
|
103
|
+
}
|
|
104
|
+
this._devMode = newDevMode
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
const eventsToLog = processedEvents.filter(
|
|
108
|
+
({ type }) => !ACTION_BLACKLIST.includes(type),
|
|
109
|
+
)
|
|
110
|
+
|
|
111
|
+
if (eventsToLog.length) {
|
|
112
|
+
const action = {
|
|
113
|
+
type: eventsToLog.map(({ type }) => type).join("|"),
|
|
114
|
+
payload: eventsToLog,
|
|
115
|
+
}
|
|
116
|
+
sendAction(action, state)
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { AnimationFrameLoop } from "./loops/animation-frame.js"
|
|
2
|
+
import { ElapsedLoop } from "./loops/elapsed.js"
|
|
3
|
+
import { FixedLoop } from "./loops/fixed.js"
|
|
4
|
+
import { FlashLoop } from "./loops/flash.js"
|
|
5
|
+
import { LagLoop } from "./loops/lag.js"
|
|
6
|
+
|
|
7
|
+
// @see https://gameprogrammingpatterns.com/game-loop.html
|
|
8
|
+
|
|
9
|
+
export default {
|
|
10
|
+
flash: FlashLoop,
|
|
11
|
+
fixed: FixedLoop,
|
|
12
|
+
elapsed: ElapsedLoop,
|
|
13
|
+
lag: LagLoop,
|
|
14
|
+
animationFrame: AnimationFrameLoop,
|
|
15
|
+
}
|
|
@@ -1,26 +1,25 @@
|
|
|
1
|
-
const ONE_SECOND = 1000
|
|
2
|
-
|
|
3
|
-
export
|
|
4
|
-
_id = null
|
|
5
|
-
_previousTime = new Date()
|
|
6
|
-
|
|
7
|
-
start(engine) {
|
|
8
|
-
this._tick(engine)
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
stop() {
|
|
12
|
-
window.cancelAnimationFrame(this._id)
|
|
13
|
-
this._id = null
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
_tick(engine) {
|
|
17
|
-
const currentTime = new Date()
|
|
18
|
-
this._id = window.requestAnimationFrame(() => this._tick(engine))
|
|
19
|
-
const dt = currentTime - this._previousTime
|
|
20
|
-
|
|
21
|
-
engine.update(dt / ONE_SECOND)
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
}
|
|
1
|
+
const ONE_SECOND = 1000
|
|
2
|
+
|
|
3
|
+
export class AnimationFrameLoop {
|
|
4
|
+
_id = null
|
|
5
|
+
_previousTime = new Date()
|
|
6
|
+
|
|
7
|
+
start(engine) {
|
|
8
|
+
this._tick(engine)
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
stop() {
|
|
12
|
+
window.cancelAnimationFrame(this._id)
|
|
13
|
+
this._id = null
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
_tick(engine) {
|
|
17
|
+
const currentTime = new Date()
|
|
18
|
+
this._id = window.requestAnimationFrame(() => this._tick(engine))
|
|
19
|
+
const dt = currentTime - this._previousTime
|
|
20
|
+
|
|
21
|
+
engine.update(dt / ONE_SECOND)
|
|
22
|
+
|
|
23
|
+
this._previousTime = currentTime
|
|
24
|
+
}
|
|
25
|
+
}
|
|
@@ -1,23 +1,22 @@
|
|
|
1
|
-
const ONE_SECOND = 1000
|
|
2
|
-
|
|
3
|
-
export
|
|
4
|
-
_shouldStop = false
|
|
5
|
-
|
|
6
|
-
start(engine) {
|
|
7
|
-
let previousTime = Date.now()
|
|
8
|
-
|
|
9
|
-
while (!this._shouldStop) {
|
|
10
|
-
const currentTime = Date.now()
|
|
11
|
-
const dt = currentTime - previousTime
|
|
12
|
-
|
|
13
|
-
engine.update(dt / ONE_SECOND)
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
}
|
|
1
|
+
const ONE_SECOND = 1000
|
|
2
|
+
|
|
3
|
+
export class ElapsedLoop {
|
|
4
|
+
_shouldStop = false
|
|
5
|
+
|
|
6
|
+
start(engine) {
|
|
7
|
+
let previousTime = Date.now()
|
|
8
|
+
|
|
9
|
+
while (!this._shouldStop) {
|
|
10
|
+
const currentTime = Date.now()
|
|
11
|
+
const dt = currentTime - previousTime
|
|
12
|
+
|
|
13
|
+
engine.update(dt / ONE_SECOND)
|
|
14
|
+
|
|
15
|
+
previousTime = currentTime
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
stop() {
|
|
20
|
+
this._shouldStop = true
|
|
21
|
+
}
|
|
22
|
+
}
|
|
@@ -1,28 +1,27 @@
|
|
|
1
|
-
const ONE_SECOND = 1000
|
|
2
|
-
|
|
3
|
-
export
|
|
4
|
-
_shouldStop = false
|
|
5
|
-
|
|
6
|
-
async start(engine, msPerUpdate) {
|
|
7
|
-
let previousTime = Date.now()
|
|
8
|
-
|
|
9
|
-
while (!this._shouldStop) {
|
|
10
|
-
const currentTime = Date.now()
|
|
11
|
-
const dt = currentTime - previousTime
|
|
12
|
-
|
|
13
|
-
engine.update(dt / ONE_SECOND)
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
}
|
|
1
|
+
const ONE_SECOND = 1000
|
|
2
|
+
|
|
3
|
+
export class FixedLoop {
|
|
4
|
+
_shouldStop = false
|
|
5
|
+
|
|
6
|
+
async start(engine, msPerUpdate) {
|
|
7
|
+
let previousTime = Date.now()
|
|
8
|
+
|
|
9
|
+
while (!this._shouldStop) {
|
|
10
|
+
const currentTime = Date.now()
|
|
11
|
+
const dt = currentTime - previousTime
|
|
12
|
+
|
|
13
|
+
engine.update(dt / ONE_SECOND)
|
|
14
|
+
|
|
15
|
+
previousTime = currentTime
|
|
16
|
+
await sleep(Date.now() - currentTime + msPerUpdate)
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
stop() {
|
|
21
|
+
this._shouldStop = true
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
function sleep(ms) {
|
|
26
|
+
return new Promise((resolve) => setTimeout(resolve, ms))
|
|
27
|
+
}
|
|
@@ -1,14 +1,13 @@
|
|
|
1
|
-
export
|
|
2
|
-
_shouldStop = false
|
|
3
|
-
|
|
4
|
-
start(engine) {
|
|
5
|
-
while (!this._shouldStop) {
|
|
6
|
-
engine.update()
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
}
|
|
1
|
+
export class FlashLoop {
|
|
2
|
+
_shouldStop = false
|
|
3
|
+
|
|
4
|
+
start(engine) {
|
|
5
|
+
while (!this._shouldStop) {
|
|
6
|
+
engine.update()
|
|
7
|
+
}
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
stop() {
|
|
11
|
+
this._shouldStop = true
|
|
12
|
+
}
|
|
13
|
+
}
|
|
@@ -1,27 +1,26 @@
|
|
|
1
|
-
const ONE_SECOND = 1000
|
|
2
|
-
|
|
3
|
-
export
|
|
4
|
-
_shouldStop = false
|
|
5
|
-
|
|
6
|
-
start(engine, msPerUpdate) {
|
|
7
|
-
let previousTime = Date.now()
|
|
8
|
-
let lag = 0
|
|
9
|
-
|
|
10
|
-
while (!this._shouldStop) {
|
|
11
|
-
const currentTime = Date.now()
|
|
12
|
-
const dt = currentTime - previousTime
|
|
13
|
-
previousTime = currentTime
|
|
14
|
-
lag += dt
|
|
15
|
-
|
|
16
|
-
while (lag >= msPerUpdate) {
|
|
17
|
-
engine.update(dt / ONE_SECOND)
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
}
|
|
1
|
+
const ONE_SECOND = 1000
|
|
2
|
+
|
|
3
|
+
export class LagLoop {
|
|
4
|
+
_shouldStop = false
|
|
5
|
+
|
|
6
|
+
start(engine, msPerUpdate) {
|
|
7
|
+
let previousTime = Date.now()
|
|
8
|
+
let lag = 0
|
|
9
|
+
|
|
10
|
+
while (!this._shouldStop) {
|
|
11
|
+
const currentTime = Date.now()
|
|
12
|
+
const dt = currentTime - previousTime
|
|
13
|
+
previousTime = currentTime
|
|
14
|
+
lag += dt
|
|
15
|
+
|
|
16
|
+
while (lag >= msPerUpdate) {
|
|
17
|
+
engine.update(dt / ONE_SECOND)
|
|
18
|
+
lag -= msPerUpdate
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
stop() {
|
|
24
|
+
this._shouldStop = true
|
|
25
|
+
}
|
|
26
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Creates a memoized selector function.
|
|
3
|
+
* NB: this implementation does not support spreading the input selectors for clarity, please just put them in an array.
|
|
4
|
+
* @param {Array<Function>} inputSelectors - An array of input selector functions.
|
|
5
|
+
* @param {Function} resultFunc - A function that receives the results of the input selectors and returns a computed value.
|
|
6
|
+
* @returns {Function} A memoized selector function that, when called, returns the selected state.
|
|
7
|
+
*/
|
|
8
|
+
export function createSelector(inputSelectors, resultFunc) {
|
|
9
|
+
let lastInputs = []
|
|
10
|
+
let lastResult = null
|
|
11
|
+
|
|
12
|
+
return (state) => {
|
|
13
|
+
const nextInputs = inputSelectors.map((selector) => selector(state))
|
|
14
|
+
const inputsChanged =
|
|
15
|
+
lastInputs.length !== nextInputs.length ||
|
|
16
|
+
nextInputs.some((input, index) => input !== lastInputs[index])
|
|
17
|
+
|
|
18
|
+
if (!inputsChanged) {
|
|
19
|
+
return lastResult
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
lastInputs = nextInputs
|
|
23
|
+
lastResult = resultFunc(...nextInputs)
|
|
24
|
+
return lastResult
|
|
25
|
+
}
|
|
26
|
+
}
|