dacha 0.17.2 → 0.18.0-alpha.1

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 (132) hide show
  1. package/build/contrib/components/collider/index.d.ts +17 -4
  2. package/build/contrib/components/collider/index.js +30 -2
  3. package/build/contrib/components/rigid-body/index.d.ts +29 -17
  4. package/build/contrib/components/rigid-body/index.js +64 -21
  5. package/build/contrib/components/shape/index.d.ts +17 -2
  6. package/build/contrib/components/shape/index.js +16 -0
  7. package/build/contrib/events/index.d.ts +10 -75
  8. package/build/contrib/events/index.js +0 -36
  9. package/build/contrib/systems/camera-system/{service.d.ts → api.d.ts} +4 -4
  10. package/build/contrib/systems/camera-system/{service.js → api.js} +2 -2
  11. package/build/contrib/systems/camera-system/index.d.ts +1 -1
  12. package/build/contrib/systems/camera-system/index.js +1 -1
  13. package/build/contrib/systems/camera-system/system.d.ts +1 -1
  14. package/build/contrib/systems/camera-system/system.js +5 -4
  15. package/build/contrib/systems/index.d.ts +3 -3
  16. package/build/contrib/systems/index.js +3 -3
  17. package/build/contrib/systems/mouse-input-system/subsystems/coordinates-projector/index.d.ts +0 -1
  18. package/build/contrib/systems/mouse-input-system/subsystems/coordinates-projector/index.js +4 -5
  19. package/build/contrib/systems/physics-system/api.d.ts +58 -0
  20. package/build/contrib/systems/physics-system/api.js +67 -0
  21. package/build/contrib/systems/physics-system/index.d.ts +2 -21
  22. package/build/contrib/systems/physics-system/index.js +2 -40
  23. package/build/contrib/systems/physics-system/physics-system.d.ts +24 -0
  24. package/build/contrib/systems/physics-system/physics-system.js +47 -0
  25. package/build/contrib/systems/physics-system/subsystems/collision-broadcast/collision.d.ts +5 -3
  26. package/build/contrib/systems/physics-system/subsystems/collision-broadcast/collision.js +7 -5
  27. package/build/contrib/systems/physics-system/subsystems/collision-broadcast/index.d.ts +4 -6
  28. package/build/contrib/systems/physics-system/subsystems/collision-broadcast/index.js +20 -17
  29. package/build/contrib/systems/physics-system/subsystems/collision-detection/aabb-builders/build-circle-aabb.js +1 -2
  30. package/build/contrib/systems/physics-system/subsystems/collision-detection/aabb-builders/build-point-aabb.d.ts +2 -0
  31. package/build/contrib/systems/physics-system/subsystems/collision-detection/aabb-builders/build-point-aabb.js +7 -0
  32. package/build/contrib/systems/physics-system/subsystems/collision-detection/aabb-builders/build-ray-aabb.d.ts +2 -0
  33. package/build/contrib/systems/physics-system/subsystems/collision-detection/aabb-builders/build-ray-aabb.js +9 -0
  34. package/build/contrib/systems/physics-system/subsystems/collision-detection/aabb-builders/build-segment-aabb.d.ts +2 -0
  35. package/build/contrib/systems/physics-system/subsystems/collision-detection/aabb-builders/build-segment-aabb.js +14 -0
  36. package/build/contrib/systems/physics-system/subsystems/collision-detection/aabb-builders/index.js +6 -0
  37. package/build/contrib/systems/physics-system/subsystems/collision-detection/geometry-builders/build-box-geometry.d.ts +3 -1
  38. package/build/contrib/systems/physics-system/subsystems/collision-detection/geometry-builders/build-box-geometry.js +52 -16
  39. package/build/contrib/systems/physics-system/subsystems/collision-detection/geometry-builders/build-circle-geometry.d.ts +3 -1
  40. package/build/contrib/systems/physics-system/subsystems/collision-detection/geometry-builders/build-circle-geometry.js +32 -7
  41. package/build/contrib/systems/physics-system/subsystems/collision-detection/geometry-builders/build-point-geometry.d.ts +3 -0
  42. package/build/contrib/systems/physics-system/subsystems/collision-detection/geometry-builders/build-point-geometry.js +5 -0
  43. package/build/contrib/systems/physics-system/subsystems/collision-detection/geometry-builders/build-ray-geometry.d.ts +3 -0
  44. package/build/contrib/systems/physics-system/subsystems/collision-detection/geometry-builders/build-ray-geometry.js +7 -0
  45. package/build/contrib/systems/physics-system/subsystems/collision-detection/geometry-builders/build-segment-geometry.d.ts +3 -0
  46. package/build/contrib/systems/physics-system/subsystems/collision-detection/geometry-builders/build-segment-geometry.js +33 -0
  47. package/build/contrib/systems/physics-system/subsystems/collision-detection/geometry-builders/index.d.ts +12 -1
  48. package/build/contrib/systems/physics-system/subsystems/collision-detection/geometry-builders/index.js +6 -0
  49. package/build/contrib/systems/physics-system/subsystems/collision-detection/index.d.ts +21 -9
  50. package/build/contrib/systems/physics-system/subsystems/collision-detection/index.js +177 -92
  51. package/build/contrib/systems/physics-system/subsystems/collision-detection/intersection-checkers/box-box/check-boxes-intersection.d.ts +10 -0
  52. package/build/contrib/systems/physics-system/subsystems/collision-detection/intersection-checkers/box-box/check-boxes-intersection.js +36 -0
  53. package/build/contrib/systems/physics-system/subsystems/collision-detection/intersection-checkers/box-box/utils.d.ts +17 -0
  54. package/build/contrib/systems/physics-system/subsystems/collision-detection/intersection-checkers/box-box/utils.js +126 -0
  55. package/build/contrib/systems/physics-system/subsystems/collision-detection/intersection-checkers/box-circle/check-box-and-circle-intersection.d.ts +9 -0
  56. package/build/contrib/systems/physics-system/subsystems/collision-detection/intersection-checkers/box-circle/check-box-and-circle-intersection.js +46 -0
  57. package/build/contrib/systems/physics-system/subsystems/collision-detection/intersection-checkers/box-segment/check-box-and-segment-intersection.d.ts +10 -0
  58. package/build/contrib/systems/physics-system/subsystems/collision-detection/intersection-checkers/box-segment/check-box-and-segment-intersection.js +28 -0
  59. package/build/contrib/systems/physics-system/subsystems/collision-detection/intersection-checkers/box-segment/utils.d.ts +19 -0
  60. package/build/contrib/systems/physics-system/subsystems/collision-detection/intersection-checkers/box-segment/utils.js +76 -0
  61. package/build/contrib/systems/physics-system/subsystems/collision-detection/intersection-checkers/circle-circle/check-circles-intersection.d.ts +12 -0
  62. package/build/contrib/systems/physics-system/subsystems/collision-detection/intersection-checkers/circle-circle/check-circles-intersection.js +47 -0
  63. package/build/contrib/systems/physics-system/subsystems/collision-detection/intersection-checkers/circle-segment/check-circle-and-segment-intersection.d.ts +10 -0
  64. package/build/contrib/systems/physics-system/subsystems/collision-detection/intersection-checkers/circle-segment/check-circle-and-segment-intersection.js +33 -0
  65. package/build/contrib/systems/physics-system/subsystems/collision-detection/intersection-checkers/index.d.ts +2 -2
  66. package/build/contrib/systems/physics-system/subsystems/collision-detection/intersection-checkers/index.js +27 -3
  67. package/build/contrib/systems/physics-system/subsystems/collision-detection/intersection-checkers/point-box/check-point-and-box-intersection.d.ts +9 -0
  68. package/build/contrib/systems/physics-system/subsystems/collision-detection/intersection-checkers/point-box/check-point-and-box-intersection.js +36 -0
  69. package/build/contrib/systems/physics-system/subsystems/collision-detection/intersection-checkers/point-circle/check-point-and-circle-intersection.d.ts +9 -0
  70. package/build/contrib/systems/physics-system/subsystems/collision-detection/intersection-checkers/point-circle/check-point-and-circle-intersection.js +33 -0
  71. package/build/contrib/systems/physics-system/subsystems/collision-detection/intersection-checkers/point-segment/check-point-and-segment-intersection.d.ts +9 -0
  72. package/build/contrib/systems/physics-system/subsystems/collision-detection/intersection-checkers/point-segment/check-point-and-segment-intersection.js +26 -0
  73. package/build/contrib/systems/physics-system/subsystems/collision-detection/intersection-checkers/ray-box/check-ray-and-box-intersection.d.ts +11 -0
  74. package/build/contrib/systems/physics-system/subsystems/collision-detection/intersection-checkers/ray-box/check-ray-and-box-intersection.js +69 -0
  75. package/build/contrib/systems/physics-system/subsystems/collision-detection/intersection-checkers/ray-circle/check-ray-and-circle-intersection.d.ts +10 -0
  76. package/build/contrib/systems/physics-system/subsystems/collision-detection/intersection-checkers/ray-circle/check-ray-and-circle-intersection.js +45 -0
  77. package/build/contrib/systems/physics-system/subsystems/collision-detection/intersection-checkers/ray-segment/check-ray-and-segment-intersection.d.ts +16 -0
  78. package/build/contrib/systems/physics-system/subsystems/collision-detection/intersection-checkers/ray-segment/check-ray-and-segment-intersection.js +51 -0
  79. package/build/contrib/systems/physics-system/subsystems/collision-detection/intersection-checkers/ray-segment/utils.d.ts +2 -0
  80. package/build/contrib/systems/physics-system/subsystems/collision-detection/intersection-checkers/ray-segment/utils.js +4 -0
  81. package/build/contrib/systems/physics-system/subsystems/collision-detection/intersection-checkers/tests/helpers.d.ts +20 -0
  82. package/build/contrib/systems/physics-system/subsystems/collision-detection/intersection-checkers/tests/helpers.js +69 -0
  83. package/build/contrib/systems/physics-system/subsystems/collision-detection/intersection-checkers/utils.d.ts +9 -0
  84. package/build/contrib/systems/physics-system/subsystems/collision-detection/intersection-checkers/utils.js +23 -0
  85. package/build/contrib/systems/physics-system/subsystems/collision-detection/query-utils.d.ts +10 -0
  86. package/build/contrib/systems/physics-system/subsystems/collision-detection/query-utils.js +63 -0
  87. package/build/contrib/systems/physics-system/subsystems/collision-detection/reorientation-checkers/check-collider.js +17 -8
  88. package/build/contrib/systems/physics-system/subsystems/collision-detection/types.d.ts +41 -11
  89. package/build/contrib/systems/physics-system/subsystems/collision-detection/types.js +0 -3
  90. package/build/contrib/systems/physics-system/subsystems/constraint-solver/index.d.ts +7 -10
  91. package/build/contrib/systems/physics-system/subsystems/constraint-solver/index.js +117 -79
  92. package/build/contrib/systems/physics-system/subsystems/index.d.ts +0 -1
  93. package/build/contrib/systems/physics-system/subsystems/index.js +0 -1
  94. package/build/contrib/systems/physics-system/subsystems/physics/index.d.ts +3 -9
  95. package/build/contrib/systems/physics-system/subsystems/physics/index.js +57 -93
  96. package/build/contrib/systems/physics-system/types.d.ts +37 -0
  97. package/build/contrib/systems/renderer/actor-render-tree.js +1 -2
  98. package/build/contrib/systems/renderer/{service → api}/index.d.ts +6 -6
  99. package/build/contrib/systems/renderer/{service → api}/index.js +14 -16
  100. package/build/contrib/systems/renderer/api/utils.d.ts +4 -0
  101. package/build/contrib/systems/renderer/{service → api}/utils.js +5 -0
  102. package/build/contrib/systems/renderer/builders/shape-builder/index.js +9 -1
  103. package/build/contrib/systems/renderer/builders/shape-builder/utils.js +16 -0
  104. package/build/contrib/systems/renderer/index.d.ts +1 -1
  105. package/build/contrib/systems/renderer/index.js +1 -1
  106. package/build/contrib/systems/renderer/renderer.d.ts +2 -1
  107. package/build/contrib/systems/renderer/renderer.js +9 -7
  108. package/build/engine/actor/actor-creator.js +6 -4
  109. package/build/engine/math-lib/math/ops.d.ts +1 -2
  110. package/build/engine/math-lib/math/ops.js +3 -3
  111. package/build/engine/math-lib/vector/ops.d.ts +18 -3
  112. package/build/engine/math-lib/vector/ops.js +28 -5
  113. package/build/engine/math-lib/vector/vector2.d.ts +22 -7
  114. package/build/engine/math-lib/vector/vector2.js +29 -5
  115. package/build/engine/template/template-collection.js +1 -1
  116. package/build/engine/world/index.d.ts +4 -24
  117. package/build/engine/world/index.js +5 -33
  118. package/build/engine/world/system-api-registry.d.ts +17 -0
  119. package/build/engine/world/system-api-registry.js +34 -0
  120. package/build/events/index.d.ts +2 -2
  121. package/build/events/index.js +1 -1
  122. package/build/types/global.d.ts +4 -0
  123. package/package.json +4 -1
  124. package/build/contrib/systems/physics-system/subsystems/collision-detection/intersection-checkers/check-box-and-circle-intersection.d.ts +0 -16
  125. package/build/contrib/systems/physics-system/subsystems/collision-detection/intersection-checkers/check-box-and-circle-intersection.js +0 -80
  126. package/build/contrib/systems/physics-system/subsystems/collision-detection/intersection-checkers/check-boxes-intersection.d.ts +0 -6
  127. package/build/contrib/systems/physics-system/subsystems/collision-detection/intersection-checkers/check-boxes-intersection.js +0 -72
  128. package/build/contrib/systems/physics-system/subsystems/collision-detection/intersection-checkers/check-circles-intersection.d.ts +0 -11
  129. package/build/contrib/systems/physics-system/subsystems/collision-detection/intersection-checkers/check-circles-intersection.js +0 -39
  130. package/build/contrib/systems/physics-system/subsystems/collision-solver/index.d.ts +0 -10
  131. package/build/contrib/systems/physics-system/subsystems/collision-solver/index.js +0 -50
  132. package/build/contrib/systems/renderer/service/utils.d.ts +0 -3
@@ -1,13 +1,38 @@
1
- export const buildCircleGeometry = (collider, transform) => {
2
- const { world: { position, scale }, } = transform;
3
- const { centerX, centerY, radius } = collider;
1
+ export function buildCircleGeometry(colliderOrOverlap, transform) {
2
+ let centerX;
3
+ let centerY;
4
+ let radius;
5
+ let positionX;
6
+ let positionY;
7
+ let scaleX;
8
+ let scaleY;
9
+ if (transform !== undefined) {
10
+ const collider = colliderOrOverlap;
11
+ centerX = collider.centerX;
12
+ centerY = collider.centerY;
13
+ radius = collider.radius;
14
+ positionX = transform.world.position.x;
15
+ positionY = transform.world.position.y;
16
+ scaleX = transform.world.scale.x;
17
+ scaleY = transform.world.scale.y;
18
+ }
19
+ else {
20
+ const overlap = colliderOrOverlap;
21
+ centerX = 0;
22
+ centerY = 0;
23
+ radius = overlap.radius;
24
+ positionX = overlap.center.x;
25
+ positionY = overlap.center.y;
26
+ scaleX = 1;
27
+ scaleY = 1;
28
+ }
4
29
  const center = {
5
- x: centerX + position.x,
6
- y: centerY + position.y,
30
+ x: centerX + positionX,
31
+ y: centerY + positionY,
7
32
  };
8
- const scaledRadius = radius * Math.max(scale.x, scale.y);
33
+ const scaledRadius = radius * Math.max(scaleX, scaleY);
9
34
  return {
10
35
  center,
11
36
  radius: scaledRadius,
12
37
  };
13
- };
38
+ }
@@ -0,0 +1,3 @@
1
+ import type { PointGeometry } from '../types';
2
+ import type { OverlapPointParams } from '../../../types';
3
+ export declare function buildPointGeometry(overlap: OverlapPointParams): PointGeometry;
@@ -0,0 +1,5 @@
1
+ export function buildPointGeometry(overlap) {
2
+ return {
3
+ center: overlap.point,
4
+ };
5
+ }
@@ -0,0 +1,3 @@
1
+ import type { RayGeometry } from '../types';
2
+ import type { RaycastParams } from '../../../types';
3
+ export declare function buildRayGeometry(overlap: RaycastParams): RayGeometry;
@@ -0,0 +1,7 @@
1
+ export function buildRayGeometry(overlap) {
2
+ return {
3
+ origin: overlap.origin,
4
+ direction: overlap.direction.normalize(),
5
+ maxDistance: overlap.maxDistance,
6
+ };
7
+ }
@@ -0,0 +1,3 @@
1
+ import type { Collider, Transform } from '../../../../../components';
2
+ import type { SegmentGeometry } from '../types';
3
+ export declare function buildSegmentGeometry(collider: Collider, transform: Transform): SegmentGeometry;
@@ -0,0 +1,33 @@
1
+ import { VectorOps } from '../../../../../../engine/math-lib';
2
+ export function buildSegmentGeometry(collider, transform) {
3
+ const centerX = collider.centerX + transform.world.position.x;
4
+ const centerY = collider.centerY + transform.world.position.y;
5
+ const point1X = collider.point1?.x ?? 0;
6
+ const point1Y = collider.point1?.y ?? 0;
7
+ const point2X = collider.point2?.x ?? 0;
8
+ const point2Y = collider.point2?.y ?? 0;
9
+ const rotation = transform.world.rotation;
10
+ const scaleX = transform.world.scale.x;
11
+ const scaleY = transform.world.scale.y;
12
+ const cos = Math.cos(rotation);
13
+ const sin = Math.sin(rotation);
14
+ const buildPoint = (x, y) => {
15
+ const scaledX = x * scaleX;
16
+ const scaledY = y * scaleY;
17
+ return {
18
+ x: scaledX * cos - scaledY * sin + centerX,
19
+ y: scaledX * sin + scaledY * cos + centerY,
20
+ };
21
+ };
22
+ const point1 = buildPoint(point1X, point1Y);
23
+ const point2 = buildPoint(point2X, point2Y);
24
+ return {
25
+ center: {
26
+ x: (point1.x + point2.x) / 2,
27
+ y: (point1.y + point2.y) / 2,
28
+ },
29
+ point1,
30
+ point2,
31
+ normal: VectorOps.getNormal(point1.x, point2.x, point1.y, point2.y),
32
+ };
33
+ }
@@ -1,4 +1,15 @@
1
1
  import type { Collider, Transform } from '../../../../../components';
2
2
  import type { Geometry } from '../types';
3
+ import { buildBoxGeometry } from './build-box-geometry';
4
+ import { buildCircleGeometry } from './build-circle-geometry';
5
+ import { buildPointGeometry } from './build-point-geometry';
6
+ import { buildRayGeometry } from './build-ray-geometry';
7
+ import { buildSegmentGeometry } from './build-segment-geometry';
3
8
  export type BuildGeometryFn = (collider: Collider, transform: Transform) => Geometry;
4
- export declare const geometryBuilders: Record<string, BuildGeometryFn>;
9
+ export declare const geometryBuilders: {
10
+ box: typeof buildBoxGeometry;
11
+ circle: typeof buildCircleGeometry;
12
+ segment: typeof buildSegmentGeometry;
13
+ point: typeof buildPointGeometry;
14
+ ray: typeof buildRayGeometry;
15
+ };
@@ -1,6 +1,12 @@
1
1
  import { buildBoxGeometry } from './build-box-geometry';
2
2
  import { buildCircleGeometry } from './build-circle-geometry';
3
+ import { buildPointGeometry } from './build-point-geometry';
4
+ import { buildRayGeometry } from './build-ray-geometry';
5
+ import { buildSegmentGeometry } from './build-segment-geometry';
3
6
  export const geometryBuilders = {
4
7
  box: buildBoxGeometry,
5
8
  circle: buildCircleGeometry,
9
+ segment: buildSegmentGeometry,
10
+ point: buildPointGeometry,
11
+ ray: buildRayGeometry,
6
12
  };
@@ -1,28 +1,40 @@
1
1
  import type { SceneSystemOptions } from '../../../../../engine/system';
2
+ import type { Actor } from '../../../../../engine/actor';
3
+ import type { RaycastParams, RaycastHit, OverlapPointParams, OverlapCircleParams, OverlapBoxParams } from '../../types';
4
+ import type { Contact } from './types';
2
5
  export declare class CollisionDetectionSubsystem {
3
6
  private actorQuery;
4
- private scene;
5
7
  private axis;
6
- private entriesMap;
7
- private collisionPairs;
8
- private entriesToDelete;
8
+ private proxiesByActorId;
9
+ private proxyPairs;
10
+ private contacts;
11
+ private actorIdsToDelete;
12
+ private collisionMatrix;
13
+ private queryCandidates;
9
14
  constructor(options: SceneSystemOptions);
10
15
  destroy(): void;
16
+ raycast(params: RaycastParams): RaycastHit | null;
17
+ raycastAll(params: RaycastParams): RaycastHit[];
18
+ overlapPoint(params: OverlapPointParams): Actor[];
19
+ overlapCircle(params: OverlapCircleParams): Actor[];
20
+ overlapBox(params: OverlapBoxParams): Actor[];
11
21
  private handleActorAdd;
12
22
  private handleActorRemove;
13
23
  private checkOnReorientation;
14
24
  private getOrientationData;
15
- private addCollisionEntry;
16
- private updateCollisionEntry;
25
+ private addProxy;
26
+ private updateProxy;
17
27
  private addToSortedList;
18
28
  private updateSortedList;
19
29
  private clearSortedList;
20
30
  private getAxes;
21
31
  private areStaticBodies;
22
32
  private testAABB;
33
+ private testCollisionLayers;
34
+ private sweepAndPruneQuery;
23
35
  private sweepAndPrune;
24
36
  private checkOnIntersection;
25
- private sendCollisionEvent;
26
- private clearDeletedEntries;
27
- update(): void;
37
+ private storeContact;
38
+ private clearDeletedProxies;
39
+ update(): Contact[];
28
40
  }
@@ -1,26 +1,28 @@
1
1
  import { ActorQuery } from '../../../../../engine/actor';
2
2
  import { Transform, Collider, RigidBody } from '../../../../components';
3
3
  import { AddActor, RemoveActor } from '../../../../../engine/events';
4
- import { Collision } from '../../../../events';
5
4
  import { insertionSort } from '../../../../../engine/data-lib';
6
5
  import { geometryBuilders } from './geometry-builders';
7
6
  import { aabbBuilders } from './aabb-builders';
8
7
  import { intersectionCheckers } from './intersection-checkers';
9
8
  import { DispersionCalculator } from './dispersion-calculator';
10
9
  import { checkTransform, checkCollider } from './reorientation-checkers';
10
+ import { buildQueryProxy, raycast, raycastAll, overlap } from './query-utils';
11
11
  export class CollisionDetectionSubsystem {
12
12
  actorQuery;
13
- scene;
14
13
  axis;
15
- entriesMap;
16
- collisionPairs;
17
- entriesToDelete;
14
+ proxiesByActorId;
15
+ proxyPairs;
16
+ contacts;
17
+ actorIdsToDelete;
18
+ collisionMatrix;
19
+ queryCandidates;
18
20
  constructor(options) {
21
+ const settings = options.globalOptions.physics;
19
22
  this.actorQuery = new ActorQuery({
20
23
  scene: options.scene,
21
24
  filter: [Collider, Transform],
22
25
  });
23
- this.scene = options.scene;
24
26
  this.axis = {
25
27
  x: {
26
28
  sortedList: [],
@@ -31,34 +33,61 @@ export class CollisionDetectionSubsystem {
31
33
  dispersionCalculator: new DispersionCalculator('y'),
32
34
  },
33
35
  };
34
- this.entriesMap = new Map();
35
- this.collisionPairs = [];
36
- this.entriesToDelete = new Set();
37
- this.actorQuery
38
- .getActors()
39
- .forEach((actor) => this.addCollisionEntry(actor));
36
+ this.proxiesByActorId = new Map();
37
+ this.proxyPairs = [];
38
+ this.contacts = [];
39
+ this.actorIdsToDelete = new Set();
40
+ this.collisionMatrix = settings?.collisionMatrix ?? {};
41
+ this.queryCandidates = [];
42
+ this.actorQuery.getActors().forEach((actor) => this.addProxy(actor));
40
43
  this.actorQuery.addEventListener(AddActor, this.handleActorAdd);
41
44
  this.actorQuery.addEventListener(RemoveActor, this.handleActorRemove);
42
45
  }
43
46
  destroy() {
44
47
  this.actorQuery.removeEventListener(AddActor, this.handleActorAdd);
45
48
  this.actorQuery.removeEventListener(RemoveActor, this.handleActorRemove);
49
+ this.actorQuery.destroy();
50
+ }
51
+ raycast(params) {
52
+ const queryProxy = buildQueryProxy('ray', params);
53
+ this.sweepAndPruneQuery(queryProxy);
54
+ return raycast(queryProxy, this.queryCandidates);
55
+ }
56
+ raycastAll(params) {
57
+ const queryProxy = buildQueryProxy('ray', params);
58
+ this.sweepAndPruneQuery(queryProxy);
59
+ return raycastAll(queryProxy, this.queryCandidates);
60
+ }
61
+ overlapPoint(params) {
62
+ const queryProxy = buildQueryProxy('point', params);
63
+ this.sweepAndPruneQuery(queryProxy);
64
+ return overlap('point', queryProxy, this.queryCandidates);
65
+ }
66
+ overlapCircle(params) {
67
+ const queryProxy = buildQueryProxy('circle', params);
68
+ this.sweepAndPruneQuery(queryProxy);
69
+ return overlap('circle', queryProxy, this.queryCandidates);
70
+ }
71
+ overlapBox(params) {
72
+ const queryProxy = buildQueryProxy('box', params);
73
+ this.sweepAndPruneQuery(queryProxy);
74
+ return overlap('box', queryProxy, this.queryCandidates);
46
75
  }
47
76
  handleActorAdd = (event) => {
48
- this.addCollisionEntry(event.actor);
77
+ this.addProxy(event.actor);
49
78
  };
50
79
  handleActorRemove = (event) => {
51
- this.entriesToDelete.add(event.actor.id);
80
+ this.actorIdsToDelete.add(event.actor.id);
52
81
  };
53
82
  checkOnReorientation(actor) {
54
- const entry = this.entriesMap.get(actor.id);
55
- if (!entry) {
83
+ const proxy = this.proxiesByActorId.get(actor.id);
84
+ if (!proxy) {
56
85
  return true;
57
86
  }
58
87
  const transform = actor.getComponent(Transform);
59
88
  const collider = actor.getComponent(Collider);
60
- const transformOld = entry.orientationData.transform;
61
- const colliderOld = entry.orientationData.collider;
89
+ const transformOld = proxy.orientationData.transform;
90
+ const colliderOld = proxy.orientationData.collider;
62
91
  return (checkTransform(transform, transformOld) ||
63
92
  checkCollider(collider, colliderOld));
64
93
  }
@@ -75,160 +104,216 @@ export class CollisionDetectionSubsystem {
75
104
  },
76
105
  collider: {
77
106
  type: collider.type,
107
+ layer: collider.layer,
78
108
  centerX: collider.centerX,
79
109
  centerY: collider.centerY,
80
110
  sizeX: collider.sizeX,
81
111
  sizeY: collider.sizeY,
82
112
  radius: collider.radius,
113
+ point1: collider.point1 ? { ...collider.point1 } : undefined,
114
+ point2: collider.point2 ? { ...collider.point2 } : undefined,
83
115
  },
84
116
  };
85
117
  }
86
- addCollisionEntry(actor) {
118
+ addProxy(actor) {
87
119
  const transform = actor.getComponent(Transform);
88
120
  const collider = actor.getComponent(Collider);
89
121
  const geometry = geometryBuilders[collider.type](collider, transform);
90
122
  const aabb = aabbBuilders[collider.type](geometry);
91
- const entry = {
123
+ const proxy = {
92
124
  actor,
93
125
  aabb,
94
126
  geometry,
95
127
  orientationData: this.getOrientationData(actor),
128
+ layer: collider.layer,
96
129
  };
97
130
  this.axis.x.dispersionCalculator.addToSample(aabb);
98
- this.addToSortedList(entry, 'x');
131
+ this.addToSortedList(proxy, 'x');
99
132
  this.axis.y.dispersionCalculator.addToSample(aabb);
100
- this.addToSortedList(entry, 'y');
101
- this.entriesMap.set(actor.id, entry);
133
+ this.addToSortedList(proxy, 'y');
134
+ this.proxiesByActorId.set(actor.id, proxy);
102
135
  }
103
- updateCollisionEntry(actor) {
136
+ updateProxy(actor) {
104
137
  const transform = actor.getComponent(Transform);
105
138
  const collider = actor.getComponent(Collider);
106
139
  const geometry = geometryBuilders[collider.type](collider, transform);
107
140
  const aabb = aabbBuilders[collider.type](geometry);
108
- const entry = this.entriesMap.get(actor.id);
109
- const prevAABB = entry.aabb;
110
- entry.aabb = aabb;
111
- entry.geometry = geometry;
112
- entry.orientationData = this.getOrientationData(actor);
141
+ const proxy = this.proxiesByActorId.get(actor.id);
142
+ const prevAABB = proxy.aabb;
143
+ proxy.aabb = aabb;
144
+ proxy.geometry = geometry;
145
+ proxy.orientationData = this.getOrientationData(actor);
146
+ proxy.layer = collider.layer;
113
147
  this.axis.x.dispersionCalculator.removeFromSample(prevAABB);
114
148
  this.axis.x.dispersionCalculator.addToSample(aabb);
115
- this.updateSortedList(entry, 'x');
149
+ this.updateSortedList(proxy, 'x');
116
150
  this.axis.y.dispersionCalculator.removeFromSample(prevAABB);
117
151
  this.axis.y.dispersionCalculator.addToSample(aabb);
118
- this.updateSortedList(entry, 'y');
152
+ this.updateSortedList(proxy, 'y');
119
153
  }
120
- addToSortedList(entry, axis) {
121
- const min = { value: entry.aabb.min[axis], entry };
122
- const max = { value: entry.aabb.max[axis], entry };
154
+ addToSortedList(proxy, axis) {
155
+ const min = { value: proxy.aabb.min[axis], proxy };
156
+ const max = { value: proxy.aabb.max[axis], proxy };
123
157
  this.axis[axis].sortedList.push(min, max);
124
- entry.edges ??= {};
125
- entry.edges[axis] = [min, max];
158
+ proxy.edges ??= {};
159
+ proxy.edges[axis] = [min, max];
126
160
  }
127
- updateSortedList(entry, axis) {
128
- const [min, max] = entry.edges[axis];
129
- min.value = entry.aabb.min[axis];
130
- min.entry = entry;
131
- max.value = entry.aabb.max[axis];
132
- max.entry = entry;
161
+ updateSortedList(proxy, axis) {
162
+ const [min, max] = proxy.edges[axis];
163
+ min.value = proxy.aabb.min[axis];
164
+ min.proxy = proxy;
165
+ max.value = proxy.aabb.max[axis];
166
+ max.proxy = proxy;
133
167
  }
134
168
  clearSortedList(axis) {
135
- this.axis[axis].sortedList = this.axis[axis].sortedList.filter((item) => !this.entriesToDelete.has(item.entry.actor.id));
169
+ this.axis[axis].sortedList = this.axis[axis].sortedList.filter((item) => !this.actorIdsToDelete.has(item.proxy.actor.id));
136
170
  }
137
171
  getAxes() {
138
172
  const xDispersion = this.axis.x.dispersionCalculator.getDispersion();
139
173
  const yDispersion = this.axis.y.dispersionCalculator.getDispersion();
140
174
  return xDispersion >= yDispersion ? ['x', 'y'] : ['y', 'x'];
141
175
  }
142
- areStaticBodies(entry1, entry2) {
143
- const { actor: actor1 } = entry1;
144
- const { actor: actor2 } = entry2;
176
+ areStaticBodies(proxy1, proxy2) {
177
+ const { actor: actor1 } = proxy1;
178
+ const { actor: actor2 } = proxy2;
145
179
  const rigidBody1 = actor1.getComponent(RigidBody);
146
180
  const rigidBody2 = actor2.getComponent(RigidBody);
147
181
  return rigidBody1?.type === 'static' && rigidBody2?.type === 'static';
148
182
  }
149
- testAABB(entry1, entry2, axis) {
150
- const aabb1 = entry1.aabb;
151
- const aabb2 = entry2.aabb;
183
+ testAABB(proxy1, proxy2, axis) {
184
+ const aabb1 = proxy1.aabb;
185
+ const aabb2 = proxy2.aabb;
152
186
  return (aabb1.max[axis] > aabb2.min[axis] && aabb1.min[axis] < aabb2.max[axis]);
153
187
  }
188
+ testCollisionLayers(proxy1, proxy2) {
189
+ return this.collisionMatrix[proxy1.layer]?.[proxy2.layer] ?? true;
190
+ }
191
+ sweepAndPruneQuery(queryProxy) {
192
+ const [mainAxis, secondAxis] = this.getAxes();
193
+ const sortedList = this.axis[mainAxis].sortedList;
194
+ const candidates = new Set();
195
+ for (const item of sortedList) {
196
+ const { proxy, value } = item;
197
+ if (value < queryProxy.aabb.min[mainAxis]) {
198
+ if (candidates.has(proxy)) {
199
+ candidates.delete(proxy);
200
+ }
201
+ else {
202
+ candidates.add(proxy);
203
+ }
204
+ continue;
205
+ }
206
+ if (value > queryProxy.aabb.max[mainAxis]) {
207
+ break;
208
+ }
209
+ if (!candidates.has(proxy)) {
210
+ candidates.add(proxy);
211
+ }
212
+ }
213
+ let candidateIndex = 0;
214
+ candidates.forEach((proxy) => {
215
+ if (!this.testAABB(proxy, queryProxy, secondAxis)) {
216
+ return;
217
+ }
218
+ if (queryProxy.layer !== undefined &&
219
+ !this.testCollisionLayers(proxy, queryProxy)) {
220
+ return;
221
+ }
222
+ this.queryCandidates[candidateIndex] = proxy;
223
+ candidateIndex += 1;
224
+ });
225
+ this.queryCandidates.length = candidateIndex;
226
+ }
154
227
  sweepAndPrune() {
155
228
  const [mainAxis, secondAxis] = this.getAxes();
156
229
  const { sortedList } = this.axis[mainAxis];
157
230
  insertionSort(sortedList, (arg1, arg2) => arg1.value - arg2.value);
158
- const activeEntries = new Set();
159
- let collisionIndex = 0;
231
+ const activeProxies = new Set();
232
+ let proxyPairIndex = 0;
160
233
  for (const item of sortedList) {
161
- const { entry } = item;
162
- if (!activeEntries.has(entry)) {
163
- activeEntries.forEach((activeEntry) => {
164
- if (!this.testAABB(entry, activeEntry, secondAxis)) {
234
+ const { proxy } = item;
235
+ if (!activeProxies.has(proxy)) {
236
+ activeProxies.forEach((activeProxy) => {
237
+ if (!this.testAABB(proxy, activeProxy, secondAxis)) {
238
+ return;
239
+ }
240
+ if (this.areStaticBodies(proxy, activeProxy)) {
165
241
  return;
166
242
  }
167
- if (this.areStaticBodies(entry, activeEntry)) {
243
+ if (!this.testCollisionLayers(proxy, activeProxy)) {
168
244
  return;
169
245
  }
170
- this.collisionPairs[collisionIndex] = [entry, activeEntry];
171
- collisionIndex += 1;
246
+ this.proxyPairs[proxyPairIndex] = [proxy, activeProxy];
247
+ proxyPairIndex += 1;
172
248
  });
173
- activeEntries.add(entry);
249
+ activeProxies.add(proxy);
174
250
  }
175
251
  else {
176
- activeEntries.delete(entry);
252
+ activeProxies.delete(proxy);
177
253
  }
178
254
  }
179
- if (this.collisionPairs.length > collisionIndex) {
180
- this.collisionPairs.length = collisionIndex;
255
+ if (this.proxyPairs.length > proxyPairIndex) {
256
+ this.proxyPairs.length = proxyPairIndex;
181
257
  }
182
258
  }
183
- checkOnIntersection(pair) {
184
- const [arg1, arg2] = pair;
185
- const type1 = arg1.actor.getComponent(Collider).type;
186
- const type2 = arg2.actor.getComponent(Collider).type;
187
- return intersectionCheckers[type1][type2](arg1, arg2);
259
+ checkOnIntersection(proxyPair) {
260
+ const [proxy1, proxy2] = proxyPair;
261
+ const type1 = proxy1.actor.getComponent(Collider).type;
262
+ const type2 = proxy2.actor.getComponent(Collider).type;
263
+ const intersectionChecker = intersectionCheckers[type1]?.[type2];
264
+ if (!intersectionChecker) {
265
+ return false;
266
+ }
267
+ return intersectionChecker(proxy1, proxy2);
188
268
  }
189
- sendCollisionEvent(actor1, actor2, intersection) {
190
- const { mtv1, mtv2 } = intersection;
191
- this.scene.dispatchEventImmediately(Collision, {
269
+ storeContact(contactIndex, actor1, actor2, intersection) {
270
+ this.contacts[contactIndex] ??= {
192
271
  actor1,
193
272
  actor2,
194
- mtv1,
195
- mtv2,
196
- });
197
- this.scene.dispatchEventImmediately(Collision, {
198
- actor1: actor2,
199
- actor2: actor1,
200
- mtv1: mtv2,
201
- mtv2: mtv1,
202
- });
273
+ normal: intersection.normal,
274
+ penetration: intersection.penetration,
275
+ contactPoints: intersection.contactPoints,
276
+ };
277
+ this.contacts[contactIndex].actor1 = actor1;
278
+ this.contacts[contactIndex].actor2 = actor2;
279
+ this.contacts[contactIndex].normal = intersection.normal;
280
+ this.contacts[contactIndex].penetration = intersection.penetration;
281
+ this.contacts[contactIndex].contactPoints = intersection.contactPoints;
203
282
  }
204
- clearDeletedEntries() {
205
- if (this.entriesToDelete.size === 0) {
283
+ clearDeletedProxies() {
284
+ if (this.actorIdsToDelete.size === 0) {
206
285
  return;
207
286
  }
208
287
  this.clearSortedList('x');
209
288
  this.clearSortedList('y');
210
- this.entriesToDelete.forEach((id) => {
211
- const entry = this.entriesMap.get(id);
212
- this.axis.x.dispersionCalculator.removeFromSample(entry.aabb);
213
- this.axis.y.dispersionCalculator.removeFromSample(entry.aabb);
214
- this.entriesMap.delete(id);
289
+ this.actorIdsToDelete.forEach((id) => {
290
+ const proxy = this.proxiesByActorId.get(id);
291
+ this.axis.x.dispersionCalculator.removeFromSample(proxy.aabb);
292
+ this.axis.y.dispersionCalculator.removeFromSample(proxy.aabb);
293
+ this.proxiesByActorId.delete(id);
215
294
  });
216
- this.entriesToDelete.clear();
295
+ this.actorIdsToDelete.clear();
217
296
  }
218
297
  update() {
219
- this.clearDeletedEntries();
298
+ this.clearDeletedProxies();
220
299
  this.actorQuery.getActors().forEach((actor) => {
221
300
  if (!this.checkOnReorientation(actor)) {
222
301
  return;
223
302
  }
224
- this.updateCollisionEntry(actor);
303
+ this.updateProxy(actor);
225
304
  });
226
305
  this.sweepAndPrune();
227
- this.collisionPairs.forEach((pair) => {
228
- const intersection = this.checkOnIntersection(pair);
306
+ let contactIndex = 0;
307
+ this.proxyPairs.forEach((proxyPair) => {
308
+ const intersection = this.checkOnIntersection(proxyPair);
229
309
  if (intersection) {
230
- this.sendCollisionEvent(pair[0].actor, pair[1].actor, intersection);
310
+ this.storeContact(contactIndex, proxyPair[0].actor, proxyPair[1].actor, intersection);
311
+ contactIndex += 1;
231
312
  }
232
313
  });
314
+ if (this.contacts.length > contactIndex) {
315
+ this.contacts.length = contactIndex;
316
+ }
317
+ return this.contacts;
233
318
  }
234
319
  }
@@ -0,0 +1,10 @@
1
+ import type { Proxy, Intersection } from '../../types';
2
+ /**
3
+ * Checks box colliders for intersection.
4
+ *
5
+ * The SAT (separating axis theorem) is used to find the collision normal
6
+ * and penetration depth. Once the best axis is known, the incident edge is
7
+ * clipped against the reference edge to produce up to two stable contact
8
+ * points for impulse-based collision resolution.
9
+ */
10
+ export declare const checkBoxesIntersection: (arg1: Proxy, arg2: Proxy) => Intersection | false;
@@ -0,0 +1,36 @@
1
+ import { orientNormal } from '../utils';
2
+ import { findMinBoxesOverlap, buildContactPoints } from './utils';
3
+ /**
4
+ * Checks box colliders for intersection.
5
+ *
6
+ * The SAT (separating axis theorem) is used to find the collision normal
7
+ * and penetration depth. Once the best axis is known, the incident edge is
8
+ * clipped against the reference edge to produce up to two stable contact
9
+ * points for impulse-based collision resolution.
10
+ */
11
+ export const checkBoxesIntersection = (arg1, arg2) => {
12
+ const geometry1 = arg1.geometry;
13
+ const geometry2 = arg2.geometry;
14
+ const overlap1 = findMinBoxesOverlap(geometry1, geometry2);
15
+ if (overlap1 === false) {
16
+ return false;
17
+ }
18
+ const overlap2 = findMinBoxesOverlap(geometry2, geometry1);
19
+ if (overlap2 === false) {
20
+ return false;
21
+ }
22
+ const isArg1Reference = overlap1.overlap <= overlap2.overlap;
23
+ const referenceGeometry = isArg1Reference ? geometry1 : geometry2;
24
+ const incidentGeometry = isArg1Reference ? geometry2 : geometry1;
25
+ const referenceOverlap = isArg1Reference ? overlap1 : overlap2;
26
+ const normal = orientNormal(referenceOverlap.axis.clone(), geometry1.center, geometry2.center);
27
+ const referenceNormal = normal.clone();
28
+ if (!isArg1Reference) {
29
+ referenceNormal.multiplyNumber(-1);
30
+ }
31
+ return {
32
+ normal,
33
+ penetration: referenceOverlap.overlap,
34
+ contactPoints: buildContactPoints(referenceGeometry, referenceNormal, incidentGeometry),
35
+ };
36
+ };
@@ -0,0 +1,17 @@
1
+ import { Vector2 } from '../../../../../../../engine/math-lib';
2
+ import type { BoxGeometry, Point } from '../../types';
3
+ export declare const CONTACT_EPSILON = 0.0001;
4
+ export declare const MAX_CONTACT_POINTS = 2;
5
+ export interface AxisOverlap {
6
+ axis: Vector2;
7
+ overlap: number;
8
+ }
9
+ export declare const findMinBoxesOverlap: (geometry1: BoxGeometry, geometry2: BoxGeometry) => AxisOverlap | false;
10
+ /**
11
+ * Builds up to two box-vs-box contact points by clipping the incident edge
12
+ * against the side planes of the reference edge.
13
+ *
14
+ * The returned points lie on the reference face plane, which makes them
15
+ * suitable to use as world-space contact points in a simple impulse solver.
16
+ */
17
+ export declare const buildContactPoints: (referencePolygon: BoxGeometry, referenceNormal: Vector2, incidentPolygon: BoxGeometry) => Point[];