@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.
Files changed (292) hide show
  1. package/README.md +39 -36
  2. package/package.json +20 -33
  3. package/src/engine/ai/movement/dynamic/align.js +63 -63
  4. package/src/engine/ai/movement/dynamic/arrive.js +42 -43
  5. package/src/engine/ai/movement/dynamic/evade.js +38 -38
  6. package/src/engine/ai/movement/dynamic/face.js +19 -20
  7. package/src/engine/ai/movement/dynamic/flee.js +45 -45
  8. package/src/engine/ai/movement/dynamic/look-where-youre-going.js +16 -17
  9. package/src/engine/ai/movement/dynamic/match-velocity.js +51 -50
  10. package/src/engine/ai/movement/dynamic/pursue.js +38 -38
  11. package/src/engine/ai/movement/dynamic/seek.js +44 -44
  12. package/src/engine/ai/movement/dynamic/wander.js +31 -32
  13. package/src/engine/ai/movement/kinematic/align.js +37 -37
  14. package/src/engine/ai/movement/kinematic/arrive.js +42 -42
  15. package/src/engine/ai/movement/kinematic/face.js +19 -20
  16. package/src/engine/ai/movement/kinematic/flee.js +26 -26
  17. package/src/engine/ai/movement/kinematic/seek.js +26 -26
  18. package/src/engine/ai/movement/kinematic/seek.test.js +42 -42
  19. package/src/engine/ai/movement/kinematic/wander-as-seek.js +31 -31
  20. package/src/engine/ai/movement/kinematic/wander.js +27 -27
  21. package/src/engine/animation/sprite.js +101 -0
  22. package/src/engine/animation/ticker.js +38 -0
  23. package/src/engine/behaviors/camera.js +68 -0
  24. package/src/engine/behaviors/controls/dynamic/modern.js +76 -0
  25. package/src/engine/behaviors/controls/dynamic/shooter.js +84 -0
  26. package/src/engine/behaviors/controls/dynamic/tank.js +69 -0
  27. package/src/engine/behaviors/controls/event-handlers.js +17 -0
  28. package/src/engine/behaviors/controls/kinematic/modern.js +76 -0
  29. package/src/engine/behaviors/controls/kinematic/shooter.js +82 -0
  30. package/src/engine/behaviors/controls/kinematic/tank.js +67 -0
  31. package/src/engine/behaviors/debug/collision.js +35 -0
  32. package/src/engine/behaviors/fps.js +29 -0
  33. package/src/engine/behaviors/fsm.js +33 -0
  34. package/src/{game/decorators → engine/behaviors}/fsm.test.js +49 -56
  35. package/src/engine/behaviors/game.js +15 -0
  36. package/src/engine/behaviors/input/controls.js +37 -0
  37. package/src/engine/behaviors/input/gamepad.js +114 -0
  38. package/src/engine/behaviors/input/input.js +48 -0
  39. package/src/engine/behaviors/input/keyboard.js +64 -0
  40. package/src/engine/behaviors/input/mouse.js +91 -0
  41. package/src/engine/behaviors/physics/bouncy.js +25 -0
  42. package/src/engine/behaviors/physics/clamped.js +36 -0
  43. package/src/{game/decorators/collisions.js → engine/behaviors/physics/collidable.js} +20 -24
  44. package/src/engine/behaviors/physics/jumpable.js +145 -0
  45. package/src/engine/behaviors/ui/button.js +17 -0
  46. package/src/engine/collision/detection.js +110 -115
  47. package/src/engine/core/api.js +34 -0
  48. package/src/engine/core/dev-tools.js +135 -0
  49. package/src/engine/core/engine.js +119 -0
  50. package/src/engine/core/loop.js +15 -0
  51. package/src/engine/{loop → core/loops}/animation-frame.js +25 -26
  52. package/src/engine/{loop → core/loops}/elapsed.js +22 -23
  53. package/src/engine/{loop → core/loops}/fixed.js +27 -28
  54. package/src/engine/{loop → core/loops}/flash.js +13 -14
  55. package/src/engine/{loop → core/loops}/lag.js +26 -27
  56. package/src/engine/core/select.js +26 -0
  57. package/src/engine/core/store.js +178 -0
  58. package/src/engine/core/store.test.js +110 -0
  59. package/src/engine/movement/dynamic/modern.js +21 -24
  60. package/src/engine/movement/dynamic/tank.js +43 -43
  61. package/src/engine/movement/kinematic/modern.js +16 -16
  62. package/src/engine/movement/kinematic/modern.test.js +27 -27
  63. package/src/engine/movement/kinematic/tank.js +27 -27
  64. package/src/engine/physics/bounds.js +138 -0
  65. package/src/engine/physics/position.js +43 -0
  66. package/src/engine/physics/position.test.js +80 -0
  67. package/src/engine/systems/sprite-animation.js +27 -0
  68. package/src/main.js +10 -5
  69. package/src/renderers/canvas/absolute-position.js +18 -0
  70. package/src/renderers/canvas/camera.js +13 -0
  71. package/src/renderers/canvas/canvas-renderer.js +68 -0
  72. package/src/{ui → renderers}/canvas/character.js +38 -35
  73. package/src/{ui → renderers}/canvas/form/button.js +25 -25
  74. package/src/{ui → renderers}/canvas/fps.js +18 -18
  75. package/src/renderers/canvas/image/hitmask.js +51 -0
  76. package/src/{ui → renderers}/canvas/image/image.js +34 -37
  77. package/src/{ui → renderers}/canvas/image/sprite.js +49 -49
  78. package/src/{ui → renderers}/canvas/image/tilemap.js +66 -64
  79. package/src/{ui → renderers}/canvas/mouse.js +37 -37
  80. package/src/renderers/canvas/rendering-system.js +79 -0
  81. package/src/{ui → renderers}/canvas/shapes/circle.js +29 -31
  82. package/src/{ui → renderers}/canvas/shapes/rectangle.js +27 -31
  83. package/src/renderers/react/game/character/index.jsx +20 -0
  84. package/src/{ui → renderers}/react/game/cursor/index.jsx +20 -20
  85. package/src/{ui → renderers}/react/game/form/fields/field/index.jsx +56 -56
  86. package/src/{ui → renderers}/react/game/form/fields/index.jsx +12 -12
  87. package/src/{ui → renderers}/react/game/form/index.jsx +22 -22
  88. package/src/{ui → renderers}/react/game/fps/index.jsx +16 -16
  89. package/src/{ui → renderers}/react/game/game.jsx +72 -71
  90. package/src/{ui → renderers}/react/game/index.jsx +29 -29
  91. package/src/{ui → renderers}/react/game/platform/index.jsx +30 -30
  92. package/src/{ui → renderers}/react/game/scene/index.jsx +27 -25
  93. package/src/{ui → renderers}/react/game/sprite/index.jsx +60 -58
  94. package/src/{ui → renderers}/react/game/stats/index.jsx +22 -22
  95. package/src/{ui → renderers}/react/hocs/with-absolute-position/index.jsx +20 -20
  96. package/src/{ui → renderers}/react/index.jsx +9 -9
  97. package/src/utils/algorithms/decision-tree.js +24 -24
  98. package/src/utils/algorithms/decision-tree.test.js +153 -102
  99. package/src/utils/algorithms/path-finding.js +155 -155
  100. package/src/utils/algorithms/path-finding.test.js +151 -151
  101. package/src/utils/data-structures/array.js +83 -83
  102. package/src/utils/data-structures/array.test.js +173 -173
  103. package/src/utils/data-structures/board.js +159 -159
  104. package/src/utils/data-structures/board.test.js +242 -242
  105. package/src/utils/data-structures/boolean.js +9 -9
  106. package/src/utils/data-structures/heap.js +164 -164
  107. package/src/utils/data-structures/heap.test.js +103 -103
  108. package/src/utils/data-structures/object.js +138 -102
  109. package/src/utils/data-structures/object.test.js +218 -121
  110. package/src/utils/data-structures/objects.js +66 -48
  111. package/src/utils/data-structures/objects.test.js +99 -99
  112. package/src/utils/data-structures/tree.js +36 -36
  113. package/src/utils/data-structures/tree.test.js +33 -33
  114. package/src/utils/functions/functions.js +19 -19
  115. package/src/utils/functions/functions.test.js +23 -23
  116. package/src/utils/math/geometry/circle.js +70 -117
  117. package/src/utils/math/geometry/circle.test.js +97 -97
  118. package/src/utils/math/geometry/hitmask.js +70 -39
  119. package/src/utils/math/geometry/hitmask.test.js +155 -84
  120. package/src/utils/math/geometry/line.js +35 -35
  121. package/src/utils/math/geometry/line.test.js +49 -49
  122. package/src/utils/math/geometry/point.js +78 -71
  123. package/src/utils/math/geometry/point.test.js +81 -81
  124. package/src/utils/math/geometry/rectangle.js +76 -45
  125. package/src/utils/math/geometry/rectangle.test.js +42 -42
  126. package/src/utils/math/geometry/segment.js +80 -80
  127. package/src/utils/math/geometry/segment.test.js +183 -183
  128. package/src/utils/math/geometry/triangle.js +15 -15
  129. package/src/utils/math/geometry/triangle.test.js +11 -11
  130. package/src/utils/math/linear-algebra/2d.js +28 -28
  131. package/src/utils/math/linear-algebra/2d.test.js +17 -17
  132. package/src/utils/math/linear-algebra/quaternion.js +22 -22
  133. package/src/utils/math/linear-algebra/quaternion.test.js +25 -25
  134. package/src/utils/math/linear-algebra/quaternions.js +20 -20
  135. package/src/utils/math/linear-algebra/quaternions.test.js +29 -29
  136. package/src/utils/math/linear-algebra/vector.js +327 -302
  137. package/src/utils/math/linear-algebra/vector.test.js +265 -257
  138. package/src/utils/math/linear-algebra/vectors.js +122 -122
  139. package/src/utils/math/linear-algebra/vectors.test.js +65 -65
  140. package/src/utils/math/linear-interpolation.js +9 -0
  141. package/src/utils/math/numbers.js +90 -90
  142. package/src/utils/math/numbers.test.js +137 -137
  143. package/src/utils/math/rng.js +44 -44
  144. package/src/utils/math/rng.test.js +39 -39
  145. package/src/utils/math/statistics.js +43 -43
  146. package/src/utils/math/statistics.test.js +47 -47
  147. package/src/utils/math/trigonometry.js +89 -89
  148. package/src/utils/math/trigonometry.test.js +52 -52
  149. package/src/utils/physics/acceleration.js +61 -63
  150. package/src/utils/physics/friction.js +28 -30
  151. package/src/utils/physics/friction.test.js +42 -44
  152. package/src/utils/physics/gravity.js +69 -71
  153. package/src/utils/physics/gravity.test.js +77 -80
  154. package/src/utils/physics/jump.js +31 -41
  155. package/src/utils/physics/velocity.js +36 -38
  156. package/src/docs/ai/movement/dynamic/align.js +0 -131
  157. package/src/docs/ai/movement/dynamic/arrive.js +0 -88
  158. package/src/docs/ai/movement/dynamic/dynamic.mdx +0 -99
  159. package/src/docs/ai/movement/dynamic/dynamic.stories.js +0 -58
  160. package/src/docs/ai/movement/dynamic/evade.js +0 -72
  161. package/src/docs/ai/movement/dynamic/face.js +0 -90
  162. package/src/docs/ai/movement/dynamic/flee.js +0 -38
  163. package/src/docs/ai/movement/dynamic/look-where-youre-going.js +0 -114
  164. package/src/docs/ai/movement/dynamic/match-velocity.js +0 -92
  165. package/src/docs/ai/movement/dynamic/pursue.js +0 -72
  166. package/src/docs/ai/movement/dynamic/seek.js +0 -37
  167. package/src/docs/ai/movement/dynamic/wander.js +0 -71
  168. package/src/docs/ai/movement/kinematic/align.js +0 -122
  169. package/src/docs/ai/movement/kinematic/arrive.js +0 -78
  170. package/src/docs/ai/movement/kinematic/face.js +0 -82
  171. package/src/docs/ai/movement/kinematic/flee.js +0 -36
  172. package/src/docs/ai/movement/kinematic/kinematic.mdx +0 -67
  173. package/src/docs/ai/movement/kinematic/kinematic.stories.js +0 -42
  174. package/src/docs/ai/movement/kinematic/seek.js +0 -34
  175. package/src/docs/ai/movement/kinematic/wander-as-seek.js +0 -62
  176. package/src/docs/ai/movement/kinematic/wander.js +0 -28
  177. package/src/docs/bounds.js +0 -7
  178. package/src/docs/code-reuse.js +0 -35
  179. package/src/docs/collision/circles.js +0 -58
  180. package/src/docs/collision/collision.mdx +0 -27
  181. package/src/docs/collision/collision.stories.js +0 -22
  182. package/src/docs/collision/platform.js +0 -76
  183. package/src/docs/collision/tilemap.js +0 -181
  184. package/src/docs/empty.js +0 -1
  185. package/src/docs/engine.mdx +0 -81
  186. package/src/docs/engine.stories.js +0 -37
  187. package/src/docs/event-handlers.js +0 -68
  188. package/src/docs/framerate.js +0 -37
  189. package/src/docs/game.jsx +0 -15
  190. package/src/docs/image/image.js +0 -19
  191. package/src/docs/image/image.stories.js +0 -22
  192. package/src/docs/image/sprite.js +0 -39
  193. package/src/docs/image/tilemap.js +0 -84
  194. package/src/docs/input/controls.js +0 -67
  195. package/src/docs/input/gamepad.js +0 -67
  196. package/src/docs/input/input.mdx +0 -55
  197. package/src/docs/input/input.stories.js +0 -27
  198. package/src/docs/input/keyboard.js +0 -58
  199. package/src/docs/input/mouse.js +0 -32
  200. package/src/docs/instances.js +0 -49
  201. package/src/docs/player/dynamic/double-jump.js +0 -90
  202. package/src/docs/player/dynamic/dynamic.stories.js +0 -32
  203. package/src/docs/player/dynamic/jump.js +0 -83
  204. package/src/docs/player/dynamic/modern-controls.js +0 -57
  205. package/src/docs/player/dynamic/shooter-controls.js +0 -51
  206. package/src/docs/player/dynamic/tank-controls.js +0 -44
  207. package/src/docs/player/kinematic/double-jump.js +0 -90
  208. package/src/docs/player/kinematic/jump.js +0 -82
  209. package/src/docs/player/kinematic/kinematic.stories.js +0 -32
  210. package/src/docs/player/kinematic/modern-controls.js +0 -56
  211. package/src/docs/player/kinematic/shooter-controls.js +0 -48
  212. package/src/docs/player/kinematic/tank-controls.js +0 -42
  213. package/src/docs/quick-start/first-game.js +0 -49
  214. package/src/docs/quick-start/hello-world.js +0 -1
  215. package/src/docs/quick-start.mdx +0 -127
  216. package/src/docs/quick-start.stories.js +0 -17
  217. package/src/docs/recipes/add-and-remove.js +0 -71
  218. package/src/docs/recipes/add-instance.js +0 -42
  219. package/src/docs/recipes/decision-tree.js +0 -169
  220. package/src/docs/recipes/random-instances.js +0 -25
  221. package/src/docs/recipes/recipes.mdx +0 -81
  222. package/src/docs/recipes/recipes.stories.js +0 -37
  223. package/src/docs/recipes/remove-instance.js +0 -52
  224. package/src/docs/recipes/states.js +0 -64
  225. package/src/docs/ui/button.js +0 -28
  226. package/src/docs/ui/form.stories.js +0 -55
  227. package/src/docs/ui-chooser.jsx +0 -6
  228. package/src/docs/utils/data-structures/object.mdx +0 -47
  229. package/src/docs/utils/data-structures/objects.mdx +0 -30
  230. package/src/docs/utils/functions/functions.mdx +0 -34
  231. package/src/docs/utils/math/geometry/circle.mdx +0 -55
  232. package/src/docs/utils/math/geometry/point.mdx +0 -38
  233. package/src/docs/utils/math/geometry/rectangle.mdx +0 -24
  234. package/src/docs/utils/math/geometry/segment.mdx +0 -55
  235. package/src/docs/utils/math/geometry/triangle.mdx +0 -22
  236. package/src/docs/utils/math/linear-algebra/2d.mdx +0 -22
  237. package/src/docs/utils/math/linear-algebra/quaternion.mdx +0 -21
  238. package/src/docs/utils/math/linear-algebra/quaternions.mdx +0 -22
  239. package/src/docs/utils/math/linear-algebra/vector.mdx +0 -177
  240. package/src/docs/utils/math/linear-algebra/vectors.mdx +0 -58
  241. package/src/docs/utils/math/numbers.mdx +0 -76
  242. package/src/docs/utils/math/random.mdx +0 -35
  243. package/src/docs/utils/math/statistics.mdx +0 -38
  244. package/src/docs/utils/math/trigonometry.mdx +0 -85
  245. package/src/docs/utils/physics/friction.mdx +0 -20
  246. package/src/docs/utils/physics/gravity.mdx +0 -28
  247. package/src/engine/loop.js +0 -15
  248. package/src/engine/store.js +0 -174
  249. package/src/engine/store.test.js +0 -256
  250. package/src/engine.js +0 -74
  251. package/src/game/animation.js +0 -26
  252. package/src/game/bounds.js +0 -66
  253. package/src/game/decorators/character.js +0 -5
  254. package/src/game/decorators/clamp-to-bounds.js +0 -15
  255. package/src/game/decorators/controls/dynamic/modern.js +0 -48
  256. package/src/game/decorators/controls/dynamic/shooter.js +0 -47
  257. package/src/game/decorators/controls/dynamic/tank.js +0 -55
  258. package/src/game/decorators/controls/kinematic/modern.js +0 -49
  259. package/src/game/decorators/controls/kinematic/shooter.js +0 -45
  260. package/src/game/decorators/controls/kinematic/tank.js +0 -52
  261. package/src/game/decorators/debug/collisions.js +0 -32
  262. package/src/game/decorators/double-jump.js +0 -70
  263. package/src/game/decorators/fps.js +0 -30
  264. package/src/game/decorators/fsm.js +0 -27
  265. package/src/game/decorators/game.js +0 -11
  266. package/src/game/decorators/image/image.js +0 -5
  267. package/src/game/decorators/image/sprite.js +0 -5
  268. package/src/game/decorators/image/tilemap.js +0 -5
  269. package/src/game/decorators/input/controls.js +0 -27
  270. package/src/game/decorators/input/gamepad.js +0 -74
  271. package/src/game/decorators/input/input.js +0 -41
  272. package/src/game/decorators/input/keyboard.js +0 -49
  273. package/src/game/decorators/input/mouse.js +0 -65
  274. package/src/game/decorators/jump.js +0 -72
  275. package/src/game/decorators/platform.js +0 -5
  276. package/src/game/decorators/ui/button.js +0 -21
  277. package/src/game/sprite.js +0 -119
  278. package/src/ui/canvas/absolute-position.js +0 -17
  279. package/src/ui/canvas/image/hitmask.js +0 -37
  280. package/src/ui/canvas.js +0 -81
  281. package/src/ui/react/game/character/index.jsx +0 -30
  282. package/src/utils/math/geometry/platform.js +0 -42
  283. package/src/utils/math/geometry/platform.test.js +0 -133
  284. /package/src/{ui → renderers}/react/game/character/character.module.scss +0 -0
  285. /package/src/{ui → renderers}/react/game/cursor/cursor.module.scss +0 -0
  286. /package/src/{ui → renderers}/react/game/form/fields/field/field.module.scss +0 -0
  287. /package/src/{ui → renderers}/react/game/form/fields/fields.module.scss +0 -0
  288. /package/src/{ui → renderers}/react/game/form/form.module.scss +0 -0
  289. /package/src/{ui → renderers}/react/game/platform/platform.module.scss +0 -0
  290. /package/src/{ui → renderers}/react/game/scene/scene.module.scss +0 -0
  291. /package/src/{ui → renderers}/react/game/sprite/sprite.module.css +0 -0
  292. /package/src/{ui → renderers}/react/hocs/with-absolute-position/with-absolute-position.module.scss +0 -0
@@ -1,302 +1,327 @@
1
- /**
2
- * @typedef {import('./types').Vector2} Vector2
3
- * @typedef {import('./types').Vector3} Vector3
4
- */
5
-
6
- import { hypothenuse } from "@inglorious/utils/math/geometry/triangle.js"
7
- import {
8
- abs as nAbs,
9
- clamp as nClamp,
10
- mod as nMod,
11
- snap as nSnap,
12
- } from "@inglorious/utils/math/numbers.js"
13
- import { atan2, cos, sin } from "@inglorious/utils/math/trigonometry.js"
14
-
15
- import { from2D, to2D } from "./2d.js"
16
- import { quaternion } from "./quaternion.js"
17
- import { cross, sum } from "./vectors.js"
18
-
19
- const ZERO_VECTOR = [0, 0, 0] // eslint-disable-line no-magic-numbers
20
- const UNIT_VECTOR = [1, 0, 0] // eslint-disable-line no-magic-numbers
21
-
22
- const X = 0
23
- const Z = 2
24
- const LAST_COORDINATE = 1
25
- const TWO_COORDINATES = 2
26
- const NO_Y = 0
27
- const DEFAULT_PRECISION = 1
28
- const DEFAULT_DECIMALS = 0
29
-
30
- /**
31
- * Returns the absolute value of each component in the vector.
32
- * @param {Vector3} vector - The input vector.
33
- * @returns {Vector3} The vector with absolute values.
34
- */
35
- export function abs(vector) {
36
- return vector.map(nAbs)
37
- }
38
-
39
- /**
40
- * Calculates the angle of the vector in radians.
41
- * @param {Vector3} vector - The input vector.
42
- * @returns {number} The angle in radians.
43
- */
44
- export function angle(vector) {
45
- return atan2(vector[vector.length - LAST_COORDINATE], vector[X])
46
- }
47
-
48
- /**
49
- * Clamps the magnitude of the vector between the given min and max values.
50
- * @param {Vector3} vector - The input vector.
51
- * @param {number} min - The minimum magnitude.
52
- * @param {number} max - The maximum magnitude.
53
- * @returns {Vector3} The clamped vector.
54
- */
55
- export function clamp(vector, min, max) {
56
- const length = magnitude(vector)
57
-
58
- if (typeof min === "number" && length < min) {
59
- return setMagnitude(vector, min)
60
- }
61
-
62
- if (typeof max === "number" && length > max) {
63
- return setMagnitude(vector, max)
64
- }
65
-
66
- if (typeof min !== "number" && typeof max !== "number") {
67
- return vector.map((coordinate, index) =>
68
- nClamp(coordinate, min[index], max[index]),
69
- )
70
- }
71
-
72
- return vector
73
- }
74
-
75
- /**
76
- * Returns the conjugate of the vector.
77
- * @param {Vector3} vector - The input vector.
78
- * @returns {Vector3} The conjugated vector.
79
- */
80
- export function conjugate(vector) {
81
- return vector.map((coordinate, index) => (index ? -coordinate : coordinate))
82
- }
83
-
84
- /**
85
- * Creates a vector with the given magnitude and angle.
86
- * @param {number} magnitude - The magnitude of the vector.
87
- * @param {number} angle - The angle of the vector in radians.
88
- * @returns {Vector3} The created vector.
89
- */
90
- export function createVector(magnitude, angle) {
91
- return multiply(fromAngle(angle), magnitude)
92
- }
93
-
94
- /**
95
- * Divides each component of the vector by the given scalar.
96
- * @param {Vector3} vector - The input vector.
97
- * @param {number} scalar - The scalar value.
98
- * @returns {Vector3} The resulting vector.
99
- */
100
- export function divide(vector, scalar) {
101
- return vector.map((coordinate) => coordinate / scalar)
102
- }
103
-
104
- /**
105
- * Creates a unit vector from the given angle.
106
- * @param {number} angle - The angle in radians.
107
- * @returns {Vector3} The unit vector.
108
- */
109
- export function fromAngle(angle) {
110
- return rotate(UNIT_VECTOR, angle)
111
- }
112
-
113
- export const length = magnitude
114
-
115
- /**
116
- * Calculates the magnitude of the vector.
117
- * @param {Vector3} vector - The input vector.
118
- * @returns {number} The magnitude of the vector.
119
- */
120
- export function magnitude(vector) {
121
- return hypothenuse(...vector)
122
- }
123
-
124
- /**
125
- * Calculates the modulus of each component in the vector with the given divisor.
126
- * @param {Vector3} vector - The input vector.
127
- * @param {number} divisor - The divisor value.
128
- * @returns {Vector3} The resulting vector.
129
- */
130
- export function mod(vector, divisor) {
131
- return vector.map((coordinate) => nMod(coordinate, divisor))
132
- }
133
-
134
- /**
135
- * Multiplies each component of the vector by the given scalar.
136
- * @param {Vector3} vector - The input vector.
137
- * @param {number} scalar - The scalar value.
138
- * @returns {Vector3} The resulting vector.
139
- */
140
- export function multiply(vector, scalar) {
141
- return vector.map((coordinate) => coordinate * scalar)
142
- }
143
-
144
- /**
145
- * Normalizes the vector to have a magnitude of 1.
146
- * @param {Vector3} vector - The input vector.
147
- * @returns {Vector3} The normalized vector.
148
- */
149
- export function normalize(vector) {
150
- const length = magnitude(vector)
151
- return vector.map((coordinate) => coordinate / length)
152
- }
153
-
154
- export const remainder = mod
155
-
156
- /**
157
- * Rotates the vector by the given angle.
158
- * @param {Vector3} vector - The input vector.
159
- * @param {number} angle - The angle in radians.
160
- * @returns {Vector3} The rotated vector.
161
- */
162
- export function rotate(vector, angle) {
163
- const is2D = vector.length === TWO_COORDINATES
164
-
165
- let v = is2D ? from2D(vector) : vector
166
-
167
- let result = rotateWithQuaternion(v, angle)
168
-
169
- return is2D ? to2D(result) : result
170
- }
171
-
172
- /**
173
- * Sets the angle of the vector while maintaining its magnitude.
174
- * @param {Vector3} vector - The input vector.
175
- * @param {number} angle - The new angle in radians.
176
- * @returns {Vector3} The vector with the updated angle.
177
- */
178
- export function setAngle(vector, angle) {
179
- const length = magnitude(vector)
180
- const [x, z] = toCartesian([length, angle])
181
- return [x, NO_Y, z]
182
- }
183
-
184
- export const setLength = setMagnitude
185
-
186
- /**
187
- * Sets the magnitude of the vector while maintaining its direction.
188
- * @param {Vector3} vector - The input vector.
189
- * @param {number} length - The new magnitude.
190
- * @returns {Vector3} The vector with the updated magnitude.
191
- */
192
- export function setMagnitude(vector, length) {
193
- const normalized = normalize(vector)
194
- return multiply(normalized, length)
195
- }
196
-
197
- /**
198
- * Shifts the components of the vector by the given index.
199
- * @param {Vector3} vector - The input vector.
200
- * @param {number} index - The index to shift by.
201
- * @returns {Vector3} The shifted vector.
202
- */
203
- export function shift(vector, index) {
204
- return [...vector.slice(index), ...vector.slice(X, index)]
205
- }
206
-
207
- /**
208
- * Snaps each component of the vector to the nearest multiple of the given precision.
209
- * @param {Vector3} vector - The input vector.
210
- * @param {number} [precision=DEFAULT_PRECISION] - The precision value.
211
- * @returns {Vector3} The snapped vector.
212
- */
213
- export function snap(vector, precision = DEFAULT_PRECISION) {
214
- return vector.map((coordinate) => nSnap(coordinate, -precision, precision))
215
- }
216
-
217
- export const times = multiply
218
-
219
- /**
220
- * Converts polar coordinates to Cartesian coordinates.
221
- * @param {Vector2} vector - The polar coordinates [magnitude, angle].
222
- * @returns {Vector2} The Cartesian coordinates [x, y].
223
- */
224
- export function toCartesian([magnitude, angle]) {
225
- return [magnitude * cos(angle), magnitude * sin(angle)]
226
- }
227
-
228
- /**
229
- * Converts a vector to cylindrical coordinates.
230
- * @param {Vector2} vector - The input vector.
231
- * @returns {Vector2} The cylindrical coordinates [radius, theta, z].
232
- */
233
- export function toCylindrical(vector) {
234
- const radius = magnitude(vector)
235
- const theta = angle(vector)
236
- return [radius * cos(theta), radius * sin(theta), vector[Z]]
237
- }
238
-
239
- /**
240
- * Converts a vector to polar coordinates.
241
- * @param {Vector2} vector - The input vector.
242
- * @returns {Vector2} The polar coordinates [magnitude, angle].
243
- */
244
- export function toPolar(vector) {
245
- return [magnitude(vector), angle(vector)]
246
- }
247
-
248
- /**
249
- * Converts a vector to a string representation.
250
- * @param {Vector3} vector - The input vector.
251
- * @param {number} [decimals=DEFAULT_DECIMALS] - The number of decimal places.
252
- * @returns {string} The string representation of the vector.
253
- */
254
- export function toString(vector, decimals = DEFAULT_DECIMALS) {
255
- return `[${vector
256
- .map((coordinate) => coordinate.toFixed(decimals))
257
- .join(", ")}]`
258
- }
259
-
260
- // TODO: add toSpherical(vector), as described in https://www.cs.mcgill.ca/~rwest/wikispeedia/wpcd/wp/p/Polar_coordinate_system.htm#:~:text=Polar%20coordinates%20can%20also%20be,as%20in%20the%20polar%20coordinates).
261
-
262
- /**
263
- * Creates a unit vector with the given angle.
264
- * @param {number} angle - The angle in radians.
265
- * @returns {Vector3} The unit vector.
266
- */
267
- export function unit(angle) {
268
- if (!angle) {
269
- return [...UNIT_VECTOR]
270
- }
271
-
272
- return setAngle(UNIT_VECTOR, angle)
273
- }
274
-
275
- /**
276
- * Creates a zero vector.
277
- * @returns {Vector3} The zero vector.
278
- */
279
- export function zero() {
280
- return [...ZERO_VECTOR]
281
- }
282
-
283
- /**
284
- * Rotates the vector using a quaternion.
285
- * @param {Vector3} vector - The input vector.
286
- * @param {number} angle - The angle in radians.
287
- * @returns {Vector3} The rotated vector.
288
- */
289
- function rotateWithQuaternion(vector, angle) {
290
- if (!angle) {
291
- return vector
292
- }
293
-
294
- // @see https://en.wikipedia.org/wiki/Quaternions_and_spatial_rotation#Performance_comparisons
295
- const [w, ...r] = quaternion(angle)
296
- const result = sum(
297
- vector,
298
- cross(multiply(r, 2), sum(cross(r, vector), multiply(vector, w))), // eslint-disable-line no-magic-numbers
299
- )
300
-
301
- return conjugate(result) // HACK: not really sure why I should invert the result, it just works this way
302
- }
1
+ /**
2
+ * @typedef {import('./types').Vector2} Vector2
3
+ * @typedef {import('./types').Vector3} Vector3
4
+ */
5
+
6
+ import { hypothenuse } from "@inglorious/utils/math/geometry/triangle.js"
7
+ import {
8
+ abs as nAbs,
9
+ clamp as nClamp,
10
+ mod as nMod,
11
+ snap as nSnap,
12
+ } from "@inglorious/utils/math/numbers.js"
13
+ import { atan2, cos, sin } from "@inglorious/utils/math/trigonometry.js"
14
+
15
+ import { from2D, to2D } from "./2d.js"
16
+ import { quaternion } from "./quaternion.js"
17
+ import { cross, sum } from "./vectors.js"
18
+
19
+ const ZERO_VECTOR = [0, 0, 0] // eslint-disable-line no-magic-numbers
20
+ const UNIT_VECTOR = [1, 0, 0] // eslint-disable-line no-magic-numbers
21
+
22
+ const X = 0
23
+ const Y = 1
24
+ const Z = 2
25
+ const LAST_COORDINATE = 1
26
+ const TWO_COORDINATES = 2
27
+ const NO_Y = 0
28
+ const DEFAULT_PRECISION = 1
29
+ const DEFAULT_DECIMALS = 0
30
+
31
+ /**
32
+ * Returns the absolute value of each component in the vector.
33
+ * @param {Vector3} vector - The input vector.
34
+ * @returns {Vector3} The vector with absolute values.
35
+ */
36
+ export function abs(vector) {
37
+ return vector.map(nAbs)
38
+ }
39
+
40
+ /**
41
+ * Calculates the angle of the vector in radians.
42
+ * @param {Vector3} vector - The input vector.
43
+ * @returns {number} The angle in radians.
44
+ */
45
+ export function angle(vector) {
46
+ return atan2(vector[vector.length - LAST_COORDINATE], vector[X])
47
+ }
48
+
49
+ /**
50
+ * Clamps the magnitude of the vector between the given min and max values.
51
+ * @param {Vector3} vector - The input vector.
52
+ * @param {number} min - The minimum magnitude.
53
+ * @param {number} max - The maximum magnitude.
54
+ * @returns {Vector3} The clamped vector.
55
+ */
56
+ export function clamp(vector, min, max) {
57
+ const length = magnitude(vector)
58
+
59
+ if (typeof min === "number" && length < min) {
60
+ return setMagnitude(vector, min)
61
+ }
62
+
63
+ if (typeof max === "number" && length > max) {
64
+ return setMagnitude(vector, max)
65
+ }
66
+
67
+ if (typeof min !== "number" && typeof max !== "number") {
68
+ return vector.map((coordinate, index) =>
69
+ nClamp(coordinate, min[index], max[index]),
70
+ )
71
+ }
72
+
73
+ return vector
74
+ }
75
+
76
+ /**
77
+ * Returns the conjugate of the vector.
78
+ * @param {Vector3} vector - The input vector.
79
+ * @returns {Vector3} The conjugated vector.
80
+ */
81
+ export function conjugate(vector) {
82
+ return vector.map((coordinate, index) => (index ? -coordinate : coordinate))
83
+ }
84
+
85
+ /**
86
+ * Creates a vector with the given magnitude and angle.
87
+ * @param {number} magnitude - The magnitude of the vector.
88
+ * @param {number} angle - The angle of the vector in radians.
89
+ * @returns {Vector3} The created vector.
90
+ */
91
+ export function createVector(magnitude, angle) {
92
+ return multiply(fromAngle(angle), magnitude)
93
+ }
94
+
95
+ /**
96
+ * Divides each component of the vector by the given scalar.
97
+ * @param {Vector3} vector - The input vector.
98
+ * @param {number} scalar - The scalar value.
99
+ * @returns {Vector3} The resulting vector.
100
+ */
101
+ export function divide(vector, scalar) {
102
+ return vector.map((coordinate) => coordinate / scalar)
103
+ }
104
+
105
+ /**
106
+ * Creates a unit vector from the given angle.
107
+ * @param {number} angle - The angle in radians.
108
+ * @returns {Vector3} The unit vector.
109
+ */
110
+ export function fromAngle(angle) {
111
+ return rotate(UNIT_VECTOR, angle)
112
+ }
113
+
114
+ export const length = magnitude
115
+
116
+ /**
117
+ * Calculates the magnitude of the vector.
118
+ * @param {Vector3} vector - The input vector.
119
+ * @returns {number} The magnitude of the vector.
120
+ */
121
+ export function magnitude(vector) {
122
+ return hypothenuse(...vector)
123
+ }
124
+
125
+ /**
126
+ * Calculates the modulus of each component in the vector with the given divisor.
127
+ * @param {Vector3} vector - The input vector.
128
+ * @param {number} divisor - The divisor value.
129
+ * @returns {Vector3} The resulting vector.
130
+ */
131
+ export function mod(vector, divisor) {
132
+ return vector.map((coordinate) => nMod(coordinate, divisor))
133
+ }
134
+
135
+ /**
136
+ * Multiplies each component of the vector by the given scalar.
137
+ * @param {Vector3} vector - The input vector.
138
+ * @param {number} scalar - The scalar value.
139
+ * @returns {Vector3} The resulting vector.
140
+ */
141
+ export function multiply(vector, scalar) {
142
+ return vector.map((coordinate) => coordinate * scalar)
143
+ }
144
+
145
+ /**
146
+ * Normalizes the vector to have a magnitude of 1.
147
+ * @param {Vector3} vector - The input vector.
148
+ * @returns {Vector3} The normalized vector.
149
+ */
150
+ export function normalize(vector) {
151
+ const length = magnitude(vector)
152
+ return vector.map((coordinate) => coordinate / length)
153
+ }
154
+
155
+ export const remainder = mod
156
+
157
+ /**
158
+ * Rotates the vector by the given angle.
159
+ * @param {Vector3} vector - The input vector.
160
+ * @param {number} angle - The angle in radians.
161
+ * @returns {Vector3} The rotated vector.
162
+ */
163
+ export function rotate(vector, angle) {
164
+ const is2D = vector.length === TWO_COORDINATES
165
+
166
+ let v = is2D ? from2D(vector) : vector
167
+
168
+ let result = rotateWithQuaternion(v, angle)
169
+
170
+ return is2D ? to2D(result) : result
171
+ }
172
+
173
+ /**
174
+ * Sets the angle of the vector while maintaining its magnitude.
175
+ * @param {Vector3} vector - The input vector.
176
+ * @param {number} angle - The new angle in radians.
177
+ * @returns {Vector3} The vector with the updated angle.
178
+ */
179
+ export function setAngle(vector, angle) {
180
+ const length = magnitude(vector)
181
+ const [x, z] = toCartesian([length, angle])
182
+ return [x, NO_Y, z]
183
+ }
184
+
185
+ export const setLength = setMagnitude
186
+
187
+ /**
188
+ * Sets the magnitude of the vector while maintaining its direction.
189
+ * @param {Vector3} vector - The input vector.
190
+ * @param {number} length - The new magnitude.
191
+ * @returns {Vector3} The vector with the updated magnitude.
192
+ */
193
+ export function setMagnitude(vector, length) {
194
+ const normalized = normalize(vector)
195
+ return multiply(normalized, length)
196
+ }
197
+
198
+ /**
199
+ * Shifts the components of the vector by the given index.
200
+ * @param {Vector3} vector - The input vector.
201
+ * @param {number} index - The index to shift by.
202
+ * @returns {Vector3} The shifted vector.
203
+ */
204
+ export function shift(vector, index) {
205
+ return [...vector.slice(index), ...vector.slice(X, index)]
206
+ }
207
+
208
+ /**
209
+ * Snaps each component of the vector to the nearest multiple of the given precision.
210
+ * @param {Vector3} vector - The input vector.
211
+ * @param {number} [precision=DEFAULT_PRECISION] - The precision value.
212
+ * @returns {Vector3} The snapped vector.
213
+ */
214
+ export function snap(vector, precision = DEFAULT_PRECISION) {
215
+ return vector.map((coordinate) => nSnap(coordinate, -precision, precision))
216
+ }
217
+
218
+ export const times = multiply
219
+
220
+ /**
221
+ * Converts polar coordinates to Cartesian coordinates.
222
+ * @param {Vector2} vector - The polar coordinates [magnitude, angle].
223
+ * @returns {Vector2} The Cartesian coordinates [x, y].
224
+ */
225
+ export function toCartesian([magnitude, angle]) {
226
+ return [magnitude * cos(angle), magnitude * sin(angle)]
227
+ }
228
+
229
+ /**
230
+ * Converts a vector to cylindrical coordinates.
231
+ * @param {Vector2} vector - The input vector.
232
+ * @returns {Vector2} The cylindrical coordinates [radius, theta, z].
233
+ */
234
+ export function toCylindrical(vector) {
235
+ const radius = magnitude(vector)
236
+ const theta = angle(vector)
237
+ return [radius * cos(theta), radius * sin(theta), vector[Z]]
238
+ }
239
+
240
+ /**
241
+ * Converts a vector to polar coordinates.
242
+ * @param {Vector2} vector - The input vector.
243
+ * @returns {Vector2} The polar coordinates [magnitude, angle].
244
+ */
245
+ export function toPolar(vector) {
246
+ return [magnitude(vector), angle(vector)]
247
+ }
248
+
249
+ /**
250
+ * Converts a vector to a string representation.
251
+ * @param {Vector3} vector - The input vector.
252
+ * @param {number} [decimals=DEFAULT_DECIMALS] - The number of decimal places.
253
+ * @returns {string} The string representation of the vector.
254
+ */
255
+ export function toString(vector, decimals = DEFAULT_DECIMALS) {
256
+ return `[${vector
257
+ .map((coordinate) => coordinate.toFixed(decimals))
258
+ .join(", ")}]`
259
+ }
260
+
261
+ // TODO: add toSpherical(vector),
262
+
263
+ /**
264
+ * Converts a 3D cartesian vector to spherical coordinates [radius, inclination, azimuth].
265
+ * - radius (r): distance from the origin.
266
+ * - inclination (θ): angle from the Y-axis (0 to PI).
267
+ * - azimuth (φ): angle from the X-axis in the XZ-plane (-PI to PI).
268
+ *
269
+ * @param {Vector3} vector The cartesian vector [x, y, z].
270
+ * @returns {Vector3} The spherical coordinates [r, θ, φ].
271
+ */
272
+ export function toSpherical(vector) {
273
+ const r = magnitude(vector)
274
+
275
+ if (!r) {
276
+ return zero()
277
+ }
278
+
279
+ // In a Y-up system, inclination is the angle with the Y axis.
280
+ const inclination = Math.acos(vector[Y] / r)
281
+ // Azimuth is the angle in the XZ plane, which `angle()` calculates.
282
+ const azimuth = angle(vector)
283
+
284
+ return [r, inclination, azimuth]
285
+ }
286
+
287
+ /**
288
+ * Creates a unit vector with the given angle.
289
+ * @param {number} angle - The angle in radians.
290
+ * @returns {Vector3} The unit vector.
291
+ */
292
+ export function unit(angle) {
293
+ if (!angle) {
294
+ return [...UNIT_VECTOR]
295
+ }
296
+
297
+ return setAngle(UNIT_VECTOR, angle)
298
+ }
299
+
300
+ /**
301
+ * Creates a zero vector.
302
+ * @returns {Vector3} The zero vector.
303
+ */
304
+ export function zero() {
305
+ return [...ZERO_VECTOR]
306
+ }
307
+
308
+ /**
309
+ * Rotates the vector using a quaternion.
310
+ * @param {Vector3} vector - The input vector.
311
+ * @param {number} angle - The angle in radians.
312
+ * @returns {Vector3} The rotated vector.
313
+ */
314
+ function rotateWithQuaternion(vector, angle) {
315
+ if (!angle) {
316
+ return vector
317
+ }
318
+
319
+ // @see https://en.wikipedia.org/wiki/Quaternions_and_spatial_rotation#Performance_comparisons
320
+ const [w, ...r] = quaternion(angle)
321
+ const result = sum(
322
+ vector,
323
+ cross(multiply(r, 2), sum(cross(r, vector), multiply(vector, w))), // eslint-disable-line no-magic-numbers
324
+ )
325
+
326
+ return conjugate(result) // HACK: not really sure why I should invert the result, it just works this way
327
+ }