@inglorious/engine 0.1.1 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +75 -72
- package/package.json +15 -37
- package/src/{engine/ai → ai}/movement/dynamic/align.js +9 -9
- package/src/{engine/ai → ai}/movement/dynamic/arrive.js +9 -10
- package/src/{engine/ai → ai}/movement/dynamic/evade.js +9 -9
- package/src/{engine/ai → ai}/movement/dynamic/face.js +5 -6
- package/src/{engine/ai/movement/dynamic/seek.js → ai/movement/dynamic/flee.js} +8 -7
- package/src/ai/movement/dynamic/look-where-youre-going.js +16 -0
- package/src/{engine/ai → ai}/movement/dynamic/match-velocity.js +9 -8
- package/src/{engine/ai → ai}/movement/dynamic/pursue.js +9 -9
- package/src/{engine/ai/movement/dynamic/flee.js → ai/movement/dynamic/seek.js} +7 -8
- package/src/{engine/ai → ai}/movement/dynamic/wander.js +9 -10
- package/src/{engine/ai → ai}/movement/kinematic/align.js +7 -7
- package/src/{engine/ai → ai}/movement/kinematic/arrive.js +8 -8
- package/src/{engine/ai → ai}/movement/kinematic/face.js +5 -6
- package/src/{engine/ai → ai}/movement/kinematic/flee.js +5 -5
- package/src/{engine/ai → ai}/movement/kinematic/seek.js +5 -5
- package/src/{engine/ai → ai}/movement/kinematic/seek.test.js +10 -10
- package/src/{engine/ai → ai}/movement/kinematic/wander-as-seek.js +9 -9
- package/src/{engine/ai → ai}/movement/kinematic/wander.js +5 -5
- package/src/animation/sprite.js +101 -0
- package/src/animation/ticker.js +38 -0
- package/src/behaviors/camera.js +68 -0
- package/src/behaviors/controls/dynamic/modern.js +76 -0
- package/src/behaviors/controls/dynamic/shooter.js +84 -0
- package/src/behaviors/controls/dynamic/tank.js +69 -0
- package/src/behaviors/controls/event-handlers.js +17 -0
- package/src/behaviors/controls/kinematic/modern.js +76 -0
- package/src/behaviors/controls/kinematic/shooter.js +82 -0
- package/src/behaviors/controls/kinematic/tank.js +67 -0
- package/src/behaviors/debug/collision.js +29 -0
- package/src/behaviors/fps.js +29 -0
- package/src/behaviors/fsm.js +33 -0
- package/src/{game/decorators → behaviors}/fsm.test.js +15 -22
- package/src/behaviors/game.js +15 -0
- package/src/behaviors/input/controls.js +37 -0
- package/src/behaviors/input/gamepad.js +114 -0
- package/src/behaviors/input/input.js +48 -0
- package/src/behaviors/input/keyboard.js +64 -0
- package/src/behaviors/input/mouse.js +91 -0
- package/src/behaviors/physics/bouncy.js +25 -0
- package/src/behaviors/physics/clamped.js +36 -0
- package/src/{game/decorators/collisions.js → behaviors/physics/collidable.js} +3 -7
- package/src/behaviors/physics/jumpable.js +145 -0
- package/src/behaviors/ui/button.js +17 -0
- package/src/collision/detection.js +110 -0
- package/src/core/api.js +34 -0
- package/src/core/dev-tools.js +135 -0
- package/src/core/engine.js +119 -0
- package/src/core/loop.js +15 -0
- package/src/{engine/loop → core/loops}/animation-frame.js +1 -2
- package/src/{engine/loop → core/loops}/elapsed.js +1 -2
- package/src/{engine/loop → core/loops}/fixed.js +1 -2
- package/src/{engine/loop → core/loops}/flash.js +1 -2
- package/src/{engine/loop → core/loops}/lag.js +1 -2
- package/src/core/select.js +26 -0
- package/src/core/store.js +178 -0
- package/src/core/store.test.js +110 -0
- package/src/main.js +7 -2
- package/src/{engine/movement → movement}/dynamic/modern.js +3 -6
- package/src/{engine/movement → movement}/dynamic/tank.js +9 -9
- package/src/{engine/movement → movement}/kinematic/modern.js +3 -3
- package/src/movement/kinematic/modern.test.js +27 -0
- package/src/{engine/movement → movement}/kinematic/tank.js +5 -5
- package/src/physics/bounds.js +138 -0
- package/src/physics/position.js +43 -0
- package/src/physics/position.test.js +80 -0
- package/src/systems/sprite-animation.js +27 -0
- package/src/engine/ai/movement/dynamic/look-where-youre-going.js +0 -17
- package/src/engine/collision/detection.js +0 -115
- package/src/engine/loop.js +0 -15
- package/src/engine/movement/kinematic/modern.test.js +0 -27
- 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/character.js +0 -35
- package/src/ui/canvas/form/button.js +0 -25
- package/src/ui/canvas/fps.js +0 -18
- package/src/ui/canvas/image/hitmask.js +0 -37
- package/src/ui/canvas/image/image.js +0 -37
- package/src/ui/canvas/image/sprite.js +0 -49
- package/src/ui/canvas/image/tilemap.js +0 -64
- package/src/ui/canvas/mouse.js +0 -37
- package/src/ui/canvas/shapes/circle.js +0 -31
- package/src/ui/canvas/shapes/rectangle.js +0 -31
- package/src/ui/canvas.js +0 -81
- package/src/ui/react/game/character/character.module.scss +0 -17
- package/src/ui/react/game/character/index.jsx +0 -30
- package/src/ui/react/game/cursor/cursor.module.scss +0 -47
- package/src/ui/react/game/cursor/index.jsx +0 -20
- package/src/ui/react/game/form/fields/field/field.module.scss +0 -5
- package/src/ui/react/game/form/fields/field/index.jsx +0 -56
- package/src/ui/react/game/form/fields/fields.module.scss +0 -48
- package/src/ui/react/game/form/fields/index.jsx +0 -12
- package/src/ui/react/game/form/form.module.scss +0 -18
- package/src/ui/react/game/form/index.jsx +0 -22
- package/src/ui/react/game/fps/index.jsx +0 -16
- package/src/ui/react/game/game.jsx +0 -71
- package/src/ui/react/game/index.jsx +0 -29
- package/src/ui/react/game/platform/index.jsx +0 -30
- package/src/ui/react/game/platform/platform.module.scss +0 -7
- package/src/ui/react/game/scene/index.jsx +0 -25
- package/src/ui/react/game/scene/scene.module.scss +0 -9
- package/src/ui/react/game/sprite/index.jsx +0 -58
- package/src/ui/react/game/sprite/sprite.module.css +0 -3
- package/src/ui/react/game/stats/index.jsx +0 -22
- package/src/ui/react/hocs/with-absolute-position/index.jsx +0 -20
- package/src/ui/react/hocs/with-absolute-position/with-absolute-position.module.scss +0 -5
- package/src/ui/react/index.jsx +0 -9
- package/src/utils/algorithms/decision-tree.js +0 -24
- package/src/utils/algorithms/decision-tree.test.js +0 -102
- 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 -102
- package/src/utils/data-structures/object.test.js +0 -121
- package/src/utils/data-structures/objects.js +0 -48
- 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 -117
- package/src/utils/math/geometry/circle.test.js +0 -97
- package/src/utils/math/geometry/hitmask.js +0 -39
- package/src/utils/math/geometry/hitmask.test.js +0 -84
- package/src/utils/math/geometry/line.js +0 -35
- package/src/utils/math/geometry/line.test.js +0 -49
- package/src/utils/math/geometry/platform.js +0 -42
- package/src/utils/math/geometry/platform.test.js +0 -133
- package/src/utils/math/geometry/point.js +0 -71
- package/src/utils/math/geometry/point.test.js +0 -81
- package/src/utils/math/geometry/rectangle.js +0 -45
- 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 -302
- package/src/utils/math/linear-algebra/vector.test.js +0 -257
- 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/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 -63
- package/src/utils/physics/friction.js +0 -30
- package/src/utils/physics/friction.test.js +0 -44
- package/src/utils/physics/gravity.js +0 -71
- package/src/utils/physics/gravity.test.js +0 -80
- package/src/utils/physics/jump.js +0 -41
- package/src/utils/physics/velocity.js +0 -38
|
@@ -1,65 +0,0 @@
|
|
|
1
|
-
import { expect, test } from "vitest"
|
|
2
|
-
|
|
3
|
-
import { cross, distance, dot, subtract, sum } from "./vectors.js"
|
|
4
|
-
|
|
5
|
-
test("it should compute the cross product between two vectors (aka vectorProduct)", () => {
|
|
6
|
-
const vector1 = [1, 2, 3]
|
|
7
|
-
const vector2 = [4, 5, 6]
|
|
8
|
-
const expectedResult = [-3, 6, -3]
|
|
9
|
-
|
|
10
|
-
expect(cross(vector1, vector2)).toStrictEqual(expectedResult)
|
|
11
|
-
})
|
|
12
|
-
|
|
13
|
-
test("it should compute the cross product of multiple vectors (aka vectorProduct)", () => {
|
|
14
|
-
const vectors = [
|
|
15
|
-
[1, 2, 3],
|
|
16
|
-
[4, 5, 6],
|
|
17
|
-
[7, 8, 9],
|
|
18
|
-
]
|
|
19
|
-
const expectedResult = [78, 6, -66]
|
|
20
|
-
|
|
21
|
-
expect(cross(...vectors)).toStrictEqual(expectedResult)
|
|
22
|
-
})
|
|
23
|
-
|
|
24
|
-
test("it should compute the distance between multiple vectors", () => {
|
|
25
|
-
const vectors = [
|
|
26
|
-
[0, 0, 0],
|
|
27
|
-
[4, 0, 3],
|
|
28
|
-
]
|
|
29
|
-
const expectedResult = 5
|
|
30
|
-
|
|
31
|
-
expect(distance(...vectors)).toStrictEqual(expectedResult)
|
|
32
|
-
})
|
|
33
|
-
|
|
34
|
-
test("it should compute the dot product of multiple vectors (aka scalarProduct)", () => {
|
|
35
|
-
const vectors = [
|
|
36
|
-
[1, 2, 3],
|
|
37
|
-
[4, 5, 6],
|
|
38
|
-
[7, 8, 9],
|
|
39
|
-
]
|
|
40
|
-
const expectedResult = 270
|
|
41
|
-
|
|
42
|
-
expect(dot(...vectors)).toStrictEqual(expectedResult)
|
|
43
|
-
})
|
|
44
|
-
|
|
45
|
-
test("it should subtract multiple vectors", () => {
|
|
46
|
-
const vectors = [
|
|
47
|
-
[1, 2, 3],
|
|
48
|
-
[4, 5, 6],
|
|
49
|
-
[7, 8, 9],
|
|
50
|
-
]
|
|
51
|
-
const expectedResult = [-10, -11, -12]
|
|
52
|
-
|
|
53
|
-
expect(subtract(...vectors)).toStrictEqual(expectedResult)
|
|
54
|
-
})
|
|
55
|
-
|
|
56
|
-
test("it should sum multiple vectors (aka add)", () => {
|
|
57
|
-
const vectors = [
|
|
58
|
-
[1, 2, 3],
|
|
59
|
-
[4, 5, 6],
|
|
60
|
-
[7, 8, 9],
|
|
61
|
-
]
|
|
62
|
-
const expectedResult = [12, 15, 18]
|
|
63
|
-
|
|
64
|
-
expect(sum(...vectors)).toStrictEqual(expectedResult)
|
|
65
|
-
})
|
|
@@ -1,90 +0,0 @@
|
|
|
1
|
-
const DEFAULT_PRECISION = 1 // Default precision used for snapping numbers.
|
|
2
|
-
const DEFAULT_TOLERANCE = 0.1 // Default tolerance used for comparing numbers.
|
|
3
|
-
const SQUARE_ROOT = 0.5 // Exponent used for calculating square roots.
|
|
4
|
-
|
|
5
|
-
/**
|
|
6
|
-
* Returns the absolute value of a number.
|
|
7
|
-
* @param {number} num - The number to get the absolute value of.
|
|
8
|
-
* @returns {number} The absolute value of the input number.
|
|
9
|
-
*/
|
|
10
|
-
export function abs(num) {
|
|
11
|
-
return Math.abs(num)
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
/**
|
|
15
|
-
* Clamps a number within the inclusive range specified by min and max.
|
|
16
|
-
* @param {number} num - The number to clamp.
|
|
17
|
-
* @param {number} min - The minimum value.
|
|
18
|
-
* @param {number} max - The maximum value.
|
|
19
|
-
* @returns {number} The clamped value.
|
|
20
|
-
*/
|
|
21
|
-
export function clamp(num, min, max) {
|
|
22
|
-
if (num < min) {
|
|
23
|
-
return min
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
if (num > max) {
|
|
27
|
-
return max
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
return num
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
/**
|
|
34
|
-
* Checks if two numbers are close to each other within a given tolerance.
|
|
35
|
-
* @param {number} num1 - The first number.
|
|
36
|
-
* @param {number} num2 - The second number.
|
|
37
|
-
* @param {number} [tolerance=DEFAULT_TOLERANCE] - The tolerance for comparison.
|
|
38
|
-
* @returns {boolean} True if the numbers are close, false otherwise.
|
|
39
|
-
*/
|
|
40
|
-
export function isClose(num1, num2, tolerance = DEFAULT_TOLERANCE) {
|
|
41
|
-
return abs(num1 - num2) <= tolerance
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
/**
|
|
45
|
-
* Computes the modulus of two numbers, ensuring a positive result.
|
|
46
|
-
* @param {number} dividend - The number to be divided.
|
|
47
|
-
* @param {number} divisor - The number to divide by.
|
|
48
|
-
* @returns {number} The modulus result.
|
|
49
|
-
*/
|
|
50
|
-
export function mod(dividend, divisor) {
|
|
51
|
-
return ((dividend % divisor) + divisor) % divisor
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
/**
|
|
55
|
-
* Snaps a number to the nearest multiple of a given precision.
|
|
56
|
-
* @param {number} num - The number to snap.
|
|
57
|
-
* @param {number} [precision=DEFAULT_PRECISION] - The precision to snap to.
|
|
58
|
-
* @returns {number} The snapped value.
|
|
59
|
-
*/
|
|
60
|
-
export function snap(num, precision = DEFAULT_PRECISION) {
|
|
61
|
-
return Math.round(num / precision) * precision
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
/**
|
|
65
|
-
* Alias for the `mod` function.
|
|
66
|
-
* @type {typeof mod}
|
|
67
|
-
*/
|
|
68
|
-
export const remainder = mod
|
|
69
|
-
|
|
70
|
-
/**
|
|
71
|
-
* Returns the sign of a number: 1 for positive, -1 for negative, and 0 for zero.
|
|
72
|
-
* @param {number} num - The number to get the sign of.
|
|
73
|
-
* @returns {number} The sign of the number.
|
|
74
|
-
*/
|
|
75
|
-
export function sign(num) {
|
|
76
|
-
if (!num) {
|
|
77
|
-
return num
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
return num / abs(num)
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
/**
|
|
84
|
-
* Computes the square root of a number.
|
|
85
|
-
* @param {number} num - The number to compute the square root of.
|
|
86
|
-
* @returns {number} The square root of the number.
|
|
87
|
-
*/
|
|
88
|
-
export function sqrt(num) {
|
|
89
|
-
return num ** SQUARE_ROOT
|
|
90
|
-
}
|
|
@@ -1,137 +0,0 @@
|
|
|
1
|
-
import { expect, test } from "vitest"
|
|
2
|
-
|
|
3
|
-
import { abs, clamp, isClose, mod, sign, snap, sqrt } from "./numbers.js"
|
|
4
|
-
|
|
5
|
-
test("it should return the same number if already positive", () => {
|
|
6
|
-
const num = 42
|
|
7
|
-
const expectedResult = 42
|
|
8
|
-
|
|
9
|
-
expect(abs(num)).toBe(expectedResult)
|
|
10
|
-
})
|
|
11
|
-
|
|
12
|
-
test("it should return the absolute value of a number", () => {
|
|
13
|
-
const num = -42
|
|
14
|
-
const expectedResult = 42
|
|
15
|
-
|
|
16
|
-
expect(abs(num)).toBe(expectedResult)
|
|
17
|
-
})
|
|
18
|
-
|
|
19
|
-
test("it should not clamp a number in the range", () => {
|
|
20
|
-
const num = 42
|
|
21
|
-
const min = 0
|
|
22
|
-
const max = 100
|
|
23
|
-
const expectedResult = 42
|
|
24
|
-
|
|
25
|
-
expect(clamp(num, min, max)).toBe(expectedResult)
|
|
26
|
-
})
|
|
27
|
-
|
|
28
|
-
test("it should clamp a number too small", () => {
|
|
29
|
-
const num = -42
|
|
30
|
-
const min = 0
|
|
31
|
-
const max = 100
|
|
32
|
-
const expectedResult = 0
|
|
33
|
-
|
|
34
|
-
expect(clamp(num, min, max)).toBe(expectedResult)
|
|
35
|
-
})
|
|
36
|
-
|
|
37
|
-
test("it should clamp a number too big", () => {
|
|
38
|
-
const num = 142
|
|
39
|
-
const min = 0
|
|
40
|
-
const max = 100
|
|
41
|
-
const expectedResult = 100
|
|
42
|
-
|
|
43
|
-
expect(clamp(num, min, max)).toBe(expectedResult)
|
|
44
|
-
})
|
|
45
|
-
|
|
46
|
-
test("it should check if two numbers are close given some tolerance", () => {
|
|
47
|
-
const num1 = 42
|
|
48
|
-
const num2 = 42.1
|
|
49
|
-
const tolerance = 0.2
|
|
50
|
-
const expectedResult = true
|
|
51
|
-
|
|
52
|
-
expect(isClose(num1, num2, tolerance)).toBe(expectedResult)
|
|
53
|
-
})
|
|
54
|
-
|
|
55
|
-
test("it should return zero if dividend equals divisor", () => {
|
|
56
|
-
const num = 2
|
|
57
|
-
const divisor = 2
|
|
58
|
-
const expectedResult = 0
|
|
59
|
-
|
|
60
|
-
expect(mod(num, divisor)).toBe(expectedResult)
|
|
61
|
-
})
|
|
62
|
-
|
|
63
|
-
test("it should return one if number is odd", () => {
|
|
64
|
-
const num = 3
|
|
65
|
-
const divisor = 2
|
|
66
|
-
const expectedResult = 1
|
|
67
|
-
|
|
68
|
-
expect(mod(num, divisor)).toBe(expectedResult)
|
|
69
|
-
})
|
|
70
|
-
|
|
71
|
-
test("it should return one if negative number turns to positive one", () => {
|
|
72
|
-
const num = -3
|
|
73
|
-
const divisor = 2
|
|
74
|
-
const expectedResult = 1
|
|
75
|
-
|
|
76
|
-
expect(mod(num, divisor)).toBe(expectedResult)
|
|
77
|
-
})
|
|
78
|
-
|
|
79
|
-
test("it should convert a float number greater than 1 to a range between -1 and 1", () => {
|
|
80
|
-
const num = 5 / 4
|
|
81
|
-
const divisor = 1
|
|
82
|
-
const expectedResult = 1 / 4
|
|
83
|
-
|
|
84
|
-
expect(mod(num, divisor)).toBe(expectedResult)
|
|
85
|
-
})
|
|
86
|
-
|
|
87
|
-
test("it should convert a float number greater than 2 to a range between -1 and 1", () => {
|
|
88
|
-
const num = 13 / 4
|
|
89
|
-
const divisor = 1
|
|
90
|
-
const expectedResult = 1 / 4
|
|
91
|
-
|
|
92
|
-
expect(mod(num, divisor)).toBe(expectedResult)
|
|
93
|
-
})
|
|
94
|
-
|
|
95
|
-
test("it should convert a negative float number to a range between -1 and 1", () => {
|
|
96
|
-
const num = -5 / 4
|
|
97
|
-
const divisor = 1
|
|
98
|
-
const expectedResult = 3 / 4
|
|
99
|
-
|
|
100
|
-
expect(mod(num, divisor)).toBe(expectedResult)
|
|
101
|
-
})
|
|
102
|
-
|
|
103
|
-
test("it should return one if number is positive", () => {
|
|
104
|
-
const num = 42
|
|
105
|
-
const expectedResult = 1
|
|
106
|
-
|
|
107
|
-
expect(sign(num)).toBe(expectedResult)
|
|
108
|
-
})
|
|
109
|
-
|
|
110
|
-
test("it should return minus one if number is negative", () => {
|
|
111
|
-
const num = -42
|
|
112
|
-
const expectedResult = -1
|
|
113
|
-
|
|
114
|
-
expect(sign(num)).toBe(expectedResult)
|
|
115
|
-
})
|
|
116
|
-
|
|
117
|
-
test("it should return the number itself if the sign is zero", () => {
|
|
118
|
-
const num = 0
|
|
119
|
-
const expectedResult = 0
|
|
120
|
-
|
|
121
|
-
expect(sign(num)).toBe(expectedResult)
|
|
122
|
-
})
|
|
123
|
-
|
|
124
|
-
test("it should snap the number to the given precision", () => {
|
|
125
|
-
const num = 42
|
|
126
|
-
const precision = 10
|
|
127
|
-
const expectedResult = 40
|
|
128
|
-
|
|
129
|
-
expect(snap(num, precision)).toBe(expectedResult)
|
|
130
|
-
})
|
|
131
|
-
|
|
132
|
-
test("it should compute the square root of the number", () => {
|
|
133
|
-
const num = 9
|
|
134
|
-
const expectedResult = 3
|
|
135
|
-
|
|
136
|
-
expect(sqrt(num)).toBe(expectedResult)
|
|
137
|
-
})
|
package/src/utils/math/rng.js
DELETED
|
@@ -1,44 +0,0 @@
|
|
|
1
|
-
/* eslint-disable no-magic-numbers */
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* Generates a random number.
|
|
5
|
-
* - If no arguments are provided, returns a random float between 0 (inclusive) and 1 (exclusive).
|
|
6
|
-
* - If one argument is provided, returns a random integer between 0 and the given number (inclusive).
|
|
7
|
-
* - If two or more arguments are provided, returns a random integer within the specified range and step.
|
|
8
|
-
*
|
|
9
|
-
* @param {number} [to] - The upper bound (inclusive) if one argument is provided.
|
|
10
|
-
* @param {number} [from] - The lower bound (inclusive) if two arguments are provided.
|
|
11
|
-
* @param {number} [step=1] - The step size if two or more arguments are provided.
|
|
12
|
-
* @returns {number} A random number based on the provided arguments.
|
|
13
|
-
*/
|
|
14
|
-
export function random(...args) {
|
|
15
|
-
let step, from, to
|
|
16
|
-
|
|
17
|
-
if (!args.length) {
|
|
18
|
-
return Math.random()
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
if (args.length === 1) {
|
|
22
|
-
step = 1
|
|
23
|
-
from = 0
|
|
24
|
-
to = args[0] + 1
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
if (args.length > 1) {
|
|
28
|
-
step = args[2] ?? 1
|
|
29
|
-
from = args[0] / step
|
|
30
|
-
to = (args[1] + 1) / step
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
return Math.floor(Math.random() * (to - from) + from) * step
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
/**
|
|
37
|
-
* Generates a random binomial value.
|
|
38
|
-
* The result is the difference between two random numbers.
|
|
39
|
-
*
|
|
40
|
-
* @returns {number} A random binomial value.
|
|
41
|
-
*/
|
|
42
|
-
export function randomBinomial() {
|
|
43
|
-
return random() - random()
|
|
44
|
-
}
|
|
@@ -1,39 +0,0 @@
|
|
|
1
|
-
import { expect, test } from "vitest"
|
|
2
|
-
|
|
3
|
-
import { random, randomBinomial } from "./rng.js"
|
|
4
|
-
|
|
5
|
-
test("it should create a random number in the range [0, 1)", () => {
|
|
6
|
-
const randomNumber = random()
|
|
7
|
-
|
|
8
|
-
expect(randomNumber).toBeGreaterThanOrEqual(0)
|
|
9
|
-
expect(randomNumber).toBeLessThan(1)
|
|
10
|
-
})
|
|
11
|
-
|
|
12
|
-
test("it should create a random integer in the range [0, 6]", () => {
|
|
13
|
-
const randomNumber = random(6)
|
|
14
|
-
|
|
15
|
-
expect(randomNumber).toBeGreaterThanOrEqual(0)
|
|
16
|
-
expect(randomNumber).toBeLessThanOrEqual(6)
|
|
17
|
-
})
|
|
18
|
-
|
|
19
|
-
test("it should create a random integer in the range [1, 6]", () => {
|
|
20
|
-
const randomNumber = random(1, 6)
|
|
21
|
-
|
|
22
|
-
expect(randomNumber).toBeGreaterThanOrEqual(1)
|
|
23
|
-
expect(randomNumber).toBeLessThanOrEqual(6)
|
|
24
|
-
})
|
|
25
|
-
|
|
26
|
-
test("it should create a random even number in the range [2, 6]", () => {
|
|
27
|
-
const randomNumber = random(2, 6, 2)
|
|
28
|
-
|
|
29
|
-
expect(randomNumber).toBeGreaterThanOrEqual(1)
|
|
30
|
-
expect(randomNumber).toBeLessThanOrEqual(6)
|
|
31
|
-
expect(randomNumber % 2).toBe(0)
|
|
32
|
-
})
|
|
33
|
-
|
|
34
|
-
test("it should create a random number in the range (-1, 1)", () => {
|
|
35
|
-
const randomNumber = randomBinomial()
|
|
36
|
-
|
|
37
|
-
expect(randomNumber).toBeGreaterThan(-1)
|
|
38
|
-
expect(randomNumber).toBeLessThan(1)
|
|
39
|
-
})
|
|
@@ -1,43 +0,0 @@
|
|
|
1
|
-
const HALF = 2
|
|
2
|
-
const AROUND_INDEX = 1
|
|
3
|
-
const NO_OCCURRENCES = 0
|
|
4
|
-
|
|
5
|
-
export const average = mean
|
|
6
|
-
|
|
7
|
-
export function mean(...numbers) {
|
|
8
|
-
return numbers.reduce((acc, num) => acc + num) / numbers.length
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
export function median(...numbers) {
|
|
12
|
-
const sortedNumbers = numbers.toSorted()
|
|
13
|
-
const middleIndex = numbers.length / HALF
|
|
14
|
-
|
|
15
|
-
if (Number.isInteger(middleIndex)) {
|
|
16
|
-
return mean(
|
|
17
|
-
...sortedNumbers.slice(
|
|
18
|
-
middleIndex - AROUND_INDEX,
|
|
19
|
-
middleIndex + AROUND_INDEX,
|
|
20
|
-
),
|
|
21
|
-
)
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
return sortedNumbers[Math.floor(middleIndex)]
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
export function mode(...values) {
|
|
28
|
-
const occurrences = values.reduce((acc, value) => {
|
|
29
|
-
acc[value] = acc[value] ?? NO_OCCURRENCES
|
|
30
|
-
acc[value]++
|
|
31
|
-
return acc
|
|
32
|
-
}, {})
|
|
33
|
-
|
|
34
|
-
return Object.entries(occurrences).reduce(
|
|
35
|
-
(acc, [value, occurrences]) => {
|
|
36
|
-
if (occurrences > acc.occurrences) {
|
|
37
|
-
acc = { value, occurrences }
|
|
38
|
-
}
|
|
39
|
-
return acc
|
|
40
|
-
},
|
|
41
|
-
{ occurrences: 0 },
|
|
42
|
-
).value
|
|
43
|
-
}
|
|
@@ -1,47 +0,0 @@
|
|
|
1
|
-
import { expect, test } from "vitest"
|
|
2
|
-
|
|
3
|
-
import { mean, median, mode } from "./statistics.js"
|
|
4
|
-
|
|
5
|
-
test("it should return the average of the given numbers", () => {
|
|
6
|
-
const numbers = [1, 3, 2]
|
|
7
|
-
const expectedResult = 2
|
|
8
|
-
|
|
9
|
-
expect(mean(...numbers)).toBeCloseTo(expectedResult)
|
|
10
|
-
})
|
|
11
|
-
|
|
12
|
-
test("it should return the median value from an odd list of numbers", () => {
|
|
13
|
-
const numbers = [1, 3, 2]
|
|
14
|
-
const expectedResult = 2
|
|
15
|
-
|
|
16
|
-
expect(median(...numbers)).toBe(expectedResult)
|
|
17
|
-
})
|
|
18
|
-
|
|
19
|
-
test("it should return the median value from an even list of numbers", () => {
|
|
20
|
-
const numbers = [1, 3, 2, 4]
|
|
21
|
-
const expectedResult = 2.5
|
|
22
|
-
|
|
23
|
-
expect(median(...numbers)).toBe(expectedResult)
|
|
24
|
-
})
|
|
25
|
-
|
|
26
|
-
test("it should find the mode of a list of values", () => {
|
|
27
|
-
const values = [
|
|
28
|
-
"rarely",
|
|
29
|
-
"seldom",
|
|
30
|
-
"seldom",
|
|
31
|
-
"sometimes",
|
|
32
|
-
"sometimes",
|
|
33
|
-
"sometimes",
|
|
34
|
-
"often",
|
|
35
|
-
"often",
|
|
36
|
-
"often",
|
|
37
|
-
"often",
|
|
38
|
-
"always",
|
|
39
|
-
"always",
|
|
40
|
-
"always",
|
|
41
|
-
"always",
|
|
42
|
-
"always",
|
|
43
|
-
]
|
|
44
|
-
const expectedResult = "always"
|
|
45
|
-
|
|
46
|
-
expect(mode(...values)).toBe(expectedResult)
|
|
47
|
-
})
|
|
@@ -1,89 +0,0 @@
|
|
|
1
|
-
import { mod } from "./numbers.js"
|
|
2
|
-
|
|
3
|
-
const HALF_CIRCLE_IN_DEGRESS = 180 // Half-circle in degrees (180°)
|
|
4
|
-
const FULL_CIRCLE = 2 // Full circle multiplier for radians (2π)
|
|
5
|
-
|
|
6
|
-
/**
|
|
7
|
-
* Calculates the arctangent of the quotient of its arguments.
|
|
8
|
-
* @param {number} y - The y-coordinate.
|
|
9
|
-
* @param {number} x - The x-coordinate.
|
|
10
|
-
* @returns {number} The angle in radians.
|
|
11
|
-
*/
|
|
12
|
-
export function atan2(y, x) {
|
|
13
|
-
return Math.atan2(y, x)
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
/**
|
|
17
|
-
* Calculates the cosine of an angle.
|
|
18
|
-
* @param {number} angle - The angle in radians.
|
|
19
|
-
* @returns {number} The cosine of the angle.
|
|
20
|
-
*/
|
|
21
|
-
export function cos(angle) {
|
|
22
|
-
return Math.cos(angle)
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
/**
|
|
26
|
-
* Alias for the `cos` function.
|
|
27
|
-
* @type {typeof cos}.
|
|
28
|
-
*/
|
|
29
|
-
export const cosine = cos
|
|
30
|
-
|
|
31
|
-
/**
|
|
32
|
-
* Returns the value of π (pi).
|
|
33
|
-
* @returns {number} The value of π.
|
|
34
|
-
*/
|
|
35
|
-
export function pi() {
|
|
36
|
-
return Math.PI
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
/**
|
|
40
|
-
* Calculates the sine of an angle.
|
|
41
|
-
* @param {number} angle - The angle in radians.
|
|
42
|
-
* @returns {number} The sine of the angle.
|
|
43
|
-
*/
|
|
44
|
-
export function sin(angle) {
|
|
45
|
-
return Math.sin(angle)
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
/**
|
|
49
|
-
* Alias for the `sin` function.
|
|
50
|
-
* @type {typeof sin}.
|
|
51
|
-
*/
|
|
52
|
-
export const sine = sin
|
|
53
|
-
|
|
54
|
-
/**
|
|
55
|
-
* Converts an angle from radians to degrees.
|
|
56
|
-
* @param {number} radians - The angle in radians.
|
|
57
|
-
* @returns {number} The angle in degrees.
|
|
58
|
-
*/
|
|
59
|
-
export function toDegrees(radians) {
|
|
60
|
-
return (radians * HALF_CIRCLE_IN_DEGRESS) / pi()
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
/**
|
|
64
|
-
* Converts an angle from degrees to radians.
|
|
65
|
-
* @param {number} degrees - The angle in degrees.
|
|
66
|
-
* @returns {number} The angle in radians.
|
|
67
|
-
*/
|
|
68
|
-
export function toRadians(degrees) {
|
|
69
|
-
return (degrees * pi()) / HALF_CIRCLE_IN_DEGRESS
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
/**
|
|
73
|
-
* Normalizes an angle to the range [-π, π].
|
|
74
|
-
* @param {number} angle - The angle in radians.
|
|
75
|
-
* @returns {number} The normalized angle in radians.
|
|
76
|
-
*/
|
|
77
|
-
export function toRange(angle) {
|
|
78
|
-
if (angle > -pi() && angle < pi()) {
|
|
79
|
-
return angle
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
angle = mod(angle, FULL_CIRCLE * pi())
|
|
83
|
-
|
|
84
|
-
if (angle > pi()) {
|
|
85
|
-
angle -= FULL_CIRCLE * pi()
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
return angle
|
|
89
|
-
}
|
|
@@ -1,52 +0,0 @@
|
|
|
1
|
-
import { expect, test } from "vitest"
|
|
2
|
-
|
|
3
|
-
import { pi, toDegrees, toRadians, toRange } from "./trigonometry.js"
|
|
4
|
-
|
|
5
|
-
test("it should convert radians to degrees", () => {
|
|
6
|
-
const radians = pi() / 4
|
|
7
|
-
const expectedResult = 45
|
|
8
|
-
|
|
9
|
-
expect(toDegrees(radians)).toBeCloseTo(expectedResult)
|
|
10
|
-
})
|
|
11
|
-
|
|
12
|
-
test("it should convert radians to degrees", () => {
|
|
13
|
-
const degrees = 45
|
|
14
|
-
const expectedResult = pi() / 4
|
|
15
|
-
|
|
16
|
-
expect(toRadians(degrees)).toBeCloseTo(expectedResult)
|
|
17
|
-
})
|
|
18
|
-
|
|
19
|
-
test("it should convert an angle greater than pi to a range between -pi and pi", () => {
|
|
20
|
-
const angle = (5 / 4) * pi()
|
|
21
|
-
const expectedResult = (-3 / 4) * pi()
|
|
22
|
-
|
|
23
|
-
expect(toRange(angle)).toBeCloseTo(expectedResult)
|
|
24
|
-
})
|
|
25
|
-
|
|
26
|
-
test("it should convert an angle greater than 2pi to a range between -pi and pi", () => {
|
|
27
|
-
const angle = (13 / 4) * pi()
|
|
28
|
-
const expectedResult = (-3 / 4) * pi()
|
|
29
|
-
|
|
30
|
-
expect(toRange(angle)).toBeCloseTo(expectedResult)
|
|
31
|
-
})
|
|
32
|
-
|
|
33
|
-
test("it should convert an angle less than pi to a range between -pi and pi", () => {
|
|
34
|
-
const angle = (-5 / 4) * pi()
|
|
35
|
-
const expectedResult = (3 / 4) * pi()
|
|
36
|
-
|
|
37
|
-
expect(toRange(angle)).toBeCloseTo(expectedResult)
|
|
38
|
-
})
|
|
39
|
-
|
|
40
|
-
test("it should convert an angle less than 2pi to a range between -pi and pi", () => {
|
|
41
|
-
const angle = (-13 / 4) * pi()
|
|
42
|
-
const expectedResult = (3 / 4) * pi()
|
|
43
|
-
|
|
44
|
-
expect(toRange(angle)).toBeCloseTo(expectedResult)
|
|
45
|
-
})
|
|
46
|
-
|
|
47
|
-
test("it should not convert an angle already in the range [-pi, pi]", () => {
|
|
48
|
-
const angle = (3 / 4) * pi()
|
|
49
|
-
const expectedResult = (3 / 4) * pi()
|
|
50
|
-
|
|
51
|
-
expect(toRange(angle)).toBe(expectedResult)
|
|
52
|
-
})
|
|
@@ -1,63 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* @typedef {import('@inglorious/utils/math/linear-algebra/types').Vector3} Vector3
|
|
3
|
-
*/
|
|
4
|
-
|
|
5
|
-
import {
|
|
6
|
-
clamp,
|
|
7
|
-
multiply,
|
|
8
|
-
zero,
|
|
9
|
-
} from "@inglorious/utils/math/linear-algebra/vector.js"
|
|
10
|
-
import { sum } from "@inglorious/utils/math/linear-algebra/vectors.js"
|
|
11
|
-
|
|
12
|
-
import { applyFriction } from "./friction.js"
|
|
13
|
-
|
|
14
|
-
const DEFAULT_OPTIONS = { dt: 0 } // Default options for the applyAcceleration function.
|
|
15
|
-
const NO_FRICTION = 0 // No friction constant.
|
|
16
|
-
const HALF_ACCELERATION = 0.5 // Half of the acceleration factor used in position calculation.
|
|
17
|
-
|
|
18
|
-
/**
|
|
19
|
-
* Applies acceleration to an object using Euler's integration method.
|
|
20
|
-
*
|
|
21
|
-
* Euler's Integration:
|
|
22
|
-
* v += a * dt
|
|
23
|
-
* p += v * dt + 1/2 * a * dt * dt
|
|
24
|
-
*
|
|
25
|
-
* @param {Object} params - The parameters for the function.
|
|
26
|
-
* @param {number} params.maxAcceleration - The maximum allowed acceleration.
|
|
27
|
-
* @param {number} params.maxSpeed - The maximum allowed speed.
|
|
28
|
-
* @param {Vector3} [params.acceleration] - The current acceleration vector. Defaults to a zero vector.
|
|
29
|
-
* @param {Vector3} [params.velocity] - The current velocity vector. Defaults to a zero vector.
|
|
30
|
-
* @param {Vector3} [params.position] - The current position vector. Defaults to a zero vector.
|
|
31
|
-
* @param {number} params.friction - The friction coefficient. Defaults to 0.
|
|
32
|
-
* @param {Object} [options=DEFAULT_OPTIONS] - Additional options.
|
|
33
|
-
* @param {number} options.dt - The time delta for the calculation. Defaults to 0.
|
|
34
|
-
* @returns {Object} - The updated acceleration, velocity, and position.
|
|
35
|
-
*/
|
|
36
|
-
export function applyAcceleration(params, options = DEFAULT_OPTIONS) {
|
|
37
|
-
let {
|
|
38
|
-
maxAcceleration,
|
|
39
|
-
maxSpeed,
|
|
40
|
-
acceleration = zero(),
|
|
41
|
-
velocity = zero(),
|
|
42
|
-
position = zero(),
|
|
43
|
-
friction = NO_FRICTION,
|
|
44
|
-
} = params
|
|
45
|
-
const { dt } = options
|
|
46
|
-
|
|
47
|
-
// Clamp acceleration to the maximum allowed range
|
|
48
|
-
acceleration = clamp(acceleration, -maxAcceleration, maxAcceleration)
|
|
49
|
-
|
|
50
|
-
// Update velocity with acceleration and clamp to the maximum allowed speed
|
|
51
|
-
velocity = sum(velocity, multiply(acceleration, dt))
|
|
52
|
-
velocity = clamp(velocity, -maxSpeed, maxSpeed)
|
|
53
|
-
velocity = applyFriction({ velocity, friction }, options)
|
|
54
|
-
|
|
55
|
-
// Update position with velocity and acceleration
|
|
56
|
-
position = sum(
|
|
57
|
-
position,
|
|
58
|
-
multiply(velocity, dt),
|
|
59
|
-
multiply(acceleration, HALF_ACCELERATION * dt * dt),
|
|
60
|
-
)
|
|
61
|
-
|
|
62
|
-
return { acceleration, velocity, position }
|
|
63
|
-
}
|
|
@@ -1,30 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* @typedef {import('@inglorious/utils/math/linear-algebra/types').Vector3} Vector3
|
|
3
|
-
*/
|
|
4
|
-
|
|
5
|
-
import {
|
|
6
|
-
magnitude,
|
|
7
|
-
setMagnitude,
|
|
8
|
-
zero,
|
|
9
|
-
} from "@inglorious/utils/math/linear-algebra/vector.js"
|
|
10
|
-
|
|
11
|
-
const DEFAULT_OPTIONS = { dt: 0 } // Default options for the applyFriction function.
|
|
12
|
-
const NO_FRICTION = 0 // No friction constant.
|
|
13
|
-
|
|
14
|
-
/**
|
|
15
|
-
* Applies friction to a given velocity vector.
|
|
16
|
-
*
|
|
17
|
-
* @param {Object} params - The parameters for the function.
|
|
18
|
-
* @param {Vector3} params.velocity - The velocity vector. Defaults to a zero vector.
|
|
19
|
-
* @param {number} params.friction - The friction coefficient. Defaults to 0.
|
|
20
|
-
* @param {Object} [options=DEFAULT_OPTIONS] - Additional options.
|
|
21
|
-
* @param {number} options.dt - The time delta for the calculation. Defaults to 0.
|
|
22
|
-
* @returns {Vector3} - The updated velocity vector after applying friction.
|
|
23
|
-
*/
|
|
24
|
-
export function applyFriction(params, options = DEFAULT_OPTIONS) {
|
|
25
|
-
let { velocity = zero(), friction = NO_FRICTION } = params
|
|
26
|
-
const { dt } = options
|
|
27
|
-
const length = magnitude(velocity)
|
|
28
|
-
|
|
29
|
-
return length ? setMagnitude(velocity, length - friction * dt) : velocity
|
|
30
|
-
}
|