@woosh/meep-engine 2.51.0 → 2.52.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 (98) hide show
  1. package/package.json +1 -1
  2. package/src/core/NumberFormat.js +0 -71
  3. package/src/core/bvh2/bvh3/ExplicitBinaryBoundingVolumeHierarchy.js +1 -0
  4. package/src/core/bvh2/bvh3/query/BVHQueryAny.js +16 -0
  5. package/src/core/bvh2/bvh3/query/bvh_collect_user_data.js +5 -5
  6. package/src/core/bvh2/bvh3/query/bvh_query_leaves_generic.js +2 -3
  7. package/src/core/bvh2/bvh3/query/bvh_query_leaves_generic.spec.js +22 -0
  8. package/src/core/bvh2/bvh3/query/bvh_query_leaves_ray.js +2 -2
  9. package/src/core/bvh2/bvh3/query/bvh_query_leaves_ray.spec.js +64 -0
  10. package/src/core/bvh2/bvh3/query/bvh_query_user_data_generic.js +2 -3
  11. package/src/core/geom/3d/aabb/aabb3_from_threejs_geometry.js +41 -0
  12. package/src/core/geom/3d/topology/struct/TopoMesh.js +3 -2
  13. package/src/core/geom/3d/topology/struct/prototypeBinaryTopology.js +4 -4
  14. package/src/core/geom/Vector2.d.ts +9 -0
  15. package/src/core/geom/Vector2.js +8 -22
  16. package/src/core/geom/Vector2.spec.js +153 -0
  17. package/src/core/model/ModuleRegistry.js +2 -4
  18. package/src/core/model/ModuleRegistry.spec.js +31 -0
  19. package/src/core/model/reactive/js/compileReactiveToJS.spec.js +14 -0
  20. package/src/core/model/reactive/model/logic/ReactiveAnd.spec.js +31 -1
  21. package/src/core/model/reactive/model/logic/ReactiveOr.spec.js +53 -0
  22. package/src/core/model/stat/LinearModifier.js +2 -2
  23. package/src/core/model/stat/LinearModifier.spec.js +62 -0
  24. package/src/core/model/stat/Stat.js +12 -0
  25. package/src/core/model/stat/Stat.spec.js +36 -0
  26. package/src/core/primitives/array/computeStridedIntegerArrayHash.spec.js +28 -0
  27. package/src/core/primitives/numbers/number_format_by_thousands.js +14 -0
  28. package/src/core/primitives/numbers/number_pretty_print.js +49 -0
  29. package/src/core/primitives/strings/computeStringHash.spec.js +12 -5
  30. package/src/core/process/BaseProcess.js +8 -8
  31. package/src/engine/Clock.js +30 -29
  32. package/src/engine/Clock.spec.js +26 -0
  33. package/src/engine/ecs/EntityBuilder.js +3 -1
  34. package/src/engine/ecs/EntityBuilder.spec.js +21 -0
  35. package/src/engine/ecs/gui/GUIElement.js +1 -1
  36. package/src/engine/ecs/gui/position/ViewportPosition.js +3 -3
  37. package/src/engine/ecs/terrain/ecs/TerrainClassifier.js +1 -1
  38. package/src/engine/ecs/terrain/ecs/layers/TerrainLayers.js +1 -1
  39. package/src/engine/ecs/transform/Transform.js +1 -0
  40. package/src/engine/graphics/camera/testClippingPlaneComputation.js +0 -4
  41. package/src/engine/graphics/ecs/animation/animator/graph/AnimationGraph.spec.js +5 -0
  42. package/src/engine/graphics/ecs/animation/animator/graph/definition/AnimationGraphDefinition.js +24 -25
  43. package/src/engine/graphics/ecs/animation/animator/graph/definition/AnimationGraphDefinition.spec.js +5 -0
  44. package/src/engine/graphics/ecs/decal/DecalSystem.js +2 -20
  45. package/src/engine/graphics/ecs/decal/v2/Decal.js +32 -32
  46. package/src/engine/graphics/ecs/decal/v2/Decal.spec.js +5 -0
  47. package/src/engine/graphics/ecs/decal/v2/FPDecalSystem.js +4 -2
  48. package/src/engine/graphics/ecs/mesh-v2/ShadedGeometry.js +4 -33
  49. package/src/engine/graphics/ecs/mesh-v2/ShadedGeometrySystem.js +8 -4
  50. package/src/engine/graphics/ecs/mesh-v2/aggregate/SGMesh.spec.js +5 -0
  51. package/src/engine/graphics/ecs/mesh-v2/sample/prototypeShadedGeometry.js +0 -12
  52. package/src/engine/graphics/ecs/path/testPathDisplaySystem.js +0 -2
  53. package/src/engine/graphics/ecs/path/tube/prototypeAnimatedPathMask.js +0 -4
  54. package/src/engine/graphics/ecs/water2/shader/testWaterShader.js +0 -2
  55. package/src/engine/graphics/geometry/buffered/computeBufferAttributeHash.js +1 -1
  56. package/src/engine/graphics/particles/particular/engine/utils/volume/prototypeParticleVolume.js +0 -2
  57. package/src/engine/graphics/render/buffer/buffers/prototypeNormalFrameBuffer.js +0 -4
  58. package/src/engine/graphics/render/forward_plus/plugin/ptototypeFPPlugin.js +0 -4
  59. package/src/engine/graphics/render/forward_plus/prototype/prototypeLightManager.js +2 -2
  60. package/src/engine/graphics/render/visibility/hiz/prototypeHiZ.js +2 -6
  61. package/src/engine/graphics/sh3/path_tracer/GeometryBVHBatched.js +2 -1
  62. package/src/engine/graphics/sh3/path_tracer/PathTracer.js +6 -1
  63. package/src/engine/graphics/sh3/path_tracer/prototypePathTracer.js +2 -2
  64. package/src/engine/graphics/shadows/testShadowMapRendering.js +0 -2
  65. package/src/engine/graphics/texture/sampler/Sampler2D.js +1 -1
  66. package/src/engine/graphics/three/expand_aabb_by_transformed_three_object.js +3 -23
  67. package/src/engine/grid/components/GridObstacle.js +45 -25
  68. package/src/engine/grid/components/GridObstacle.spec.js +130 -1
  69. package/src/engine/grid/components/GridPosition.js +5 -17
  70. package/src/engine/grid/components/GridPosition2Transform.js +1 -70
  71. package/src/engine/grid/components/GridPosition2TransformSerializationAdapter.js +70 -0
  72. package/src/engine/plugin/EnginePlugin.js +12 -14
  73. package/src/engine/plugin/EnginePlugin.spec.js +5 -0
  74. package/src/engine/plugin/EnginePluginManager.js +18 -22
  75. package/src/engine/scene/transitionToScene.js +12 -1
  76. package/src/engine/simulation/Ticker.js +1 -1
  77. package/src/generation/theme/TerrainLayerDescription.js +1 -1
  78. package/src/view/common/LabelView.js +3 -3
  79. package/src/engine/ecs/components/AimController.js +0 -18
  80. package/src/engine/ecs/components/Attacker.js +0 -13
  81. package/src/engine/ecs/components/MeshCollider.js +0 -15
  82. package/src/engine/ecs/components/RangedAttack.js +0 -12
  83. package/src/engine/ecs/components/TargetAI.js +0 -11
  84. package/src/engine/ecs/components/ViewportMeshProjection.js +0 -18
  85. package/src/engine/ecs/systems/AimControllerSystem.js +0 -63
  86. package/src/engine/ecs/systems/AttackerSystem.js +0 -67
  87. package/src/engine/ecs/systems/MeshColliderSystem.js +0 -47
  88. package/src/engine/ecs/systems/MonsterAISystem.js +0 -163
  89. package/src/engine/ecs/systems/MortalitySystem.js +0 -46
  90. package/src/engine/ecs/systems/RangedAttackSystem.js +0 -132
  91. package/src/engine/ecs/systems/SerializationMetadataSystem.js +0 -10
  92. package/src/engine/ecs/systems/TargetAISystem.js +0 -107
  93. package/src/engine/ecs/systems/ViewportMeshProjectionSystem.js +0 -68
  94. package/src/engine/graphics/particles/ParticleEmitterLibrary.js +0 -87
  95. package/src/engine/grid/components/ViewportGridProjection.js +0 -20
  96. package/src/engine/grid/systems/GridObstacleSystem.js +0 -58
  97. package/src/engine/grid/systems/ViewportGridProjectionSystem.js +0 -105
  98. /package/src/{engine → core/primitives/array}/computeStridedIntegerArrayHash.js +0 -0
package/package.json CHANGED
@@ -5,7 +5,7 @@
5
5
  "description": "Fully featured ECS game engine written in JavaScript",
6
6
  "type": "module",
7
7
  "author": "Alexander Goldring",
8
- "version": "2.51.0",
8
+ "version": "2.52.0",
9
9
  "main": "build/meep.module.js",
10
10
  "module": "build/meep.module.js",
11
11
  "exports": {
@@ -2,74 +2,3 @@
2
2
  * Created by Alex on 08/08/2016.
3
3
  * @copyright Alex Goldring 2016
4
4
  */
5
-
6
-
7
- import { assert } from "./assert.js";
8
-
9
- /**
10
- *
11
- * @param {number} x
12
- * @param {string} [separator]
13
- * @returns {string}
14
- */
15
- function formatNumberByThousands(x, separator) {
16
- if (separator === undefined) {
17
- separator = ','
18
- }
19
-
20
- return x.toString().replace(/\B(?=(\d{3})+(?!\d))/g, separator);
21
- }
22
-
23
-
24
- /**
25
- *
26
- * @param {string} value
27
- * @returns {number}
28
- */
29
- function countDecimals(value) {
30
- if (value % 1 === 0) {
31
- //whole number
32
- return 0;
33
- }
34
- const s = value.toString();
35
- const index = s.indexOf('.');
36
-
37
- if (index === -1) {
38
- return 0;
39
- }
40
-
41
- //find last 0
42
- let endIndex = s.length - 1;
43
- for (; endIndex > index && s.charAt(endIndex) === "0"; endIndex--) {
44
-
45
- }
46
- const result = endIndex - index;
47
- return result;
48
- }
49
-
50
- /**
51
- *
52
- * @param {number} value
53
- * @returns {string|number}
54
- */
55
- function prettyPrint(value) {
56
- assert.typeOf(value, 'number', 'value');
57
-
58
- const MAX_DECIMALS = 2;
59
-
60
- const fraction = value % 1;
61
- if (fraction !== 0 && Math.abs(value) < 100) {
62
- const decimals = countDecimals(value.toFixed(MAX_DECIMALS));
63
- const decimalsToPrint = Math.min(decimals, MAX_DECIMALS);
64
- return value.toFixed(decimalsToPrint);
65
- } else {
66
- //no fraction
67
- return formatNumberByThousands(value - fraction, ",");
68
- }
69
-
70
- }
71
-
72
- export {
73
- prettyPrint,
74
- formatNumberByThousands
75
- };
@@ -583,6 +583,7 @@ export class ExplicitBinaryBoundingVolumeHierarchy {
583
583
  */
584
584
  insert_leaf(leaf) {
585
585
  assert.isNonNegativeInteger(leaf, 'leaf');
586
+ assert.equal(this.node_is_leaf(leaf), true, 'not is not a leaf');
586
587
 
587
588
  let uint32 = this.__data_uint32;
588
589
 
@@ -0,0 +1,16 @@
1
+ import { BVHQuery } from "./BVHQuery.js";
2
+
3
+ /**
4
+ * Accept any node
5
+ */
6
+ export class BVHQueryAny extends BVHQuery {
7
+ evaluate(node, tree) {
8
+ return true;
9
+ }
10
+
11
+ /**
12
+ * @readonly
13
+ * @type {BVHQueryAny}
14
+ */
15
+ static INSTANCE = new BVHQueryAny();
16
+ }
@@ -10,15 +10,15 @@ const stack = SCRATCH_UINT32_TRAVERSAL_STACK;
10
10
  * @param {number[]} destination
11
11
  * @param {number} destination_offset
12
12
  * @param {ExplicitBinaryBoundingVolumeHierarchy} bvh
13
- * @param {number} node
13
+ * @param {number} root
14
14
  * @returns {number} number of collected elements
15
15
  */
16
16
  export function bvh_collect_user_data(
17
17
  destination, destination_offset,
18
- bvh, node
18
+ bvh, root
19
19
  ) {
20
20
 
21
- if (node === NULL_NODE) {
21
+ if (root === NULL_NODE) {
22
22
  return 0;
23
23
  }
24
24
 
@@ -28,7 +28,7 @@ export function bvh_collect_user_data(
28
28
  */
29
29
  const stack_top = stack.pointer++;
30
30
 
31
- stack[stack_top] = node;
31
+ stack[stack_top] = root;
32
32
 
33
33
  let result_cursor = destination_offset;
34
34
 
@@ -54,7 +54,7 @@ export function bvh_collect_user_data(
54
54
  stack[stack.pointer++] = child2;
55
55
 
56
56
  } else {
57
- // leaf node
57
+ // leaf root
58
58
 
59
59
  destination[result_cursor++] = bvh.node_get_user_data(node);
60
60
  }
@@ -8,16 +8,15 @@ const stack = SCRATCH_UINT32_TRAVERSAL_STACK;
8
8
  * @param {ExplicitBinaryBoundingVolumeHierarchy} bvh
9
9
  * @param {number[]} result
10
10
  * @param {number} result_offset
11
+ * @param {number} root
11
12
  * @param {BVHQuery} query
12
13
  * @returns {number}
13
14
  */
14
15
  export function bvh_query_leaves_generic(
15
16
  result, result_offset,
16
- bvh, query
17
+ bvh, root, query
17
18
  ) {
18
19
 
19
- const root = bvh.root;
20
-
21
20
  if (root === NULL_NODE) {
22
21
  return 0;
23
22
  }
@@ -0,0 +1,22 @@
1
+ import { ExplicitBinaryBoundingVolumeHierarchy } from "../ExplicitBinaryBoundingVolumeHierarchy.js";
2
+ import { bvh_query_leaves_generic } from "./bvh_query_leaves_generic.js";
3
+ import { BVHQueryAny } from "./BVHQueryAny.js";
4
+
5
+ test("all-accepting query", () => {
6
+ const bvh = new ExplicitBinaryBoundingVolumeHierarchy();
7
+
8
+ const leaf_a = bvh.allocate_node();
9
+ const leaf_b = bvh.allocate_node();
10
+
11
+ bvh.insert_leaf(leaf_a);
12
+ bvh.insert_leaf(leaf_b);
13
+
14
+ const result = [];
15
+
16
+ const count = bvh_query_leaves_generic(result, 1, bvh, bvh.root, BVHQueryAny.INSTANCE);
17
+
18
+ expect(count).toBe(2);
19
+ expect(result).toContain(leaf_a);
20
+ expect(result).toContain(leaf_b);
21
+
22
+ });
@@ -13,6 +13,7 @@ const stack = SCRATCH_UINT32_TRAVERSAL_STACK;
13
13
  /**
14
14
  *
15
15
  * @param {ExplicitBinaryBoundingVolumeHierarchy} bvh
16
+ * @param {number} root
16
17
  * @param {number[]} result
17
18
  * @param {number} result_offset
18
19
  * @param {number} origin_x
@@ -24,12 +25,11 @@ const stack = SCRATCH_UINT32_TRAVERSAL_STACK;
24
25
  * @returns {number}
25
26
  */
26
27
  export function bvh_query_leaves_ray(
27
- bvh,
28
+ bvh, root,
28
29
  result, result_offset,
29
30
  origin_x, origin_y, origin_z,
30
31
  direction_x, direction_y, direction_z
31
32
  ) {
32
- const root = bvh.root;
33
33
 
34
34
  if (root === NULL_NODE) {
35
35
  return 0;
@@ -0,0 +1,64 @@
1
+ import { ExplicitBinaryBoundingVolumeHierarchy } from "../ExplicitBinaryBoundingVolumeHierarchy.js";
2
+ import { bvh_query_leaves_ray } from "./bvh_query_leaves_ray.js";
3
+
4
+ /**
5
+ *
6
+ * @param {number[]} leaves
7
+ */
8
+ function makeBVH(...leaves) {
9
+
10
+ const bvh = new ExplicitBinaryBoundingVolumeHierarchy();
11
+
12
+ for (let i = 0; i < leaves.length; i++) {
13
+
14
+ const node = bvh.allocate_node();
15
+
16
+ bvh.node_set_aabb(node, leaves[i]);
17
+ bvh.node_set_user_data(node, i);
18
+
19
+ bvh.insert_leaf(node);
20
+ }
21
+
22
+ return bvh;
23
+ }
24
+
25
+ test("cast positive -X to +X, 1 node", () => {
26
+
27
+ const bvh = makeBVH(
28
+ [1, 3, 5, 7, 11, 13]
29
+ );
30
+
31
+ const result = [];
32
+
33
+ const match_count = bvh_query_leaves_ray(
34
+ bvh, bvh.root,
35
+ result, 0,
36
+ -1, 4, 6,
37
+ 1, 0, 0
38
+ );
39
+
40
+ expect(match_count).toBe(1);
41
+
42
+ expect(result[0]).toEqual(0);
43
+ });
44
+
45
+ test("cast positive -X to +X, 1/2 nodes", () => {
46
+
47
+ const bvh = makeBVH(
48
+ [-4, 3, 5, -2, 11, 13],
49
+ [1, 3, 5, 7, 11, 13]
50
+ );
51
+
52
+ const result = [];
53
+
54
+ const match_count = bvh_query_leaves_ray(
55
+ bvh, bvh.root,
56
+ result, 0,
57
+ -1, 4, 6,
58
+ 1, 0, 0
59
+ );
60
+
61
+ expect(match_count).toBe(1);
62
+
63
+ expect(result[0]).toEqual(1);
64
+ });
@@ -9,16 +9,15 @@ const stack = SCRATCH_UINT32_TRAVERSAL_STACK;
9
9
  * @param {ExplicitBinaryBoundingVolumeHierarchy} bvh
10
10
  * @param {number[]} result
11
11
  * @param {number} result_offset
12
+ * @param {number} root
12
13
  * @param {BVHQuery} query
13
14
  * @returns {number}
14
15
  */
15
16
  export function bvh_query_user_data_generic(
16
17
  result, result_offset,
17
- bvh, query
18
+ bvh,root, query
18
19
  ) {
19
20
 
20
- const root = bvh.root;
21
-
22
21
  if (root === NULL_NODE) {
23
22
  return 0;
24
23
  }
@@ -0,0 +1,41 @@
1
+ import { assert } from "../../../assert.js";
2
+
3
+ /**
4
+ *
5
+ * @param {number[]|ArrayLike<number>|Float32Array} result
6
+ * @param {BufferGeometry} geometry
7
+ */
8
+ export function aabb3_from_threejs_geometry(result, geometry) {
9
+ const gbb = geometry.boundingBox;
10
+
11
+ assert.notNull(gbb, 'boundingBox');
12
+
13
+ const min = gbb.min;
14
+ const max = gbb.max;
15
+
16
+ const x0 = min.x;
17
+ const y0 = min.y;
18
+ const z0 = min.z;
19
+
20
+ const x1 = max.x;
21
+ const y1 = max.y;
22
+ const z1 = max.z;
23
+
24
+ // validate bounds
25
+ assert.notNaN(x0, 'x0');
26
+ assert.notNaN(y0, 'y0');
27
+ assert.notNaN(z0, 'z0');
28
+
29
+ assert.notNaN(x1, 'x1');
30
+ assert.notNaN(y1, 'y1');
31
+ assert.notNaN(z1, 'z1');
32
+
33
+ // marshal into transform-accepted format
34
+ result[0] = x0;
35
+ result[1] = y0;
36
+ result[2] = z0;
37
+
38
+ result[3] = x1;
39
+ result[4] = y1;
40
+ result[5] = z1;
41
+ }
@@ -8,7 +8,8 @@ import { tm_kill_only_vert } from "../tm_kill_only_vert.js";
8
8
  import { tm_kill_only_edge } from "../tm_kill_only_edge.js";
9
9
  import { tm_kill_only_face } from "../tm_kill_only_face.js";
10
10
  import { query_edge_other_vertex } from "../query/query_edge_other_vertex.js";
11
- import { formatNumberByThousands } from "../../../../NumberFormat.js";
11
+
12
+ import { number_format_by_thousands } from "../../../../primitives/numbers/number_format_by_thousands.js";
12
13
 
13
14
  export class TopoMesh {
14
15
  constructor() {
@@ -643,7 +644,7 @@ export class TopoMesh {
643
644
  }
644
645
 
645
646
  toString() {
646
- return `TopoMesh{ vertices: ${formatNumberByThousands(this.vertices.length)}, edges: ${formatNumberByThousands(this.getEdges().size)}, faces: ${formatNumberByThousands(this.getFaces().size)} }`;
647
+ return `TopoMesh{ vertices: ${number_format_by_thousands(this.vertices.length)}, edges: ${number_format_by_thousands(this.getEdges().size)}, faces: ${number_format_by_thousands(this.getFaces().size)} }`;
647
648
  }
648
649
  }
649
650
 
@@ -5,8 +5,8 @@ import { BinaryTopology } from "./binary/BinaryTopology.js";
5
5
  import {
6
6
  compute_buffer_geometry_byte_size
7
7
  } from "../../../../../engine/graphics/geometry/buffered/compute_buffer_geometry_byte_size.js";
8
- import { prettyPrint } from "../../../../NumberFormat.js";
9
8
  import { TopoMesh } from "./TopoMesh.js";
9
+ import { number_pretty_print } from "../../../../primitives/numbers/number_pretty_print.js";
10
10
 
11
11
  function promise_ply(url) {
12
12
 
@@ -44,9 +44,9 @@ async function main() {
44
44
 
45
45
  console.log(mesh, lucy_geom);
46
46
 
47
- console.log(`source mesh size: ${prettyPrint(compute_buffer_geometry_byte_size(lucy_geom))} bytes`);
48
- console.log(`binary topology size: ${prettyPrint(mesh.byteSize)} bytes`);
49
- console.log(`object topology size: ${prettyPrint(topoMesh.byteSize)} bytes`);
47
+ console.log(`source mesh size: ${number_pretty_print(compute_buffer_geometry_byte_size(lucy_geom))} bytes`);
48
+ console.log(`binary topology size: ${number_pretty_print(mesh.byteSize)} bytes`);
49
+ console.log(`object topology size: ${number_pretty_print(topoMesh.byteSize)} bytes`);
50
50
 
51
51
  window.topo_obj = topoMesh;
52
52
  }
@@ -23,6 +23,8 @@ export default class Vector2 {
23
23
 
24
24
  _sub(x: number, y: number): void
25
25
 
26
+ lerpVectors(a: Vector2, b: Vector2, f: number): void
27
+
26
28
  abs(): void
27
29
 
28
30
  round(): void
@@ -31,6 +33,8 @@ export default class Vector2 {
31
33
 
32
34
  ceil(): void
33
35
 
36
+ rotate(angle: number): void
37
+
34
38
  copy(other: Vector2): void
35
39
 
36
40
  clone(): Vector2
@@ -39,8 +43,13 @@ export default class Vector2 {
39
43
 
40
44
  roughlyEquals(other: Vector2, tolerance?: number): boolean
41
45
 
46
+ hash(): number
47
+
42
48
  distanceTo(other: Vector2): number
43
49
 
50
+ manhattanDistanceTo(other: Vector2): number
51
+
52
+
44
53
  isZero(): boolean
45
54
 
46
55
  readFromArray(array: ArrayLike<number>, offset?: number): void
@@ -450,7 +450,10 @@ class Vector2 {
450
450
  * @param {number} fraction
451
451
  */
452
452
  lerpVectors(a, b, fraction) {
453
- v2Lerp(this, a, b, fraction);
453
+ const x = lerp(a.x, b.x, fraction);
454
+ const y = lerp(a.y, b.y, fraction);
455
+
456
+ this.set(x, y);
454
457
  }
455
458
 
456
459
  /**
@@ -538,7 +541,7 @@ class Vector2 {
538
541
  *
539
542
  * @returns {number}
540
543
  */
541
- hashCode() {
544
+ hash() {
542
545
  const x = Math.sin(this.x) * 1367130550;
543
546
  const y = Math.sin(this.y) * 1367130550;
544
547
 
@@ -550,7 +553,7 @@ class Vector2 {
550
553
  }
551
554
 
552
555
  /**
553
- *
556
+ * Rotation is counter-clockwise
554
557
  * @param {number} angle in radians
555
558
  */
556
559
  rotate(angle) {
@@ -558,7 +561,7 @@ class Vector2 {
558
561
  const cos = Math.cos(angle);
559
562
 
560
563
  const x = this.x * cos - this.y * sin
561
- const y = this.x * sin - this.y * cos;
564
+ const y = this.x * sin + this.y * cos;
562
565
 
563
566
  this.set(x, y);
564
567
  }
@@ -597,7 +600,7 @@ class Vector2 {
597
600
  * @return {boolean}
598
601
  */
599
602
  roughlyEquals(other, tolerance) {
600
- return this._roughlyEquals(other.x, other.y, tolerance);
603
+ return this._roughlyEquals(other.x, other.y, tolerance);
601
604
  }
602
605
 
603
606
  /**
@@ -677,23 +680,6 @@ Vector2.one = Object.freeze(new Vector2(1, 1));
677
680
  * @type {boolean}
678
681
  */
679
682
  Vector2.prototype.isVector2 = true;
680
-
681
- /**
682
- *
683
- * @param {Vector2} result
684
- * @param {Vector2} a
685
- * @param {Vector2} b
686
- * @param {number} fraction
687
- */
688
- function v2Lerp(result, a, b, fraction) {
689
-
690
- const x = lerp(a.x, b.x, fraction);
691
- const y = lerp(a.y, b.y, fraction);
692
-
693
- result.set(x, y);
694
- }
695
-
696
-
697
683
  /**
698
684
  *
699
685
  * @param {number} x0
@@ -8,6 +8,21 @@ test("setting x and y via constructor", () => {
8
8
  expect(v.y).toBe(13);
9
9
  });
10
10
 
11
+ test("array-style accessors", () => {
12
+
13
+ const v = new Vector2();
14
+
15
+ v[0] = 3;
16
+ v[1] = -7;
17
+
18
+ expect(v[0]).toEqual(3);
19
+ expect(v.x).toEqual(3);
20
+
21
+ expect(v[1]).toEqual(-7);
22
+ expect(v.y).toEqual(-7);
23
+
24
+ });
25
+
11
26
  test('add works', () => {
12
27
  const a = new Vector2(1, 3);
13
28
  const b = new Vector2(5, 7);
@@ -140,3 +155,141 @@ test("onChange is dispatched when y changes via set", () => {
140
155
 
141
156
  expect(changeHandler).toHaveBeenLastCalledWith(2, 3, 1, 3);
142
157
  });
158
+
159
+ test("rotate", () => {
160
+
161
+ const v = new Vector2(0, 0);
162
+
163
+ v.rotate(0);
164
+
165
+ expect(v.x).toBeCloseTo(0);
166
+ expect(v.y).toBeCloseTo(0);
167
+
168
+ v.set(1, 0);
169
+
170
+ v.rotate(0);
171
+
172
+ expect(v.x).toBeCloseTo(1);
173
+ expect(v.y).toBeCloseTo(0);
174
+
175
+ v.set(0, 1);
176
+
177
+ v.rotate(0);
178
+
179
+ expect(v.x).toBeCloseTo(0);
180
+ expect(v.y).toBeCloseTo(1);
181
+
182
+ v.set(1, 0);
183
+
184
+ v.rotate(Math.PI);
185
+
186
+ expect(v.x).toBeCloseTo(-1);
187
+ expect(v.y).toBeCloseTo(0);
188
+
189
+ v.set(-1, 0);
190
+
191
+ v.rotate(Math.PI);
192
+
193
+ expect(v.x).toBeCloseTo(1);
194
+ expect(v.y).toBeCloseTo(0);
195
+
196
+ v.set(0, 1);
197
+
198
+ v.rotate(Math.PI);
199
+
200
+ expect(v.x).toBeCloseTo(0);
201
+ expect(v.y).toBeCloseTo(-1);
202
+
203
+ v.set(0, -1);
204
+
205
+ v.rotate(Math.PI);
206
+
207
+ expect(v.x).toBeCloseTo(0);
208
+ expect(v.y).toBeCloseTo(1);
209
+
210
+ v.set(1, 1);
211
+
212
+ v.rotate(Math.PI * 0.5);
213
+
214
+ expect(v.x).toBeCloseTo(-1);
215
+ expect(v.y).toBeCloseTo(1);
216
+ });
217
+
218
+ test("hash", () => {
219
+
220
+ function validate(x, y) {
221
+
222
+ const v = new Vector2(x, y);
223
+
224
+ const hash = v.hash();
225
+
226
+ expect(hash).toEqual(v.hash()); // stability
227
+ expect(typeof hash).toBe("number");
228
+ expect(Number.isInteger(hash)).toBe(true);
229
+
230
+ }
231
+
232
+ validate(0, 0);
233
+ validate(0, 1);
234
+ validate(1, 0);
235
+ validate(1, 1);
236
+
237
+ validate(0, -1);
238
+ validate(-1, 0);
239
+ validate(-1, -1);
240
+ });
241
+
242
+ test("normalize", () => {
243
+
244
+ const v = new Vector2(1, 1);
245
+
246
+ v.normalize();
247
+
248
+ const s = 1 / Math.SQRT2;
249
+
250
+ expect(v.x).toBeCloseTo(s);
251
+ expect(v.y).toBeCloseTo(s);
252
+
253
+ v.set(-1, -1);
254
+
255
+ v.normalize();
256
+
257
+ expect(v.x).toBeCloseTo(-s);
258
+ expect(v.y).toBeCloseTo(-s);
259
+
260
+ });
261
+
262
+ test("length", () => {
263
+
264
+ expect(new Vector2(1, 0).length()).toBeCloseTo(1);
265
+ expect(new Vector2(0, 1).length()).toBeCloseTo(1);
266
+
267
+ expect(new Vector2(1, 1).length()).toBeCloseTo(Math.SQRT2);
268
+
269
+ expect(new Vector2(-1, 1).length()).toBeCloseTo(Math.SQRT2);
270
+
271
+ expect(new Vector2(1, -1).length()).toBeCloseTo(Math.SQRT2);
272
+
273
+ expect(new Vector2(-1, -1).length()).toBeCloseTo(Math.SQRT2);
274
+ });
275
+
276
+
277
+ test("manhattanDistanceTo", () => {
278
+ const a = new Vector2(1, 3);
279
+ const b = new Vector2(5, 11);
280
+
281
+ expect(a.manhattanDistanceTo(b)).toEqual(12)
282
+ });
283
+
284
+ test("lerpVectors", () => {
285
+
286
+
287
+ const a = new Vector2(-1, 3);
288
+ const b = new Vector2(5, -11);
289
+
290
+ a.lerpVectors(a, b, 0.1);
291
+
292
+ expect(a.x).toBeCloseTo(-1 * 0.9 + 5 * 0.1);
293
+ expect(a.y).toBeCloseTo(3 * 0.9 - 11 * 0.1);
294
+
295
+ });
@@ -15,9 +15,7 @@ export class ModuleRegistry {
15
15
 
16
16
  constructor() {
17
17
 
18
- const self = this;
19
-
20
- this.proxy = new Proxy({}, {
18
+ this.proxy = new Proxy(this, {
21
19
  /**
22
20
  *
23
21
  * @param target
@@ -26,7 +24,7 @@ export class ModuleRegistry {
26
24
  * @returns {Class}
27
25
  */
28
26
  get(target, p, receiver) {
29
- const module = self.get(p);
27
+ const module = target.get(p);
30
28
 
31
29
  if (module === undefined) {
32
30
  throw new Error(`Module '${p}' not found in the registry`);
@@ -0,0 +1,31 @@
1
+ import { ModuleRegistry } from "./ModuleRegistry.js";
2
+
3
+ test("constructor does not throw", () => {
4
+
5
+ expect(() => new ModuleRegistry()).not.toThrow();
6
+
7
+ });
8
+
9
+ test("add/retrieve", () => {
10
+
11
+ const registry = new ModuleRegistry();
12
+
13
+ const module = {};
14
+
15
+ registry.add("x", module);
16
+
17
+ expect(registry.get("x")).toBe(module);
18
+
19
+ });
20
+
21
+ test("retrieve by proxy", () => {
22
+
23
+ const registry = new ModuleRegistry();
24
+
25
+ const module = {};
26
+
27
+ registry.add("x", module);
28
+
29
+ expect(registry.proxy.x).toBe(module);
30
+
31
+ });