@inglorious/engine 0.2.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.
- package/README.md +76 -75
- package/package.json +14 -25
- package/src/{engine/ai → ai}/movement/dynamic/align.js +63 -63
- package/src/{engine/ai → ai}/movement/dynamic/arrive.js +42 -42
- package/src/{engine/ai → ai}/movement/dynamic/evade.js +38 -38
- package/src/{engine/ai → ai}/movement/dynamic/face.js +19 -19
- package/src/{engine/ai → ai}/movement/dynamic/flee.js +45 -45
- package/src/{engine/ai → ai}/movement/dynamic/look-where-youre-going.js +16 -16
- package/src/{engine/ai → ai}/movement/dynamic/match-velocity.js +51 -51
- package/src/{engine/ai → ai}/movement/dynamic/pursue.js +38 -38
- package/src/{engine/ai → ai}/movement/dynamic/seek.js +44 -44
- package/src/{engine/ai → ai}/movement/dynamic/wander.js +31 -31
- package/src/{engine/ai → ai}/movement/kinematic/align.js +37 -37
- package/src/{engine/ai → ai}/movement/kinematic/arrive.js +42 -42
- package/src/{engine/ai → ai}/movement/kinematic/face.js +19 -19
- package/src/{engine/ai → ai}/movement/kinematic/flee.js +26 -26
- package/src/{engine/ai → ai}/movement/kinematic/seek.js +26 -26
- package/src/{engine/ai → ai}/movement/kinematic/seek.test.js +42 -42
- package/src/{engine/ai → ai}/movement/kinematic/wander-as-seek.js +31 -31
- package/src/{engine/ai → ai}/movement/kinematic/wander.js +27 -27
- package/src/{engine/animation → animation}/sprite.js +101 -101
- package/src/{engine/animation → animation}/ticker.js +38 -38
- package/src/{engine/behaviors → behaviors}/camera.js +68 -68
- package/src/{engine/behaviors → behaviors}/controls/dynamic/modern.js +76 -76
- package/src/{engine/behaviors → behaviors}/controls/dynamic/shooter.js +84 -84
- package/src/{engine/behaviors → behaviors}/controls/dynamic/tank.js +69 -69
- package/src/{engine/behaviors → behaviors}/controls/event-handlers.js +17 -17
- package/src/{engine/behaviors → behaviors}/controls/kinematic/modern.js +76 -76
- package/src/{engine/behaviors → behaviors}/controls/kinematic/shooter.js +82 -82
- package/src/{engine/behaviors → behaviors}/controls/kinematic/tank.js +67 -67
- package/src/behaviors/debug/collision.js +29 -0
- package/src/{engine/behaviors → behaviors}/fps.js +29 -29
- package/src/{engine/behaviors → behaviors}/fsm.js +33 -33
- package/src/{engine/behaviors → behaviors}/fsm.test.js +49 -49
- package/src/{engine/behaviors → behaviors}/game.js +15 -15
- package/src/{engine/behaviors → behaviors}/input/controls.js +37 -37
- package/src/{engine/behaviors → behaviors}/input/gamepad.js +114 -114
- package/src/{engine/behaviors → behaviors}/input/input.js +48 -48
- package/src/{engine/behaviors → behaviors}/input/keyboard.js +64 -64
- package/src/{engine/behaviors → behaviors}/input/mouse.js +91 -91
- package/src/{engine/behaviors → behaviors}/physics/bouncy.js +25 -25
- package/src/{engine/behaviors → behaviors}/physics/clamped.js +36 -36
- package/src/{engine/behaviors → behaviors}/physics/collidable.js +20 -20
- package/src/{engine/behaviors → behaviors}/physics/jumpable.js +145 -145
- package/src/{engine/behaviors → behaviors}/ui/button.js +17 -17
- package/src/{engine/collision → collision}/detection.js +110 -110
- package/src/{engine/core → core}/dev-tools.js +135 -135
- package/src/{engine/core → core}/engine.js +119 -119
- package/src/{engine/core → core}/loop.js +15 -15
- package/src/{engine/core → core}/loops/animation-frame.js +25 -25
- package/src/{engine/core → core}/loops/elapsed.js +22 -22
- package/src/{engine/core → core}/loops/fixed.js +27 -27
- package/src/{engine/core → core}/loops/flash.js +13 -13
- package/src/{engine/core → core}/loops/lag.js +26 -26
- package/src/main.js +10 -10
- package/src/{engine/movement → movement}/dynamic/modern.js +21 -21
- package/src/{engine/movement → movement}/dynamic/tank.js +43 -43
- package/src/{engine/movement → movement}/kinematic/modern.js +16 -16
- package/src/{engine/movement → movement}/kinematic/modern.test.js +27 -27
- package/src/{engine/movement → movement}/kinematic/tank.js +27 -27
- package/src/{engine/physics → physics}/bounds.js +138 -138
- package/src/{engine/physics → physics}/position.js +43 -43
- package/src/{engine/physics → physics}/position.test.js +80 -80
- package/src/{engine/systems → systems}/sprite-animation.js +27 -27
- package/src/engine/behaviors/debug/collision.js +0 -35
- package/src/engine/core/api.js +0 -34
- package/src/engine/core/select.js +0 -26
- package/src/engine/core/store.js +0 -178
- package/src/engine/core/store.test.js +0 -110
- package/src/renderers/canvas/absolute-position.js +0 -18
- package/src/renderers/canvas/camera.js +0 -13
- package/src/renderers/canvas/canvas-renderer.js +0 -68
- package/src/renderers/canvas/character.js +0 -38
- package/src/renderers/canvas/form/button.js +0 -25
- package/src/renderers/canvas/fps.js +0 -18
- package/src/renderers/canvas/image/hitmask.js +0 -51
- package/src/renderers/canvas/image/image.js +0 -34
- package/src/renderers/canvas/image/sprite.js +0 -49
- package/src/renderers/canvas/image/tilemap.js +0 -66
- package/src/renderers/canvas/mouse.js +0 -37
- package/src/renderers/canvas/rendering-system.js +0 -79
- package/src/renderers/canvas/shapes/circle.js +0 -29
- package/src/renderers/canvas/shapes/rectangle.js +0 -27
- package/src/renderers/react/game/character/character.module.scss +0 -17
- package/src/renderers/react/game/character/index.jsx +0 -20
- package/src/renderers/react/game/cursor/cursor.module.scss +0 -47
- package/src/renderers/react/game/cursor/index.jsx +0 -20
- package/src/renderers/react/game/form/fields/field/field.module.scss +0 -5
- package/src/renderers/react/game/form/fields/field/index.jsx +0 -56
- package/src/renderers/react/game/form/fields/fields.module.scss +0 -48
- package/src/renderers/react/game/form/fields/index.jsx +0 -12
- package/src/renderers/react/game/form/form.module.scss +0 -18
- package/src/renderers/react/game/form/index.jsx +0 -22
- package/src/renderers/react/game/fps/index.jsx +0 -16
- package/src/renderers/react/game/game.jsx +0 -72
- package/src/renderers/react/game/index.jsx +0 -29
- package/src/renderers/react/game/platform/index.jsx +0 -30
- package/src/renderers/react/game/platform/platform.module.scss +0 -7
- package/src/renderers/react/game/scene/index.jsx +0 -27
- package/src/renderers/react/game/scene/scene.module.scss +0 -9
- package/src/renderers/react/game/sprite/index.jsx +0 -60
- package/src/renderers/react/game/sprite/sprite.module.css +0 -3
- package/src/renderers/react/game/stats/index.jsx +0 -22
- package/src/renderers/react/hocs/with-absolute-position/index.jsx +0 -20
- package/src/renderers/react/hocs/with-absolute-position/with-absolute-position.module.scss +0 -5
- package/src/renderers/react/index.jsx +0 -9
- package/src/utils/algorithms/decision-tree.js +0 -24
- package/src/utils/algorithms/decision-tree.test.js +0 -153
- package/src/utils/algorithms/path-finding.js +0 -155
- package/src/utils/algorithms/path-finding.test.js +0 -151
- package/src/utils/algorithms/types.d.ts +0 -28
- package/src/utils/data-structures/array.js +0 -83
- package/src/utils/data-structures/array.test.js +0 -173
- package/src/utils/data-structures/board.js +0 -159
- package/src/utils/data-structures/board.test.js +0 -242
- package/src/utils/data-structures/boolean.js +0 -9
- package/src/utils/data-structures/heap.js +0 -164
- package/src/utils/data-structures/heap.test.js +0 -103
- package/src/utils/data-structures/object.js +0 -138
- package/src/utils/data-structures/object.test.js +0 -218
- package/src/utils/data-structures/objects.js +0 -66
- package/src/utils/data-structures/objects.test.js +0 -99
- package/src/utils/data-structures/tree.js +0 -36
- package/src/utils/data-structures/tree.test.js +0 -33
- package/src/utils/data-structures/types.d.ts +0 -4
- package/src/utils/functions/functions.js +0 -19
- package/src/utils/functions/functions.test.js +0 -23
- package/src/utils/math/geometry/circle.js +0 -70
- package/src/utils/math/geometry/circle.test.js +0 -97
- package/src/utils/math/geometry/hitmask.js +0 -70
- package/src/utils/math/geometry/hitmask.test.js +0 -155
- package/src/utils/math/geometry/line.js +0 -35
- package/src/utils/math/geometry/line.test.js +0 -49
- package/src/utils/math/geometry/point.js +0 -78
- package/src/utils/math/geometry/point.test.js +0 -81
- package/src/utils/math/geometry/rectangle.js +0 -76
- package/src/utils/math/geometry/rectangle.test.js +0 -42
- package/src/utils/math/geometry/segment.js +0 -80
- package/src/utils/math/geometry/segment.test.js +0 -183
- package/src/utils/math/geometry/triangle.js +0 -15
- package/src/utils/math/geometry/triangle.test.js +0 -11
- package/src/utils/math/geometry/types.d.ts +0 -23
- package/src/utils/math/linear-algebra/2d.js +0 -28
- package/src/utils/math/linear-algebra/2d.test.js +0 -17
- package/src/utils/math/linear-algebra/quaternion.js +0 -22
- package/src/utils/math/linear-algebra/quaternion.test.js +0 -25
- package/src/utils/math/linear-algebra/quaternions.js +0 -20
- package/src/utils/math/linear-algebra/quaternions.test.js +0 -29
- package/src/utils/math/linear-algebra/types.d.ts +0 -4
- package/src/utils/math/linear-algebra/vector.js +0 -327
- package/src/utils/math/linear-algebra/vector.test.js +0 -265
- package/src/utils/math/linear-algebra/vectors.js +0 -122
- package/src/utils/math/linear-algebra/vectors.test.js +0 -65
- package/src/utils/math/linear-interpolation.js +0 -9
- package/src/utils/math/numbers.js +0 -90
- package/src/utils/math/numbers.test.js +0 -137
- package/src/utils/math/rng.js +0 -44
- package/src/utils/math/rng.test.js +0 -39
- package/src/utils/math/statistics.js +0 -43
- package/src/utils/math/statistics.test.js +0 -47
- package/src/utils/math/trigonometry.js +0 -89
- package/src/utils/math/trigonometry.test.js +0 -52
- package/src/utils/physics/acceleration.js +0 -61
- package/src/utils/physics/friction.js +0 -28
- package/src/utils/physics/friction.test.js +0 -42
- package/src/utils/physics/gravity.js +0 -69
- package/src/utils/physics/gravity.test.js +0 -77
- package/src/utils/physics/jump.js +0 -31
- package/src/utils/physics/velocity.js +0 -36
|
@@ -1,16 +1,16 @@
|
|
|
1
|
-
import {
|
|
2
|
-
angle,
|
|
3
|
-
magnitude,
|
|
4
|
-
} from "@inglorious/utils/math/linear-algebra/vector.js"
|
|
5
|
-
import { applyVelocity } from "@inglorious/utils/physics/velocity.js"
|
|
6
|
-
|
|
7
|
-
const DEFAULT_ORIENTATION = 0
|
|
8
|
-
|
|
9
|
-
export function modernMove(entity, dt) {
|
|
10
|
-
const { velocity, position } = applyVelocity(entity, dt)
|
|
11
|
-
|
|
12
|
-
let orientation = entity.orientation ?? DEFAULT_ORIENTATION
|
|
13
|
-
orientation = magnitude(velocity) ? angle(velocity) : orientation
|
|
14
|
-
|
|
15
|
-
return { velocity, position, orientation }
|
|
16
|
-
}
|
|
1
|
+
import {
|
|
2
|
+
angle,
|
|
3
|
+
magnitude,
|
|
4
|
+
} from "@inglorious/utils/math/linear-algebra/vector.js"
|
|
5
|
+
import { applyVelocity } from "@inglorious/utils/physics/velocity.js"
|
|
6
|
+
|
|
7
|
+
const DEFAULT_ORIENTATION = 0
|
|
8
|
+
|
|
9
|
+
export function modernMove(entity, dt) {
|
|
10
|
+
const { velocity, position } = applyVelocity(entity, dt)
|
|
11
|
+
|
|
12
|
+
let orientation = entity.orientation ?? DEFAULT_ORIENTATION
|
|
13
|
+
orientation = magnitude(velocity) ? angle(velocity) : orientation
|
|
14
|
+
|
|
15
|
+
return { velocity, position, orientation }
|
|
16
|
+
}
|
|
@@ -1,27 +1,27 @@
|
|
|
1
|
-
import { expect, test } from "vitest"
|
|
2
|
-
|
|
3
|
-
import { modernMove } from "./modern.js"
|
|
4
|
-
|
|
5
|
-
test("it should move following its velocity", () => {
|
|
6
|
-
const entity = { maxSpeed: 1, velocity: [1, 0, 0], position: [0, 0, 0] }
|
|
7
|
-
const dt = 1
|
|
8
|
-
const expectedResult = {
|
|
9
|
-
velocity: [1, 0, 0],
|
|
10
|
-
position: [1, 0, 0],
|
|
11
|
-
orientation: 0,
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
expect(modernMove(entity, dt)).toStrictEqual(expectedResult)
|
|
15
|
-
})
|
|
16
|
-
|
|
17
|
-
test("it should limit the velocity to the max speed", () => {
|
|
18
|
-
const entity = { maxSpeed: 1, velocity: [10, 0, 0], position: [0, 0, 0] }
|
|
19
|
-
const dt = 1
|
|
20
|
-
const expectedResult = {
|
|
21
|
-
velocity: [1, 0, 0],
|
|
22
|
-
position: [1, 0, 0],
|
|
23
|
-
orientation: 0,
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
expect(modernMove(entity, dt)).toStrictEqual(expectedResult)
|
|
27
|
-
})
|
|
1
|
+
import { expect, test } from "vitest"
|
|
2
|
+
|
|
3
|
+
import { modernMove } from "./modern.js"
|
|
4
|
+
|
|
5
|
+
test("it should move following its velocity", () => {
|
|
6
|
+
const entity = { maxSpeed: 1, velocity: [1, 0, 0], position: [0, 0, 0] }
|
|
7
|
+
const dt = 1
|
|
8
|
+
const expectedResult = {
|
|
9
|
+
velocity: [1, 0, 0],
|
|
10
|
+
position: [1, 0, 0],
|
|
11
|
+
orientation: 0,
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
expect(modernMove(entity, dt)).toStrictEqual(expectedResult)
|
|
15
|
+
})
|
|
16
|
+
|
|
17
|
+
test("it should limit the velocity to the max speed", () => {
|
|
18
|
+
const entity = { maxSpeed: 1, velocity: [10, 0, 0], position: [0, 0, 0] }
|
|
19
|
+
const dt = 1
|
|
20
|
+
const expectedResult = {
|
|
21
|
+
velocity: [1, 0, 0],
|
|
22
|
+
position: [1, 0, 0],
|
|
23
|
+
orientation: 0,
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
expect(modernMove(entity, dt)).toStrictEqual(expectedResult)
|
|
27
|
+
})
|
|
@@ -1,27 +1,27 @@
|
|
|
1
|
-
import {
|
|
2
|
-
clamp,
|
|
3
|
-
multiply,
|
|
4
|
-
rotate,
|
|
5
|
-
zero,
|
|
6
|
-
} from "@inglorious/utils/math/linear-algebra/vector.js"
|
|
7
|
-
import { sum } from "@inglorious/utils/math/linear-algebra/vectors.js"
|
|
8
|
-
import { toRange } from "@inglorious/utils/math/trigonometry.js"
|
|
9
|
-
|
|
10
|
-
const DEFAULT_MAX_SPEED = 0
|
|
11
|
-
|
|
12
|
-
const DEFAULT_ORIENTATION = 0
|
|
13
|
-
|
|
14
|
-
export function tankMove(entity, dt) {
|
|
15
|
-
const maxSpeed = entity.maxSpeed ?? DEFAULT_MAX_SPEED
|
|
16
|
-
|
|
17
|
-
let orientation = entity.orientation ?? DEFAULT_ORIENTATION
|
|
18
|
-
orientation = toRange(orientation)
|
|
19
|
-
|
|
20
|
-
let velocity = entity.velocity ?? zero()
|
|
21
|
-
velocity = rotate(velocity, orientation)
|
|
22
|
-
velocity = clamp(velocity, -maxSpeed, maxSpeed)
|
|
23
|
-
|
|
24
|
-
const position = sum(entity.position, multiply(velocity, dt))
|
|
25
|
-
|
|
26
|
-
return { velocity, position, orientation }
|
|
27
|
-
}
|
|
1
|
+
import {
|
|
2
|
+
clamp,
|
|
3
|
+
multiply,
|
|
4
|
+
rotate,
|
|
5
|
+
zero,
|
|
6
|
+
} from "@inglorious/utils/math/linear-algebra/vector.js"
|
|
7
|
+
import { sum } from "@inglorious/utils/math/linear-algebra/vectors.js"
|
|
8
|
+
import { toRange } from "@inglorious/utils/math/trigonometry.js"
|
|
9
|
+
|
|
10
|
+
const DEFAULT_MAX_SPEED = 0
|
|
11
|
+
|
|
12
|
+
const DEFAULT_ORIENTATION = 0
|
|
13
|
+
|
|
14
|
+
export function tankMove(entity, dt) {
|
|
15
|
+
const maxSpeed = entity.maxSpeed ?? DEFAULT_MAX_SPEED
|
|
16
|
+
|
|
17
|
+
let orientation = entity.orientation ?? DEFAULT_ORIENTATION
|
|
18
|
+
orientation = toRange(orientation)
|
|
19
|
+
|
|
20
|
+
let velocity = entity.velocity ?? zero()
|
|
21
|
+
velocity = rotate(velocity, orientation)
|
|
22
|
+
velocity = clamp(velocity, -maxSpeed, maxSpeed)
|
|
23
|
+
|
|
24
|
+
const position = sum(entity.position, multiply(velocity, dt))
|
|
25
|
+
|
|
26
|
+
return { velocity, position, orientation }
|
|
27
|
+
}
|
|
@@ -1,138 +1,138 @@
|
|
|
1
|
-
import {
|
|
2
|
-
angle,
|
|
3
|
-
clamp,
|
|
4
|
-
createVector,
|
|
5
|
-
fromAngle,
|
|
6
|
-
multiply,
|
|
7
|
-
zero,
|
|
8
|
-
} from "@inglorious/utils/math/linear-algebra/vector.js"
|
|
9
|
-
import { sum } from "@inglorious/utils/math/linear-algebra/vectors.js"
|
|
10
|
-
import { abs } from "@inglorious/utils/math/numbers.js"
|
|
11
|
-
|
|
12
|
-
const DOUBLE = 2
|
|
13
|
-
const HALF = 2
|
|
14
|
-
const X = 0
|
|
15
|
-
const Z = 2
|
|
16
|
-
|
|
17
|
-
export function bounce(entity, dt, [minX, minZ, maxX, maxZ]) {
|
|
18
|
-
const [x, , z] = entity.position
|
|
19
|
-
|
|
20
|
-
const velocity = createVector(entity.maxSpeed, entity.orientation)
|
|
21
|
-
if (x < minX || x >= maxX) {
|
|
22
|
-
velocity[X] = -velocity[X]
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
if (z < minZ || z >= maxZ) {
|
|
26
|
-
velocity[Z] = -velocity[Z]
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
const position = sum(entity.position, multiply(velocity, dt))
|
|
30
|
-
const orientation = angle(velocity)
|
|
31
|
-
|
|
32
|
-
return { velocity, position, orientation }
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
const ClampToBoundsByShape = {
|
|
36
|
-
rectangle(entity, [minX, minZ, maxX, maxZ], collisionGroup) {
|
|
37
|
-
const [width, height, depth] =
|
|
38
|
-
entity.collisions[collisionGroup].size ?? entity.size
|
|
39
|
-
|
|
40
|
-
const halfWidth = width / HALF
|
|
41
|
-
const halfHeight = height / HALF
|
|
42
|
-
const halfDepth = depth / HALF
|
|
43
|
-
|
|
44
|
-
return clamp(
|
|
45
|
-
entity.position,
|
|
46
|
-
[minX + halfWidth, minZ + halfHeight, minZ + halfDepth],
|
|
47
|
-
[maxX - halfWidth, maxZ - halfHeight, maxZ - halfDepth],
|
|
48
|
-
)
|
|
49
|
-
},
|
|
50
|
-
|
|
51
|
-
circle(entity, [minX, minY, maxX, maxY], collisionGroup, depthAxis = "y") {
|
|
52
|
-
const radius = entity.collisions[collisionGroup].radius ?? entity.radius
|
|
53
|
-
|
|
54
|
-
if (depthAxis === "z") {
|
|
55
|
-
return clamp(
|
|
56
|
-
entity.position,
|
|
57
|
-
[minX + radius, minY + radius, minY],
|
|
58
|
-
[maxX - radius, maxY - radius, maxY],
|
|
59
|
-
)
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
return clamp(
|
|
63
|
-
entity.position,
|
|
64
|
-
[minX + radius, minY, minY + radius],
|
|
65
|
-
[maxX - radius, maxY, maxY - radius],
|
|
66
|
-
)
|
|
67
|
-
},
|
|
68
|
-
|
|
69
|
-
point(entity, [minX, minZ, maxX, maxZ]) {
|
|
70
|
-
return clamp(entity.position, [minX, minZ, minZ], [maxX, maxZ, maxZ])
|
|
71
|
-
},
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
export function clampToBounds(
|
|
75
|
-
entity,
|
|
76
|
-
bounds,
|
|
77
|
-
collisionGroup = "bounds",
|
|
78
|
-
depthAxis,
|
|
79
|
-
) {
|
|
80
|
-
const shape = entity.collisions[collisionGroup].shape || "rectangle"
|
|
81
|
-
const handler = ClampToBoundsByShape[shape] || ClampToBoundsByShape.point
|
|
82
|
-
return handler(entity, bounds, collisionGroup, depthAxis)
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
export function flip(entity, [minX, minZ, maxX, maxZ]) {
|
|
86
|
-
const [x, , z] = entity.position
|
|
87
|
-
|
|
88
|
-
entity.collisions ??= {}
|
|
89
|
-
entity.collisions.bounds ??= {}
|
|
90
|
-
entity.collisions.bounds.shape ??= "rectangle"
|
|
91
|
-
|
|
92
|
-
let width, height, depth
|
|
93
|
-
if (entity.collisions.bounds.shape === "circle") {
|
|
94
|
-
width = entity.collisions.bounds.radius * DOUBLE
|
|
95
|
-
height = entity.collisions.bounds.radius * DOUBLE
|
|
96
|
-
depth = entity.collisions.bounds.radius * DOUBLE
|
|
97
|
-
} else {
|
|
98
|
-
;[width, height, depth] = entity.collisions.bounds.size ?? entity.size
|
|
99
|
-
}
|
|
100
|
-
const halfWidth = width / HALF
|
|
101
|
-
const halfHeight = height / HALF
|
|
102
|
-
const halfDepth = depth / HALF
|
|
103
|
-
|
|
104
|
-
const left = x - halfWidth
|
|
105
|
-
const right = x + halfWidth
|
|
106
|
-
const bottom = z - halfHeight
|
|
107
|
-
const top = z + halfHeight
|
|
108
|
-
const back = z - halfDepth
|
|
109
|
-
const front = z + halfDepth
|
|
110
|
-
|
|
111
|
-
const direction = fromAngle(entity.orientation)
|
|
112
|
-
|
|
113
|
-
if (
|
|
114
|
-
left < minX ||
|
|
115
|
-
right >= maxX ||
|
|
116
|
-
bottom < minZ ||
|
|
117
|
-
top >= maxZ ||
|
|
118
|
-
back < minZ ||
|
|
119
|
-
front >= maxZ
|
|
120
|
-
) {
|
|
121
|
-
if (left < minX) {
|
|
122
|
-
direction[X] = abs(direction[X])
|
|
123
|
-
} else if (right >= maxX) {
|
|
124
|
-
direction[X] = -abs(direction[X])
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
if (back < minZ) {
|
|
128
|
-
direction[Z] = abs(direction[Z])
|
|
129
|
-
} else if (front >= maxZ) {
|
|
130
|
-
direction[Z] = -abs(direction[Z])
|
|
131
|
-
}
|
|
132
|
-
|
|
133
|
-
entity.acceleration = zero()
|
|
134
|
-
entity.velocity = zero()
|
|
135
|
-
}
|
|
136
|
-
|
|
137
|
-
entity.orientation = angle(direction)
|
|
138
|
-
}
|
|
1
|
+
import {
|
|
2
|
+
angle,
|
|
3
|
+
clamp,
|
|
4
|
+
createVector,
|
|
5
|
+
fromAngle,
|
|
6
|
+
multiply,
|
|
7
|
+
zero,
|
|
8
|
+
} from "@inglorious/utils/math/linear-algebra/vector.js"
|
|
9
|
+
import { sum } from "@inglorious/utils/math/linear-algebra/vectors.js"
|
|
10
|
+
import { abs } from "@inglorious/utils/math/numbers.js"
|
|
11
|
+
|
|
12
|
+
const DOUBLE = 2
|
|
13
|
+
const HALF = 2
|
|
14
|
+
const X = 0
|
|
15
|
+
const Z = 2
|
|
16
|
+
|
|
17
|
+
export function bounce(entity, dt, [minX, minZ, maxX, maxZ]) {
|
|
18
|
+
const [x, , z] = entity.position
|
|
19
|
+
|
|
20
|
+
const velocity = createVector(entity.maxSpeed, entity.orientation)
|
|
21
|
+
if (x < minX || x >= maxX) {
|
|
22
|
+
velocity[X] = -velocity[X]
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
if (z < minZ || z >= maxZ) {
|
|
26
|
+
velocity[Z] = -velocity[Z]
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
const position = sum(entity.position, multiply(velocity, dt))
|
|
30
|
+
const orientation = angle(velocity)
|
|
31
|
+
|
|
32
|
+
return { velocity, position, orientation }
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
const ClampToBoundsByShape = {
|
|
36
|
+
rectangle(entity, [minX, minZ, maxX, maxZ], collisionGroup) {
|
|
37
|
+
const [width, height, depth] =
|
|
38
|
+
entity.collisions[collisionGroup].size ?? entity.size
|
|
39
|
+
|
|
40
|
+
const halfWidth = width / HALF
|
|
41
|
+
const halfHeight = height / HALF
|
|
42
|
+
const halfDepth = depth / HALF
|
|
43
|
+
|
|
44
|
+
return clamp(
|
|
45
|
+
entity.position,
|
|
46
|
+
[minX + halfWidth, minZ + halfHeight, minZ + halfDepth],
|
|
47
|
+
[maxX - halfWidth, maxZ - halfHeight, maxZ - halfDepth],
|
|
48
|
+
)
|
|
49
|
+
},
|
|
50
|
+
|
|
51
|
+
circle(entity, [minX, minY, maxX, maxY], collisionGroup, depthAxis = "y") {
|
|
52
|
+
const radius = entity.collisions[collisionGroup].radius ?? entity.radius
|
|
53
|
+
|
|
54
|
+
if (depthAxis === "z") {
|
|
55
|
+
return clamp(
|
|
56
|
+
entity.position,
|
|
57
|
+
[minX + radius, minY + radius, minY],
|
|
58
|
+
[maxX - radius, maxY - radius, maxY],
|
|
59
|
+
)
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
return clamp(
|
|
63
|
+
entity.position,
|
|
64
|
+
[minX + radius, minY, minY + radius],
|
|
65
|
+
[maxX - radius, maxY, maxY - radius],
|
|
66
|
+
)
|
|
67
|
+
},
|
|
68
|
+
|
|
69
|
+
point(entity, [minX, minZ, maxX, maxZ]) {
|
|
70
|
+
return clamp(entity.position, [minX, minZ, minZ], [maxX, maxZ, maxZ])
|
|
71
|
+
},
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
export function clampToBounds(
|
|
75
|
+
entity,
|
|
76
|
+
bounds,
|
|
77
|
+
collisionGroup = "bounds",
|
|
78
|
+
depthAxis,
|
|
79
|
+
) {
|
|
80
|
+
const shape = entity.collisions[collisionGroup].shape || "rectangle"
|
|
81
|
+
const handler = ClampToBoundsByShape[shape] || ClampToBoundsByShape.point
|
|
82
|
+
return handler(entity, bounds, collisionGroup, depthAxis)
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
export function flip(entity, [minX, minZ, maxX, maxZ]) {
|
|
86
|
+
const [x, , z] = entity.position
|
|
87
|
+
|
|
88
|
+
entity.collisions ??= {}
|
|
89
|
+
entity.collisions.bounds ??= {}
|
|
90
|
+
entity.collisions.bounds.shape ??= "rectangle"
|
|
91
|
+
|
|
92
|
+
let width, height, depth
|
|
93
|
+
if (entity.collisions.bounds.shape === "circle") {
|
|
94
|
+
width = entity.collisions.bounds.radius * DOUBLE
|
|
95
|
+
height = entity.collisions.bounds.radius * DOUBLE
|
|
96
|
+
depth = entity.collisions.bounds.radius * DOUBLE
|
|
97
|
+
} else {
|
|
98
|
+
;[width, height, depth] = entity.collisions.bounds.size ?? entity.size
|
|
99
|
+
}
|
|
100
|
+
const halfWidth = width / HALF
|
|
101
|
+
const halfHeight = height / HALF
|
|
102
|
+
const halfDepth = depth / HALF
|
|
103
|
+
|
|
104
|
+
const left = x - halfWidth
|
|
105
|
+
const right = x + halfWidth
|
|
106
|
+
const bottom = z - halfHeight
|
|
107
|
+
const top = z + halfHeight
|
|
108
|
+
const back = z - halfDepth
|
|
109
|
+
const front = z + halfDepth
|
|
110
|
+
|
|
111
|
+
const direction = fromAngle(entity.orientation)
|
|
112
|
+
|
|
113
|
+
if (
|
|
114
|
+
left < minX ||
|
|
115
|
+
right >= maxX ||
|
|
116
|
+
bottom < minZ ||
|
|
117
|
+
top >= maxZ ||
|
|
118
|
+
back < minZ ||
|
|
119
|
+
front >= maxZ
|
|
120
|
+
) {
|
|
121
|
+
if (left < minX) {
|
|
122
|
+
direction[X] = abs(direction[X])
|
|
123
|
+
} else if (right >= maxX) {
|
|
124
|
+
direction[X] = -abs(direction[X])
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
if (back < minZ) {
|
|
128
|
+
direction[Z] = abs(direction[Z])
|
|
129
|
+
} else if (front >= maxZ) {
|
|
130
|
+
direction[Z] = -abs(direction[Z])
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
entity.acceleration = zero()
|
|
134
|
+
entity.velocity = zero()
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
entity.orientation = angle(direction)
|
|
138
|
+
}
|
|
@@ -1,43 +1,43 @@
|
|
|
1
|
-
const HALF = 2
|
|
2
|
-
|
|
3
|
-
export function calculateLandingPosition(
|
|
4
|
-
entity,
|
|
5
|
-
target,
|
|
6
|
-
collisionGroup = "platform",
|
|
7
|
-
) {
|
|
8
|
-
const entityShape = entity.collisions[collisionGroup]?.shape
|
|
9
|
-
|
|
10
|
-
if (CalculatePY[entityShape]) {
|
|
11
|
-
return CalculatePY[entityShape](entity, target, collisionGroup)
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
return calculatePYForPoint(entity, target, collisionGroup)
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
function calculatePYForPoint(entity, target, collisionGroup) {
|
|
18
|
-
const [, targetY] = target.position
|
|
19
|
-
const [, targetHeight] = target.collisions[collisionGroup].size ?? target.size
|
|
20
|
-
return targetY + targetHeight / HALF
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
function calculatePYForCircle(entity, target, collisionGroup) {
|
|
24
|
-
const entityRadius = entity.collisions[collisionGroup].radius ?? entity.radius
|
|
25
|
-
|
|
26
|
-
const [, targetY] = target.position
|
|
27
|
-
const [, targetHeight] = target.collisions[collisionGroup].size ?? target.size
|
|
28
|
-
return targetY + targetHeight / HALF + entityRadius
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
function calculatePYForRectangle(entity, target, collisionGroup) {
|
|
32
|
-
const [, entityHeight] = entity.collisions[collisionGroup].size ?? entity.size
|
|
33
|
-
|
|
34
|
-
const [, targetY] = target.position
|
|
35
|
-
const [, targetHeight] = target.collisions[collisionGroup].size ?? target.size
|
|
36
|
-
return targetY + targetHeight / HALF + entityHeight / HALF
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
const CalculatePY = {
|
|
40
|
-
point: calculatePYForPoint,
|
|
41
|
-
circle: calculatePYForCircle,
|
|
42
|
-
rectangle: calculatePYForRectangle,
|
|
43
|
-
}
|
|
1
|
+
const HALF = 2
|
|
2
|
+
|
|
3
|
+
export function calculateLandingPosition(
|
|
4
|
+
entity,
|
|
5
|
+
target,
|
|
6
|
+
collisionGroup = "platform",
|
|
7
|
+
) {
|
|
8
|
+
const entityShape = entity.collisions[collisionGroup]?.shape
|
|
9
|
+
|
|
10
|
+
if (CalculatePY[entityShape]) {
|
|
11
|
+
return CalculatePY[entityShape](entity, target, collisionGroup)
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
return calculatePYForPoint(entity, target, collisionGroup)
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
function calculatePYForPoint(entity, target, collisionGroup) {
|
|
18
|
+
const [, targetY] = target.position
|
|
19
|
+
const [, targetHeight] = target.collisions[collisionGroup].size ?? target.size
|
|
20
|
+
return targetY + targetHeight / HALF
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
function calculatePYForCircle(entity, target, collisionGroup) {
|
|
24
|
+
const entityRadius = entity.collisions[collisionGroup].radius ?? entity.radius
|
|
25
|
+
|
|
26
|
+
const [, targetY] = target.position
|
|
27
|
+
const [, targetHeight] = target.collisions[collisionGroup].size ?? target.size
|
|
28
|
+
return targetY + targetHeight / HALF + entityRadius
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
function calculatePYForRectangle(entity, target, collisionGroup) {
|
|
32
|
+
const [, entityHeight] = entity.collisions[collisionGroup].size ?? entity.size
|
|
33
|
+
|
|
34
|
+
const [, targetY] = target.position
|
|
35
|
+
const [, targetHeight] = target.collisions[collisionGroup].size ?? target.size
|
|
36
|
+
return targetY + targetHeight / HALF + entityHeight / HALF
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
const CalculatePY = {
|
|
40
|
+
point: calculatePYForPoint,
|
|
41
|
+
circle: calculatePYForCircle,
|
|
42
|
+
rectangle: calculatePYForRectangle,
|
|
43
|
+
}
|
|
@@ -1,80 +1,80 @@
|
|
|
1
|
-
import { expect, test } from "vitest"
|
|
2
|
-
|
|
3
|
-
import { calculateLandingPosition } from "./position.js"
|
|
4
|
-
|
|
5
|
-
test("it should calculate the landing position for a point entity on a platform", () => {
|
|
6
|
-
const entity = {
|
|
7
|
-
collisions: {
|
|
8
|
-
platform: { shape: "point" },
|
|
9
|
-
},
|
|
10
|
-
}
|
|
11
|
-
const target = {
|
|
12
|
-
position: [0, 0, 0],
|
|
13
|
-
collisions: {
|
|
14
|
-
platform: { size: [20, 10, 0] },
|
|
15
|
-
},
|
|
16
|
-
}
|
|
17
|
-
const collisionGroup = "platform"
|
|
18
|
-
|
|
19
|
-
const py = calculateLandingPosition(entity, target, collisionGroup)
|
|
20
|
-
|
|
21
|
-
expect(py).toBe(5)
|
|
22
|
-
})
|
|
23
|
-
|
|
24
|
-
test("it should calculate the landing position for a circular entity on a platform", () => {
|
|
25
|
-
const entity = {
|
|
26
|
-
collisions: {
|
|
27
|
-
platform: { shape: "circle", radius: 5 },
|
|
28
|
-
},
|
|
29
|
-
}
|
|
30
|
-
const target = {
|
|
31
|
-
position: [0, 0, 0],
|
|
32
|
-
collisions: {
|
|
33
|
-
platform: { size: [20, 10, 0] },
|
|
34
|
-
},
|
|
35
|
-
}
|
|
36
|
-
const collisionGroup = "platform"
|
|
37
|
-
|
|
38
|
-
const py = calculateLandingPosition(entity, target, collisionGroup)
|
|
39
|
-
|
|
40
|
-
expect(py).toBe(10)
|
|
41
|
-
})
|
|
42
|
-
|
|
43
|
-
test("it should calculate the landing position for a rectangular entity on a platform", () => {
|
|
44
|
-
const entity = {
|
|
45
|
-
size: [10, 10, 0],
|
|
46
|
-
collisions: {
|
|
47
|
-
platform: { shape: "rectangle" },
|
|
48
|
-
},
|
|
49
|
-
}
|
|
50
|
-
const target = {
|
|
51
|
-
position: [0, 0, 0],
|
|
52
|
-
collisions: {
|
|
53
|
-
platform: { size: [20, 10, 0] },
|
|
54
|
-
},
|
|
55
|
-
}
|
|
56
|
-
const collisionGroup = "platform"
|
|
57
|
-
|
|
58
|
-
const py = calculateLandingPosition(entity, target, collisionGroup)
|
|
59
|
-
|
|
60
|
-
expect(py).toBe(10)
|
|
61
|
-
})
|
|
62
|
-
|
|
63
|
-
test("it should fallback to a rectangular calculation for an unknown entity shape", () => {
|
|
64
|
-
const entity = {
|
|
65
|
-
collisions: {
|
|
66
|
-
platform: { shape: "triangle" },
|
|
67
|
-
},
|
|
68
|
-
}
|
|
69
|
-
const target = {
|
|
70
|
-
position: [0, 0, 0],
|
|
71
|
-
collisions: {
|
|
72
|
-
platform: { size: [20, 10, 0] },
|
|
73
|
-
},
|
|
74
|
-
}
|
|
75
|
-
const collisionGroup = "platform"
|
|
76
|
-
|
|
77
|
-
const py = calculateLandingPosition(entity, target, collisionGroup)
|
|
78
|
-
|
|
79
|
-
expect(py).toBe(5)
|
|
80
|
-
})
|
|
1
|
+
import { expect, test } from "vitest"
|
|
2
|
+
|
|
3
|
+
import { calculateLandingPosition } from "./position.js"
|
|
4
|
+
|
|
5
|
+
test("it should calculate the landing position for a point entity on a platform", () => {
|
|
6
|
+
const entity = {
|
|
7
|
+
collisions: {
|
|
8
|
+
platform: { shape: "point" },
|
|
9
|
+
},
|
|
10
|
+
}
|
|
11
|
+
const target = {
|
|
12
|
+
position: [0, 0, 0],
|
|
13
|
+
collisions: {
|
|
14
|
+
platform: { size: [20, 10, 0] },
|
|
15
|
+
},
|
|
16
|
+
}
|
|
17
|
+
const collisionGroup = "platform"
|
|
18
|
+
|
|
19
|
+
const py = calculateLandingPosition(entity, target, collisionGroup)
|
|
20
|
+
|
|
21
|
+
expect(py).toBe(5)
|
|
22
|
+
})
|
|
23
|
+
|
|
24
|
+
test("it should calculate the landing position for a circular entity on a platform", () => {
|
|
25
|
+
const entity = {
|
|
26
|
+
collisions: {
|
|
27
|
+
platform: { shape: "circle", radius: 5 },
|
|
28
|
+
},
|
|
29
|
+
}
|
|
30
|
+
const target = {
|
|
31
|
+
position: [0, 0, 0],
|
|
32
|
+
collisions: {
|
|
33
|
+
platform: { size: [20, 10, 0] },
|
|
34
|
+
},
|
|
35
|
+
}
|
|
36
|
+
const collisionGroup = "platform"
|
|
37
|
+
|
|
38
|
+
const py = calculateLandingPosition(entity, target, collisionGroup)
|
|
39
|
+
|
|
40
|
+
expect(py).toBe(10)
|
|
41
|
+
})
|
|
42
|
+
|
|
43
|
+
test("it should calculate the landing position for a rectangular entity on a platform", () => {
|
|
44
|
+
const entity = {
|
|
45
|
+
size: [10, 10, 0],
|
|
46
|
+
collisions: {
|
|
47
|
+
platform: { shape: "rectangle" },
|
|
48
|
+
},
|
|
49
|
+
}
|
|
50
|
+
const target = {
|
|
51
|
+
position: [0, 0, 0],
|
|
52
|
+
collisions: {
|
|
53
|
+
platform: { size: [20, 10, 0] },
|
|
54
|
+
},
|
|
55
|
+
}
|
|
56
|
+
const collisionGroup = "platform"
|
|
57
|
+
|
|
58
|
+
const py = calculateLandingPosition(entity, target, collisionGroup)
|
|
59
|
+
|
|
60
|
+
expect(py).toBe(10)
|
|
61
|
+
})
|
|
62
|
+
|
|
63
|
+
test("it should fallback to a rectangular calculation for an unknown entity shape", () => {
|
|
64
|
+
const entity = {
|
|
65
|
+
collisions: {
|
|
66
|
+
platform: { shape: "triangle" },
|
|
67
|
+
},
|
|
68
|
+
}
|
|
69
|
+
const target = {
|
|
70
|
+
position: [0, 0, 0],
|
|
71
|
+
collisions: {
|
|
72
|
+
platform: { size: [20, 10, 0] },
|
|
73
|
+
},
|
|
74
|
+
}
|
|
75
|
+
const collisionGroup = "platform"
|
|
76
|
+
|
|
77
|
+
const py = calculateLandingPosition(entity, target, collisionGroup)
|
|
78
|
+
|
|
79
|
+
expect(py).toBe(5)
|
|
80
|
+
})
|