@inglorious/utils 4.0.0 → 5.0.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 +22 -6
- package/package.json +35 -19
- package/src/algorithms/path-finding.js +2 -2
- package/src/data-structures/array.js +12 -0
- package/src/data-structures/index.js +2 -2
- package/src/data-structures/{objects.js → object.js} +87 -36
- package/src/data-structures/string.js +77 -0
- package/src/functions/index.js +1 -1
- package/src/math/circle.js +1 -1
- package/src/math/hitmask.js +1 -1
- package/src/math/index.js +4 -4
- package/src/math/line.js +1 -1
- package/src/math/point.js +23 -2
- package/src/math/{quaternions.js → quaternion.js} +3 -3
- package/src/math/rectangle.js +12 -0
- package/src/math/rng.js +5 -2
- package/src/math/segment.js +1 -1
- package/src/math/trigonometry.js +1 -1
- package/src/math/{vectors.js → vector.js} +67 -8
- package/src/physics/acceleration.js +2 -2
- package/src/physics/friction.js +2 -2
- package/src/physics/gravity.js +2 -2
- package/src/physics/velocity.js +2 -2
- package/src/v.js +1 -1
- package/types/algorithms/path-finding.d.ts +1 -1
- package/types/data-structures/array.d.ts +5 -0
- package/types/data-structures/index.d.ts +1 -1
- package/types/data-structures/{objects.d.ts → object.d.ts} +1 -1
- package/types/math/index.d.ts +3 -3
- package/types/math/point.d.ts +26 -1
- package/types/math/{quaternions.d.ts → quaternion.d.ts} +1 -1
- package/types/math/rectangle.d.ts +23 -2
- package/types/math/{vectors.d.ts → vector.d.ts} +29 -0
- package/types/physics/acceleration.d.ts +1 -1
- package/types/physics/friction.d.ts +1 -1
- package/types/physics/gravity.d.ts +1 -1
- package/types/physics/velocity.d.ts +1 -1
- package/types/v.d.ts +1 -1
- /package/src/functions/{functions.js → function.js} +0 -0
- /package/src/math/{numbers.js → number.js} +0 -0
- /package/types/functions/{functions.d.ts → function.d.ts} +0 -0
- /package/types/math/{numbers.d.ts → number.d.ts} +0 -0
package/README.md
CHANGED
|
@@ -92,7 +92,7 @@ const throttledSave = throttle(() => {
|
|
|
92
92
|
Perform vector operations on plain objects.
|
|
93
93
|
|
|
94
94
|
```javascript
|
|
95
|
-
import { add } from "@inglorious/utils/
|
|
95
|
+
import { add } from "@inglorious/utils/vector.js"
|
|
96
96
|
|
|
97
97
|
const position = [10, 20]
|
|
98
98
|
const velocity = [2, -1]
|
|
@@ -101,6 +101,23 @@ const newPosition = add(position, velocity)
|
|
|
101
101
|
// => [12, 19]
|
|
102
102
|
```
|
|
103
103
|
|
|
104
|
+
Two vectors are worth knowing by name: `ZERO_VECTOR`, with every component at zero, and
|
|
105
|
+
`UNIT_VECTOR`, one unit long along the x axis. The zero one is handy for naming the components
|
|
106
|
+
you care about, or for building a vector up from scratch:
|
|
107
|
+
|
|
108
|
+
```javascript
|
|
109
|
+
import { ZERO_VECTOR } from "@inglorious/utils/math/vector.js"
|
|
110
|
+
import { v } from "@inglorious/utils/v.js"
|
|
111
|
+
|
|
112
|
+
const [, NO_RISE, NO_DEPTH] = ZERO_VECTOR
|
|
113
|
+
|
|
114
|
+
const position = v(10, 20, NO_DEPTH)
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
Vectors are mutable arrays, so copy a shared vector rather than storing it where something writes
|
|
118
|
+
to one, such as an entity position. Copy it with `v(...ZERO_VECTOR)`: a plain spread
|
|
119
|
+
(`[...ZERO_VECTOR]`) gives you a new array but drops the tag that `isVector` looks for.
|
|
120
|
+
|
|
104
121
|
---
|
|
105
122
|
|
|
106
123
|
## API
|
|
@@ -111,7 +128,6 @@ Most modules are grouped by category:
|
|
|
111
128
|
|
|
112
129
|
- **`@inglorious/utils/algorithms`**: Utilities for AI algorithms, like decision trees and A\*.
|
|
113
130
|
- **`@inglorious/utils/data-structures`**: Utilities for arrays, boards, heaps, objects, sets, strings, and trees.
|
|
114
|
-
- **`@inglorious/utils/functions`**: Utilities for function composition and timing.
|
|
115
131
|
- **`@inglorious/utils/math`**: Utilities for math operations.
|
|
116
132
|
- **`@inglorious/utils/physics`**: Utilities for calculations on friction, acceleration, and gravity.
|
|
117
133
|
|
|
@@ -119,15 +135,15 @@ The four largest modules are also available as top-level subpaths, so you don't
|
|
|
119
135
|
know whether a helper lives under `data-structures` or `math`:
|
|
120
136
|
|
|
121
137
|
- **`@inglorious/utils/functions`**: `compose`, `debounce`, `isFunction`, `pipe`, `throttle`.
|
|
122
|
-
- **`@inglorious/utils/
|
|
123
|
-
- **`@inglorious/utils/
|
|
124
|
-
- **`@inglorious/utils/
|
|
138
|
+
- **`@inglorious/utils/object`**: Single-object helpers (`clone`, `get`, `set`, `produce`, ...) alongside multi-object helpers (`merge`, `extend`, `defaults`, ...).
|
|
139
|
+
- **`@inglorious/utils/quaternion`**: `quaternion` and `combine`.
|
|
140
|
+
- **`@inglorious/utils/vector`**: Single-vector helpers (`magnitude`, `normalize`, `rotate`, ...) alongside multi-vector helpers (`cross`, `dot`, `sum`, ...).
|
|
125
141
|
|
|
126
142
|
`divide`, `mod`, `multiply` and `power` accept either a scalar or one or more vectors:
|
|
127
143
|
a scalar is applied to every component, while vectors are combined component-wise.
|
|
128
144
|
|
|
129
145
|
```javascript
|
|
130
|
-
import { multiply } from "@inglorious/utils/
|
|
146
|
+
import { multiply } from "@inglorious/utils/vector.js"
|
|
131
147
|
|
|
132
148
|
multiply([1, 2, 3], 2) // => [2, 4, 6]
|
|
133
149
|
multiply([1, 2, 3], [4, 5, 6]) // => [4, 10, 18]
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@inglorious/utils",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "5.0.0",
|
|
4
4
|
"description": "A set of general-purpose utility functions designed with functional programming principles in mind.",
|
|
5
5
|
"author": "Matteo Antony Mistretta <antony.mistretta@gmail.com> (https://ingloriouscoderz.it)",
|
|
6
6
|
"license": "MIT",
|
|
@@ -26,6 +26,14 @@
|
|
|
26
26
|
"types": "./types/index.d.ts",
|
|
27
27
|
"import": "./src/index.js"
|
|
28
28
|
},
|
|
29
|
+
"./array.js": {
|
|
30
|
+
"types": "./types/data-structures/array.d.ts",
|
|
31
|
+
"import": "./src/data-structures/array.js"
|
|
32
|
+
},
|
|
33
|
+
"./array": {
|
|
34
|
+
"types": "./types/data-structures/array.d.ts",
|
|
35
|
+
"import": "./src/data-structures/array.js"
|
|
36
|
+
},
|
|
29
37
|
"./algorithms": {
|
|
30
38
|
"types": "./types/algorithms/index.d.ts",
|
|
31
39
|
"import": "./src/algorithms/index.js"
|
|
@@ -50,6 +58,14 @@
|
|
|
50
58
|
"types": "./types/data-structures/*.d.ts",
|
|
51
59
|
"import": "./src/data-structures/*.js"
|
|
52
60
|
},
|
|
61
|
+
"./function.js": {
|
|
62
|
+
"types": "./types/functions/function.d.ts",
|
|
63
|
+
"import": "./src/functions/function.js"
|
|
64
|
+
},
|
|
65
|
+
"./function": {
|
|
66
|
+
"types": "./types/functions/function.d.ts",
|
|
67
|
+
"import": "./src/functions/function.js"
|
|
68
|
+
},
|
|
53
69
|
"./functions": {
|
|
54
70
|
"types": "./types/functions/index.d.ts",
|
|
55
71
|
"import": "./src/functions/index.js"
|
|
@@ -78,29 +94,29 @@
|
|
|
78
94
|
"types": "./types/physics/*.d.ts",
|
|
79
95
|
"import": "./src/physics/*.js"
|
|
80
96
|
},
|
|
81
|
-
"./
|
|
82
|
-
"types": "./types/data-structures/
|
|
83
|
-
"import": "./src/data-structures/
|
|
97
|
+
"./object.js": {
|
|
98
|
+
"types": "./types/data-structures/object.d.ts",
|
|
99
|
+
"import": "./src/data-structures/object.js"
|
|
84
100
|
},
|
|
85
|
-
"./
|
|
86
|
-
"types": "./types/data-structures/
|
|
87
|
-
"import": "./src/data-structures/
|
|
101
|
+
"./object": {
|
|
102
|
+
"types": "./types/data-structures/object.d.ts",
|
|
103
|
+
"import": "./src/data-structures/object.js"
|
|
88
104
|
},
|
|
89
|
-
"./
|
|
90
|
-
"types": "./types/math/
|
|
91
|
-
"import": "./src/math/
|
|
105
|
+
"./quaternion.js": {
|
|
106
|
+
"types": "./types/math/quaternion.d.ts",
|
|
107
|
+
"import": "./src/math/quaternion.js"
|
|
92
108
|
},
|
|
93
|
-
"./
|
|
94
|
-
"types": "./types/math/
|
|
95
|
-
"import": "./src/math/
|
|
109
|
+
"./quaternion": {
|
|
110
|
+
"types": "./types/math/quaternion.d.ts",
|
|
111
|
+
"import": "./src/math/quaternion.js"
|
|
96
112
|
},
|
|
97
|
-
"./
|
|
98
|
-
"types": "./types/math/
|
|
99
|
-
"import": "./src/math/
|
|
113
|
+
"./vector.js": {
|
|
114
|
+
"types": "./types/math/vector.d.ts",
|
|
115
|
+
"import": "./src/math/vector.js"
|
|
100
116
|
},
|
|
101
|
-
"./
|
|
102
|
-
"types": "./types/math/
|
|
103
|
-
"import": "./src/math/
|
|
117
|
+
"./vector": {
|
|
118
|
+
"types": "./types/math/vector.d.ts",
|
|
119
|
+
"import": "./src/math/vector.js"
|
|
104
120
|
},
|
|
105
121
|
"./v.js": {
|
|
106
122
|
"types": "./types/v.d.ts",
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* @typedef {import("../../types/algorithms/path-finding").Node} Node
|
|
3
3
|
* @typedef {import("../../types/algorithms/path-finding").Graph} Graph
|
|
4
|
-
* @typedef {import("../../types/math/
|
|
4
|
+
* @typedef {import("../../types/math/vector").Vector2} Vector2
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
7
|
import { contains, push, remove, root } from "../data-structures/heap.js"
|
|
8
|
-
import { abs, magnitude, subtract } from "../math/
|
|
8
|
+
import { abs, magnitude, subtract } from "../math/vector.js"
|
|
9
9
|
|
|
10
10
|
const NO_COST = 0
|
|
11
11
|
|
|
@@ -22,6 +22,18 @@ export function contains(arr, item) {
|
|
|
22
22
|
return arr.includes(item)
|
|
23
23
|
}
|
|
24
24
|
|
|
25
|
+
/**
|
|
26
|
+
* The index `step` places along a list of `length`, wrapping round at either end.
|
|
27
|
+
*
|
|
28
|
+
* @param {number} index - Where to start from.
|
|
29
|
+
* @param {number} length - How long the list is.
|
|
30
|
+
* @param {number} step - How far to move. Negative steps move backwards.
|
|
31
|
+
* @returns {number} - The index landed on, always within the list.
|
|
32
|
+
*/
|
|
33
|
+
export function cycleIndex(index, length, step) {
|
|
34
|
+
return (((index + step) % length) + length) % length
|
|
35
|
+
}
|
|
36
|
+
|
|
25
37
|
/**
|
|
26
38
|
* Ensures that the given value is an array. If it's not an array, it wraps it in one.
|
|
27
39
|
*
|
|
@@ -2,9 +2,9 @@ import * as array from "./array.js"
|
|
|
2
2
|
import * as board from "./board.js"
|
|
3
3
|
import * as boolean from "./boolean.js"
|
|
4
4
|
import * as heap from "./heap.js"
|
|
5
|
-
import * as
|
|
5
|
+
import * as object from "./object.js"
|
|
6
6
|
import * as set from "./set.js"
|
|
7
7
|
import * as string from "./string.js"
|
|
8
8
|
import * as tree from "./tree.js"
|
|
9
9
|
|
|
10
|
-
export { array, board, boolean, heap,
|
|
10
|
+
export { array, board, boolean, heap, object, set, string, tree }
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { isFunction } from "../functions/
|
|
1
|
+
import { isFunction } from "../functions/function.js"
|
|
2
2
|
import { v } from "../v.js"
|
|
3
3
|
import { isArray } from "./array.js"
|
|
4
4
|
|
|
@@ -28,6 +28,39 @@ export function clone(obj) {
|
|
|
28
28
|
return deserialize(serialize(obj))
|
|
29
29
|
}
|
|
30
30
|
|
|
31
|
+
/**
|
|
32
|
+
* Recursively merges properties from a source object into a target object.
|
|
33
|
+
* This is a helper function for `merge` and `extend`.
|
|
34
|
+
*
|
|
35
|
+
* @param {Object} target - The target object to merge into.
|
|
36
|
+
* @param {Object} source - The source object to merge from.
|
|
37
|
+
* @param {Function} [merger] - An optional function to customize merging behavior for specific keys.
|
|
38
|
+
* @returns {Object} - The modified target object.
|
|
39
|
+
*/
|
|
40
|
+
function deepMerge(target, source, merger) {
|
|
41
|
+
for (const [key, value] of Object.entries(source)) {
|
|
42
|
+
if (isFunction(merger)) {
|
|
43
|
+
const mergedValue = merger(target[key], value)
|
|
44
|
+
if (mergedValue !== undefined) {
|
|
45
|
+
target[key] = mergedValue
|
|
46
|
+
continue
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
if (isArray(value)) {
|
|
51
|
+
target[key] = value
|
|
52
|
+
} else if (isObject(value)) {
|
|
53
|
+
if (!isObject(target[key])) {
|
|
54
|
+
target[key] = {}
|
|
55
|
+
}
|
|
56
|
+
target[key] = deepMerge(target[key], value, merger)
|
|
57
|
+
} else {
|
|
58
|
+
target[key] = value
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
return target
|
|
62
|
+
}
|
|
63
|
+
|
|
31
64
|
/**
|
|
32
65
|
* Assigns default properties to a target object from a source object.
|
|
33
66
|
* For each key in `defaultProps`, if `target[key]` is `null` or `undefined`,
|
|
@@ -186,6 +219,57 @@ export function get(obj, path, defaultValue = undefined) {
|
|
|
186
219
|
* @param {*} value - The value to check.
|
|
187
220
|
* @returns {boolean} True if the value is a plain object, false otherwise.
|
|
188
221
|
*/
|
|
222
|
+
/**
|
|
223
|
+
* Whether two values are the same, all the way down.
|
|
224
|
+
*
|
|
225
|
+
* Written here rather than with `JSON.stringify` because stringify cannot tell a key
|
|
226
|
+
* that was left out from one that was set to nothing, and those are different: a key
|
|
227
|
+
* mapped to `undefined` is a key with nothing mapped to it, which is how a mapping is
|
|
228
|
+
* taken off.
|
|
229
|
+
*
|
|
230
|
+
* @param {*} left - The first value.
|
|
231
|
+
* @param {*} right - The second value.
|
|
232
|
+
* @param {WeakMap} [seen] - The pairs already compared, so a structure that contains
|
|
233
|
+
* itself is not walked for ever. Passed along rather than asked for.
|
|
234
|
+
*
|
|
235
|
+
* What it does not settle is whether two structures *share* the same parts. One value
|
|
236
|
+
* used twice against two equal ones written out twice are reported as different, because
|
|
237
|
+
* only the pairs already met are remembered. That errs towards calling things changed
|
|
238
|
+
* when they are not, which is the safe way round for the thing this is asked about.
|
|
239
|
+
*
|
|
240
|
+
* @returns {boolean} Whether the two are the same.
|
|
241
|
+
*/
|
|
242
|
+
export function isDeepEqual(left, right, seen = new WeakMap()) {
|
|
243
|
+
if (Object.is(left, right)) return true
|
|
244
|
+
|
|
245
|
+
// `Object.is` has already said no to these two being the same object, and neither can be
|
|
246
|
+
// walked: a function is equal to itself and nothing else, and a key present in one and
|
|
247
|
+
// not the other is a difference even when both read as undefined.
|
|
248
|
+
if (typeof left !== "object" || typeof right !== "object") return false
|
|
249
|
+
if (left === null || right === null) return false
|
|
250
|
+
|
|
251
|
+
if (Array.isArray(left) !== Array.isArray(right)) return false
|
|
252
|
+
|
|
253
|
+
// A thing that contains itself would otherwise be walked for ever. Meeting the same
|
|
254
|
+
// thing twice means it has already been compared, and it was the same then or the walk
|
|
255
|
+
// would have stopped there -- so the only question left is whether it was matched to
|
|
256
|
+
// this one. A structure that loops back to itself differently is a difference, which is
|
|
257
|
+
// what stops this reporting two equal loops that are not.
|
|
258
|
+
if (seen.has(left)) return seen.get(left) === right
|
|
259
|
+
|
|
260
|
+
seen.set(left, right)
|
|
261
|
+
|
|
262
|
+
const leftKeys = Object.keys(left)
|
|
263
|
+
const rightKeys = Object.keys(right)
|
|
264
|
+
|
|
265
|
+
if (leftKeys.length !== rightKeys.length) return false
|
|
266
|
+
|
|
267
|
+
return leftKeys.every(
|
|
268
|
+
(key) =>
|
|
269
|
+
Object.hasOwn(right, key) && isDeepEqual(left[key], right[key], seen),
|
|
270
|
+
)
|
|
271
|
+
}
|
|
272
|
+
|
|
189
273
|
export function isObject(value) {
|
|
190
274
|
return value != null && value.constructor === Object
|
|
191
275
|
}
|
|
@@ -286,7 +370,7 @@ export function produce(baseState, recipe, ...args) {
|
|
|
286
370
|
*/
|
|
287
371
|
export function serialize(obj) {
|
|
288
372
|
function replacer(key, value) {
|
|
289
|
-
// Handle top-
|
|
373
|
+
// Handle top-stage vector
|
|
290
374
|
if (value?.__isVector__) {
|
|
291
375
|
return {
|
|
292
376
|
_type: "vector",
|
|
@@ -360,7 +444,7 @@ export function set(obj, path, value) {
|
|
|
360
444
|
* Converts an object or array to a formatted string representation.
|
|
361
445
|
*
|
|
362
446
|
* @param {*} obj - The object or array to convert.
|
|
363
|
-
* @param {number} [indentationLevel=INITIAL_LEVEL] - The current indentation
|
|
447
|
+
* @param {number} [indentationLevel=INITIAL_LEVEL] - The current indentation stage (used for nested structures).
|
|
364
448
|
* @returns {string} A string representation of the input object or array.
|
|
365
449
|
*/
|
|
366
450
|
export function toString(obj, indentationLevel = INITIAL_LEVEL) {
|
|
@@ -396,36 +480,3 @@ ${" ".repeat(indentationLevel)}}`
|
|
|
396
480
|
|
|
397
481
|
return obj
|
|
398
482
|
}
|
|
399
|
-
|
|
400
|
-
/**
|
|
401
|
-
* Recursively merges properties from a source object into a target object.
|
|
402
|
-
* This is a helper function for `merge` and `extend`.
|
|
403
|
-
*
|
|
404
|
-
* @param {Object} target - The target object to merge into.
|
|
405
|
-
* @param {Object} source - The source object to merge from.
|
|
406
|
-
* @param {Function} [merger] - An optional function to customize merging behavior for specific keys.
|
|
407
|
-
* @returns {Object} - The modified target object.
|
|
408
|
-
*/
|
|
409
|
-
function deepMerge(target, source, merger) {
|
|
410
|
-
for (const [key, value] of Object.entries(source)) {
|
|
411
|
-
if (isFunction(merger)) {
|
|
412
|
-
const mergedValue = merger(target[key], value)
|
|
413
|
-
if (mergedValue !== undefined) {
|
|
414
|
-
target[key] = mergedValue
|
|
415
|
-
continue
|
|
416
|
-
}
|
|
417
|
-
}
|
|
418
|
-
|
|
419
|
-
if (isArray(value)) {
|
|
420
|
-
target[key] = value
|
|
421
|
-
} else if (isObject(value)) {
|
|
422
|
-
if (!isObject(target[key])) {
|
|
423
|
-
target[key] = {}
|
|
424
|
-
}
|
|
425
|
-
target[key] = deepMerge(target[key], value, merger)
|
|
426
|
-
} else {
|
|
427
|
-
target[key] = value
|
|
428
|
-
}
|
|
429
|
-
}
|
|
430
|
-
return target
|
|
431
|
-
}
|
|
@@ -11,3 +11,80 @@ export function toCamelCase(input) {
|
|
|
11
11
|
|
|
12
12
|
return [firstChar.toLowerCase(), ...rest].join("")
|
|
13
13
|
}
|
|
14
|
+
|
|
15
|
+
// How long a row or column is by one, which is the whole of what the offsets below mean.
|
|
16
|
+
// The grid's own edges are counted by the same one.
|
|
17
|
+
const ONE = 1
|
|
18
|
+
const NONE = 0
|
|
19
|
+
const FIRST = 0
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* How far one string is from another, in single-character edits.
|
|
23
|
+
*
|
|
24
|
+
* The grid is built in full rather than in the one row that would do, because this is
|
|
25
|
+
* short and the short version is where an off-by-one hides.
|
|
26
|
+
*
|
|
27
|
+
* @example
|
|
28
|
+
* ```js
|
|
29
|
+
* import { editDistance } from "@inglorious/utils/data-structures/string.js"
|
|
30
|
+
*
|
|
31
|
+
* editDistance("audio", "audi") // 1
|
|
32
|
+
* ```
|
|
33
|
+
*
|
|
34
|
+
* @param {string} a - The string that was asked about.
|
|
35
|
+
* @param {string} b - The string to compare it with.
|
|
36
|
+
* @returns {number} How many edits turn one into the other.
|
|
37
|
+
*/
|
|
38
|
+
export function editDistance(a, b) {
|
|
39
|
+
const grid = Array.from({ length: a.length + ONE }, () =>
|
|
40
|
+
Array.from({ length: b.length + ONE }, () => NONE),
|
|
41
|
+
)
|
|
42
|
+
|
|
43
|
+
for (let i = FIRST; i <= a.length; i++) grid[i][FIRST] = i
|
|
44
|
+
for (let j = FIRST; j <= b.length; j++) grid[FIRST][j] = j
|
|
45
|
+
|
|
46
|
+
for (let i = ONE; i <= a.length; i++) {
|
|
47
|
+
for (let j = ONE; j <= b.length; j++) {
|
|
48
|
+
grid[i][j] = Math.min(
|
|
49
|
+
grid[i - ONE][j] + ONE,
|
|
50
|
+
grid[i][j - ONE] + ONE,
|
|
51
|
+
grid[i - ONE][j - ONE] + (a[i - ONE] === b[j - ONE] ? NONE : ONE),
|
|
52
|
+
)
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
return grid[a.length][b.length]
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
// How far a string may be from the one asked about and still be worth suggesting. A
|
|
60
|
+
// mistyped name is nearly always one or two edits away from the right one; anything
|
|
61
|
+
// further off is a different string rather than a wrong one.
|
|
62
|
+
const NEAR_ENOUGH = 3
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* The strings closest to one that was asked for, nearest first.
|
|
66
|
+
*
|
|
67
|
+
* Case is folded, because a name differing from a declared one only by a capital is the
|
|
68
|
+
* commonest kind of mistake and the one where saying nothing is least helpful.
|
|
69
|
+
*
|
|
70
|
+
* @example
|
|
71
|
+
* ```js
|
|
72
|
+
* import { namesNear } from "@inglorious/utils/data-structures/string.js"
|
|
73
|
+
*
|
|
74
|
+
* namesNear("audio", ["Game", "Audio"]) // ["Audio"]
|
|
75
|
+
* ```
|
|
76
|
+
*
|
|
77
|
+
* @param {string} wanted - The string that was asked for.
|
|
78
|
+
* @param {string[]} candidates - Every string that could have been meant.
|
|
79
|
+
* @returns {string[]} The ones worth suggesting, which may be none of them.
|
|
80
|
+
*/
|
|
81
|
+
export function namesNear(wanted, candidates) {
|
|
82
|
+
const target = wanted.toLowerCase()
|
|
83
|
+
const allowed = Math.max(ONE, Math.floor(target.length / NEAR_ENOUGH))
|
|
84
|
+
|
|
85
|
+
return candidates
|
|
86
|
+
.map((name) => [name, editDistance(target, name.toLowerCase())])
|
|
87
|
+
.filter(([, d]) => d <= allowed)
|
|
88
|
+
.sort(([, a], [, b]) => a - b)
|
|
89
|
+
.map(([name]) => name)
|
|
90
|
+
}
|
package/src/functions/index.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export * from "./
|
|
1
|
+
export * from "./function.js"
|
package/src/math/circle.js
CHANGED
package/src/math/hitmask.js
CHANGED
package/src/math/index.js
CHANGED
|
@@ -2,16 +2,16 @@ import * as circle from "./circle.js"
|
|
|
2
2
|
import * as hitmask from "./hitmask.js"
|
|
3
3
|
import * as line from "./line.js"
|
|
4
4
|
import * as linearInterpolation from "./linear-interpolation.js"
|
|
5
|
-
import * as numbers from "./
|
|
5
|
+
import * as numbers from "./number.js"
|
|
6
6
|
import * as point from "./point.js"
|
|
7
|
-
import * as quaternions from "./
|
|
7
|
+
import * as quaternions from "./quaternion.js"
|
|
8
8
|
import * as rectangle from "./rectangle.js"
|
|
9
9
|
import * as rng from "./rng.js"
|
|
10
10
|
import * as segment from "./segment.js"
|
|
11
11
|
import * as statistics from "./statistics.js"
|
|
12
12
|
import * as triangle from "./triangle.js"
|
|
13
13
|
import * as trigonometry from "./trigonometry.js"
|
|
14
|
-
import * as
|
|
14
|
+
import * as vector from "./vector.js"
|
|
15
15
|
|
|
16
16
|
export {
|
|
17
17
|
circle,
|
|
@@ -27,5 +27,5 @@ export {
|
|
|
27
27
|
statistics,
|
|
28
28
|
triangle,
|
|
29
29
|
trigonometry,
|
|
30
|
-
|
|
30
|
+
vector,
|
|
31
31
|
}
|
package/src/math/line.js
CHANGED
package/src/math/point.js
CHANGED
|
@@ -1,4 +1,25 @@
|
|
|
1
1
|
/**
|
|
2
|
+
* A point in the Inglorious coordinate system: `[x, y, z]`.
|
|
3
|
+
*
|
|
4
|
+
* The world is y-up: the origin sits on the floor, and a bigger `y` is always a
|
|
5
|
+
* higher place in the world. Gravity subtracts from it, a jump adds to it, and an
|
|
6
|
+
* object resting on the ground has `y = 0`.
|
|
7
|
+
*
|
|
8
|
+
* `z` is the depth axis, and it is y-up as well — it is not screen-down, so both
|
|
9
|
+
* vertical axes grow upwards. Renderers turn them into screen coordinates:
|
|
10
|
+
* `@inglorious/renderer-2d` projects a point to `canvasY = height - y - z`,
|
|
11
|
+
* which puts `(0, 0, 0)` at the bottom-left of the canvas and turns both axes
|
|
12
|
+
* upside down.
|
|
13
|
+
*
|
|
14
|
+
* @example Reading a position in a 2D game
|
|
15
|
+
* ```js
|
|
16
|
+
* v(0, 0, 0) // the floor
|
|
17
|
+
* v(0, 100, 0) // a hundred pixels up
|
|
18
|
+
*
|
|
19
|
+
* entity.velocity[1] -= GRAVITY * dt // falling loses height
|
|
20
|
+
* entity.position[1] = 0 // keeping a body on the ground
|
|
21
|
+
* ```
|
|
22
|
+
*
|
|
2
23
|
* @typedef {import("../../types/math/point").Point} Point
|
|
3
24
|
* @typedef {import("../../types/math/point").PointInput} PointInput
|
|
4
25
|
* @typedef {import("../../types/math/line").Line} Line
|
|
@@ -10,8 +31,8 @@ const SQUARED = 2
|
|
|
10
31
|
const HALF = 2
|
|
11
32
|
|
|
12
33
|
import { distanceFromPoint } from "./line.js"
|
|
13
|
-
import { isBetween } from "./
|
|
14
|
-
import { isVector } from "./
|
|
34
|
+
import { isBetween } from "./number.js"
|
|
35
|
+
import { isVector } from "./vector.js"
|
|
15
36
|
|
|
16
37
|
/**
|
|
17
38
|
* Calculates the distance from a point to a line.
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* @typedef {import("../../types/math/
|
|
3
|
-
* @typedef {import("../../types/math/
|
|
2
|
+
* @typedef {import("../../types/math/vector").Vector3} Vector3
|
|
3
|
+
* @typedef {import("../../types/math/quaternion").Quaternion} Quaternion
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
6
|
import { v } from "../v.js"
|
|
7
7
|
import { cos, sin } from "./trigonometry.js"
|
|
8
|
-
import { cross, dot, multiply, sum } from "./
|
|
8
|
+
import { cross, dot, multiply, sum } from "./vector.js"
|
|
9
9
|
|
|
10
10
|
const DEFAULT_ANGLE = 0
|
|
11
11
|
const HALF = 2 // Constant representing the divisor for halving an angle.
|
package/src/math/rectangle.js
CHANGED
|
@@ -1,4 +1,11 @@
|
|
|
1
1
|
/**
|
|
2
|
+
* `height` and `depth` are independent axes, not halves of one screen
|
|
3
|
+
* dimension, so a body on the `xy` plane is sized `v(w, h, 0)` and one on the
|
|
4
|
+
* `xz` plane `v(w, 0, h)`. `@inglorious/renderer-2d` flattens both onto the
|
|
5
|
+
* screen and draws a rectangle `height + depth` tall, while
|
|
6
|
+
* {@link intersectsRectangle} tests the two axes separately.
|
|
7
|
+
*
|
|
8
|
+
* @typedef {import("../../types/math/rectangle").Size} Size
|
|
2
9
|
* @typedef {import("../../types/math/circle").Circle} Circle
|
|
3
10
|
* @typedef {import("../../types/math/point").PointInput} PointInput
|
|
4
11
|
* @typedef {import("../../types/math/rectangle").Rectangle} Rectangle
|
|
@@ -11,6 +18,11 @@ const HALF = 2
|
|
|
11
18
|
|
|
12
19
|
/**
|
|
13
20
|
* Checks if a rectangle intersects with a point.
|
|
21
|
+
*
|
|
22
|
+
* The rectangle's `position` is its center, and `size` extends around it. An
|
|
23
|
+
* anchored shape is the exception: its `anchor` picks which point sits on the
|
|
24
|
+
* position, so the two only line up when the anchor matches, such as
|
|
25
|
+
* `[0.5, 0.5]` for a centred one.
|
|
14
26
|
* @param {Rectangle} rectangle - The rectangle to check.
|
|
15
27
|
* @param {PointInput} point - The point to check.
|
|
16
28
|
* @returns {boolean} True if the point intersects the circle, false otherwise.
|
package/src/math/rng.js
CHANGED
|
@@ -31,10 +31,13 @@ export function random(...args) {
|
|
|
31
31
|
return Math.random()
|
|
32
32
|
}
|
|
33
33
|
|
|
34
|
+
// A range with a fractional bound cannot be stepped through as integers, so it
|
|
35
|
+
// is read as a continuous range. Requiring both bounds to be floats used to
|
|
36
|
+
// send `random(0.5, 1)` down the integer path, where it could only ever answer
|
|
37
|
+
// 0 or 1.
|
|
34
38
|
if (
|
|
35
39
|
args.length > 1 &&
|
|
36
|
-
!Number.isInteger(args[0])
|
|
37
|
-
!Number.isInteger(args[1])
|
|
40
|
+
(!Number.isInteger(args[0]) || !Number.isInteger(args[1]))
|
|
38
41
|
) {
|
|
39
42
|
const [from, to] = args
|
|
40
43
|
return Math.random() * (to - from) + from
|
package/src/math/segment.js
CHANGED
package/src/math/trigonometry.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* @typedef {import("../../types/math/
|
|
3
|
-
* @typedef {import("../../types/math/
|
|
4
|
-
* @typedef {import("../../types/math/
|
|
5
|
-
* @typedef {import("../../types/math/
|
|
2
|
+
* @typedef {import("../../types/math/vector").Vector} Vector
|
|
3
|
+
* @typedef {import("../../types/math/vector").Vector2} Vector2
|
|
4
|
+
* @typedef {import("../../types/math/vector").Vector3} Vector3
|
|
5
|
+
* @typedef {import("../../types/math/vector").Vector7} Vector7
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
8
|
import { v } from "../v.js"
|
|
@@ -11,13 +11,32 @@ import {
|
|
|
11
11
|
clamp as nClamp,
|
|
12
12
|
mod as nMod,
|
|
13
13
|
snap as nSnap,
|
|
14
|
-
} from "./
|
|
15
|
-
import { quaternion } from "./
|
|
14
|
+
} from "./number.js"
|
|
15
|
+
import { quaternion } from "./quaternion.js"
|
|
16
|
+
import { random } from "./rng.js"
|
|
16
17
|
import { hypothenuse } from "./triangle.js"
|
|
17
18
|
import { atan2, cos, sin } from "./trigonometry.js"
|
|
18
19
|
|
|
19
|
-
|
|
20
|
-
|
|
20
|
+
/**
|
|
21
|
+
* The vector with every component at zero. Useful for naming the components you
|
|
22
|
+
* care about, and for building a vector up from scratch:
|
|
23
|
+
*
|
|
24
|
+
* const [, NO_RISE, NO_DEPTH] = ZERO_VECTOR
|
|
25
|
+
* const position = v(10, 20, NO_DEPTH)
|
|
26
|
+
*
|
|
27
|
+
* Vectors are mutable arrays, so copy it rather than storing it where something
|
|
28
|
+
* writes to one, such as an entity position. Copy it with `v(...ZERO_VECTOR)`,
|
|
29
|
+
* since a plain spread drops the tag `isVector` looks for.
|
|
30
|
+
*/
|
|
31
|
+
export const ZERO_VECTOR = v(0, 0, 0) // eslint-disable-line no-magic-numbers
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* The vector one unit long along the x axis. Useful for facing a direction, as
|
|
35
|
+
* in `rotate(UNIT_VECTOR, angle)`.
|
|
36
|
+
*
|
|
37
|
+
* As with `ZERO_VECTOR`, copy it with `v(...UNIT_VECTOR)` before storing it.
|
|
38
|
+
*/
|
|
39
|
+
export const UNIT_VECTOR = v(1, 0, 0) // eslint-disable-line no-magic-numbers
|
|
21
40
|
|
|
22
41
|
const X = 0
|
|
23
42
|
const Y = 1
|
|
@@ -25,6 +44,7 @@ const Z = 2
|
|
|
25
44
|
const LAST_COORDINATE = 1
|
|
26
45
|
const TWO_COORDINATES = 2
|
|
27
46
|
const NO_Y = 0
|
|
47
|
+
const NO_COMPONENT = 0
|
|
28
48
|
const DEFAULT_PRECISION = 1
|
|
29
49
|
const DEFAULT_DECIMALS = 0
|
|
30
50
|
|
|
@@ -228,6 +248,16 @@ export function multiply(...operands) {
|
|
|
228
248
|
return v(...operands.reduce(multiplyCoordinates))
|
|
229
249
|
}
|
|
230
250
|
|
|
251
|
+
/**
|
|
252
|
+
* Flips the direction of every component, so that adding the result to a vector
|
|
253
|
+
* gives back the point mirrored through it.
|
|
254
|
+
* @param {Vector} vector - The input vector.
|
|
255
|
+
* @returns {Vector} The negated vector.
|
|
256
|
+
*/
|
|
257
|
+
export function negate(vector) {
|
|
258
|
+
return v(...vector.map((coordinate) => -coordinate))
|
|
259
|
+
}
|
|
260
|
+
|
|
231
261
|
/**
|
|
232
262
|
* Normalizes the vector to have a magnitude of 1.
|
|
233
263
|
* @param {Vector} vector - The input vector.
|
|
@@ -264,6 +294,35 @@ export function powerOf(scalar, vector) {
|
|
|
264
294
|
return v(...vector.map((coordinate) => scalar ** coordinate))
|
|
265
295
|
}
|
|
266
296
|
|
|
297
|
+
/**
|
|
298
|
+
* Draws a random vector, taking each component from its own range: the low end is
|
|
299
|
+
* where that axis starts, the high end where it can reach. This is `random`
|
|
300
|
+
* applied per axis, so it suits ranges that differ by axis, where a single pair of
|
|
301
|
+
* bounds would have to be square.
|
|
302
|
+
*
|
|
303
|
+
* A component whose bounds are the same always comes out equal to them, and either
|
|
304
|
+
* bound may be left out to fall back to zero on that axis.
|
|
305
|
+
*
|
|
306
|
+
* @param {Vector} [low] - Where each axis starts.
|
|
307
|
+
* @param {Vector} [high] - Where each axis can reach.
|
|
308
|
+
* @returns {Vector} The random vector.
|
|
309
|
+
* @example
|
|
310
|
+
* ```js
|
|
311
|
+
* // Debris thrown to the left or right, never up or down.
|
|
312
|
+
* randomVector(v(-15, 0, 0), v(15, 0, 0))
|
|
313
|
+
* ```
|
|
314
|
+
*/
|
|
315
|
+
export function randomVector(low, high) {
|
|
316
|
+
const [lowX, lowY, lowZ] = low ?? []
|
|
317
|
+
const [highX, highY, highZ] = high ?? []
|
|
318
|
+
|
|
319
|
+
return v(
|
|
320
|
+
random(lowX ?? NO_COMPONENT, highX ?? NO_COMPONENT),
|
|
321
|
+
random(lowY ?? NO_COMPONENT, highY ?? NO_COMPONENT),
|
|
322
|
+
random(lowZ ?? NO_COMPONENT, highZ ?? NO_COMPONENT),
|
|
323
|
+
)
|
|
324
|
+
}
|
|
325
|
+
|
|
267
326
|
/**
|
|
268
327
|
* Alias for the mod function.
|
|
269
328
|
* @type {typeof mod}
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* @typedef {import("../../types/math/
|
|
2
|
+
* @typedef {import("../../types/math/vector").Vector3} Vector3
|
|
3
3
|
*/
|
|
4
4
|
|
|
5
|
-
import { clamp, multiply, sum, zero } from "../math/
|
|
5
|
+
import { clamp, multiply, sum, zero } from "../math/vector.js"
|
|
6
6
|
import { applyFriction } from "./friction.js"
|
|
7
7
|
|
|
8
8
|
const DEFAULT_DT = 1 // Default time delta for the applyAcceleration function.
|
package/src/physics/friction.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* @typedef {import("../../types/math/
|
|
2
|
+
* @typedef {import("../../types/math/vector").Vector3} Vector3
|
|
3
3
|
*/
|
|
4
4
|
|
|
5
|
-
import { magnitude, setMagnitude, zero } from "../math/
|
|
5
|
+
import { magnitude, setMagnitude, zero } from "../math/vector.js"
|
|
6
6
|
|
|
7
7
|
const DEFAULT_DT = 1 // Default time delta for the applyFriction function.
|
|
8
8
|
const NO_FRICTION = 0 // No friction constant.
|
package/src/physics/gravity.js
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* @typedef {import("../../types/math/
|
|
2
|
+
* @typedef {import("../../types/math/vector").Vector3} Vector3
|
|
3
3
|
*/
|
|
4
4
|
|
|
5
5
|
/* eslint-disable no-magic-numbers */
|
|
6
6
|
|
|
7
|
-
import { zero } from "../math/
|
|
7
|
+
import { zero } from "../math/vector.js"
|
|
8
8
|
|
|
9
9
|
const DEFAULT_DT = 1 // Default delta time for the applyGravity function.
|
|
10
10
|
const DEFAULT_JUMP = 0 // Default maximum jump height.
|
package/src/physics/velocity.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* @typedef {import("../../types/math/
|
|
2
|
+
* @typedef {import("../../types/math/vector").Vector3} Vector3
|
|
3
3
|
*/
|
|
4
4
|
|
|
5
|
-
import { clamp, multiply, sum, zero } from "../math/
|
|
5
|
+
import { clamp, multiply, sum, zero } from "../math/vector.js"
|
|
6
6
|
|
|
7
7
|
const DEFAULT_DT = 1 // Default time delta for the applyVelocity function.
|
|
8
8
|
const DEFAULT_MAX_SPEED = 0 // Default maximum speed for velocity clamping.
|
package/src/v.js
CHANGED
|
@@ -5,6 +5,11 @@ export type Comparator<T> = (left: T, right: T) => number
|
|
|
5
5
|
*/
|
|
6
6
|
export function contains<T>(arr: readonly T[], item: T): boolean
|
|
7
7
|
|
|
8
|
+
/**
|
|
9
|
+
* The index `step` places along a list of `length`, wrapping round at either end.
|
|
10
|
+
*/
|
|
11
|
+
export function cycleIndex(index: number, length: number, step: number): number
|
|
12
|
+
|
|
8
13
|
/**
|
|
9
14
|
* Ensures that a value is an array.
|
|
10
15
|
*/
|
|
@@ -2,7 +2,7 @@ export * as array from "./array"
|
|
|
2
2
|
export * as board from "./board"
|
|
3
3
|
export * as boolean from "./boolean"
|
|
4
4
|
export * as heap from "./heap"
|
|
5
|
-
export * as
|
|
5
|
+
export * as object from "./object"
|
|
6
6
|
export * as set from "./set"
|
|
7
7
|
export * as string from "./string"
|
|
8
8
|
export * as tree from "./tree"
|
package/types/math/index.d.ts
CHANGED
|
@@ -2,13 +2,13 @@ export * as circle from "./circle"
|
|
|
2
2
|
export * as hitmask from "./hitmask"
|
|
3
3
|
export * as line from "./line"
|
|
4
4
|
export * as linearInterpolation from "./linear-interpolation"
|
|
5
|
-
export * as
|
|
5
|
+
export * as number from "./number"
|
|
6
6
|
export * as point from "./point"
|
|
7
|
-
export * as
|
|
7
|
+
export * as quaternion from "./quaternion"
|
|
8
8
|
export * as rectangle from "./rectangle"
|
|
9
9
|
export * as rng from "./rng"
|
|
10
10
|
export * as segment from "./segment"
|
|
11
11
|
export * as statistics from "./statistics"
|
|
12
12
|
export * as triangle from "./triangle"
|
|
13
13
|
export * as trigonometry from "./trigonometry"
|
|
14
|
-
export * as
|
|
14
|
+
export * as vector from "./vector"
|
package/types/math/point.d.ts
CHANGED
|
@@ -3,7 +3,32 @@ import type { Circle } from "./circle"
|
|
|
3
3
|
import type { Line } from "./line"
|
|
4
4
|
import type { Rectangle } from "./rectangle"
|
|
5
5
|
|
|
6
|
-
/**
|
|
6
|
+
/**
|
|
7
|
+
* A point in the Inglorious coordinate system: `[x, y, z]`.
|
|
8
|
+
*
|
|
9
|
+
* The world is **y-up**: the origin sits on the floor, and a bigger `y` is
|
|
10
|
+
* always a higher place in the world. Gravity subtracts from it, a jump adds to
|
|
11
|
+
* it, and an object resting on the ground has `y = 0`.
|
|
12
|
+
*
|
|
13
|
+
* `z` is the depth axis, and it is **y-up as well** — it is not screen-down, so
|
|
14
|
+
* both vertical axes grow upwards. Renderers are what turn them into screen
|
|
15
|
+
* coordinates: `@inglorious/renderer-2d` projects a point to
|
|
16
|
+
* `canvasY = viewportHeight - y - z`, which puts `(0, 0, 0)` at the bottom-left
|
|
17
|
+
* corner of the canvas and turns both axes upside down.
|
|
18
|
+
*
|
|
19
|
+
* @example Reading a position in a 2D game
|
|
20
|
+
* ```js
|
|
21
|
+
* // Ground level, and a hundred pixels above it.
|
|
22
|
+
* v(0, 0, 0) // the floor
|
|
23
|
+
* v(0, 100, 0) // a hundred pixels up
|
|
24
|
+
*
|
|
25
|
+
* // Falling means losing height, in 2D as well as in 3D.
|
|
26
|
+
* entity.velocity[1] -= GRAVITY * dt
|
|
27
|
+
*
|
|
28
|
+
* // Keep a body on the ground.
|
|
29
|
+
* entity.position[1] = 0
|
|
30
|
+
* ```
|
|
31
|
+
*/
|
|
7
32
|
export type Point = readonly [x: number, y: number, z: number]
|
|
8
33
|
|
|
9
34
|
/** Accepts a 3D point, branded vector, or object with a point position. */
|
|
@@ -1,10 +1,31 @@
|
|
|
1
1
|
import type { Circle } from "./circle"
|
|
2
2
|
import type { Point, PointInput } from "./point"
|
|
3
3
|
|
|
4
|
-
/**
|
|
4
|
+
/**
|
|
5
|
+
* The dimensions of a 3D object, as `[width, height, depth]`.
|
|
6
|
+
*
|
|
7
|
+
* `width` is the extent along `x`, `height` the extent along `y` and `depth` the
|
|
8
|
+
* extent along `z`. `height` and `depth` are **independent axes**, not halves of
|
|
9
|
+
* one screen dimension, so in a 2D game that plays on the `xy` plane a size reads
|
|
10
|
+
* as `v(w, h, 0)` — and an entity whose body is placed on the `xz` plane instead
|
|
11
|
+
* reads as `v(w, 0, h)`.
|
|
12
|
+
*
|
|
13
|
+
* When a renderer has to flatten both vertical axes onto the screen, it adds
|
|
14
|
+
* them: `@inglorious/renderer-2d` draws a rectangle `height + depth` tall. A
|
|
15
|
+
* collision shape never does — `intersectsRectangle` tests the two axes
|
|
16
|
+
* separately, which is why a body cannot collide with something that is merely
|
|
17
|
+
* "near it" on the other axis.
|
|
18
|
+
*/
|
|
5
19
|
export type Size = readonly [width: number, height: number, depth: number]
|
|
6
20
|
|
|
7
|
-
/**
|
|
21
|
+
/**
|
|
22
|
+
* Represents an axis-aligned rectangle.
|
|
23
|
+
*
|
|
24
|
+
* `position` is the point the box hangs off and `size` is its extent, so with
|
|
25
|
+
* the default centred anchor the position is the middle of the box. Set an
|
|
26
|
+
* `anchor` to describe the box by a different point, such as `[0, 0]` for its
|
|
27
|
+
* bottom-left corner, so that the box stands on its position.
|
|
28
|
+
*/
|
|
8
29
|
export interface Rectangle {
|
|
9
30
|
/** The center of the rectangle. */
|
|
10
31
|
position: Point
|
|
@@ -18,6 +18,22 @@ export type Vector7 = Vector<
|
|
|
18
18
|
readonly [number, number, number, number, number, number, number]
|
|
19
19
|
>
|
|
20
20
|
|
|
21
|
+
/**
|
|
22
|
+
* The vector with every component at zero.
|
|
23
|
+
*
|
|
24
|
+
* Vectors are mutable, so copy it with `v(...ZERO_VECTOR)` before storing it
|
|
25
|
+
* where something writes to one.
|
|
26
|
+
*/
|
|
27
|
+
export const ZERO_VECTOR: Vector3
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* The vector one unit long along the x axis.
|
|
31
|
+
*
|
|
32
|
+
* Vectors are mutable, so copy it with `v(...UNIT_VECTOR)` before storing it
|
|
33
|
+
* where something writes to one.
|
|
34
|
+
*/
|
|
35
|
+
export const UNIT_VECTOR: Vector3
|
|
36
|
+
|
|
21
37
|
/** Returns the absolute value of each vector component. */
|
|
22
38
|
export function abs<T extends Vector>(vector: T): T
|
|
23
39
|
|
|
@@ -107,6 +123,11 @@ export function multiply<T extends Vector2 | Vector3>(
|
|
|
107
123
|
): T
|
|
108
124
|
|
|
109
125
|
/** Normalizes a vector to unit magnitude. */
|
|
126
|
+
/**
|
|
127
|
+
* Flips the direction of every component.
|
|
128
|
+
*/
|
|
129
|
+
export function negate<T extends Vector>(vector: T): T
|
|
130
|
+
|
|
110
131
|
export function normalize<T extends Vector>(vector: T): T
|
|
111
132
|
|
|
112
133
|
/** Alias for `power`. */
|
|
@@ -124,6 +145,14 @@ export function power<T extends Vector2 | Vector3>(
|
|
|
124
145
|
/** Raises a scalar to each vector component. */
|
|
125
146
|
export function powerOf<T extends Vector>(scalar: number, vector: T): T
|
|
126
147
|
|
|
148
|
+
/**
|
|
149
|
+
* Draws a random vector, taking each component from its own range.
|
|
150
|
+
*/
|
|
151
|
+
export function randomVector(
|
|
152
|
+
low?: readonly number[],
|
|
153
|
+
high?: readonly number[],
|
|
154
|
+
): Vector3
|
|
155
|
+
|
|
127
156
|
/** Alias for `mod`. */
|
|
128
157
|
export const remainder: typeof mod
|
|
129
158
|
|
package/types/v.d.ts
CHANGED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|