dacha 0.18.0-alpha.8 → 0.18.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/build/contrib/components/index.d.ts +1 -0
- package/build/contrib/components/index.js +1 -0
- package/build/contrib/components/interpolation/index.d.ts +85 -0
- package/build/contrib/components/interpolation/index.js +101 -0
- package/build/contrib/components/rigid-body/index.d.ts +108 -14
- package/build/contrib/components/rigid-body/index.js +191 -22
- package/build/contrib/systems/animator/index.d.ts +3 -2
- package/build/contrib/systems/animator/index.js +6 -3
- package/build/contrib/systems/behavior-system/system.d.ts +4 -2
- package/build/contrib/systems/behavior-system/system.js +11 -3
- package/build/contrib/systems/behavior-system/types.d.ts +7 -10
- package/build/contrib/systems/character-controller/index.d.ts +4 -2
- package/build/contrib/systems/character-controller/index.js +22 -17
- package/build/contrib/systems/character-controller/one-way-validator.d.ts +15 -0
- package/build/contrib/systems/character-controller/one-way-validator.js +73 -0
- package/build/contrib/systems/game-stats-meter/index.d.ts +4 -3
- package/build/contrib/systems/game-stats-meter/index.js +11 -10
- package/build/contrib/systems/index.d.ts +2 -0
- package/build/contrib/systems/index.js +1 -0
- package/build/contrib/systems/interpolator/api.d.ts +40 -0
- package/build/contrib/systems/interpolator/api.js +70 -0
- package/build/contrib/systems/interpolator/index.d.ts +3 -0
- package/build/contrib/systems/interpolator/index.js +2 -0
- package/build/contrib/systems/interpolator/system.d.ts +31 -0
- package/build/contrib/systems/interpolator/system.js +96 -0
- package/build/contrib/systems/interpolator/tests/helpers.d.ts +13 -0
- package/build/contrib/systems/interpolator/tests/helpers.js +45 -0
- package/build/contrib/systems/interpolator/utils.d.ts +5 -0
- package/build/contrib/systems/interpolator/utils.js +41 -0
- package/build/contrib/systems/physics-system/api.d.ts +45 -1
- package/build/contrib/systems/physics-system/api.js +49 -0
- package/build/contrib/systems/physics-system/consts.d.ts +13 -0
- package/build/contrib/systems/physics-system/consts.js +17 -0
- package/build/contrib/systems/physics-system/physics-system.d.ts +2 -2
- package/build/contrib/systems/physics-system/physics-system.js +24 -4
- package/build/contrib/systems/physics-system/subsystems/collision-detection/dynamic-aabb-tree/index.d.ts +1 -1
- package/build/contrib/systems/physics-system/subsystems/collision-detection/dynamic-aabb-tree/index.js +21 -15
- package/build/contrib/systems/physics-system/subsystems/collision-detection/index.d.ts +11 -11
- package/build/contrib/systems/physics-system/subsystems/collision-detection/index.js +133 -125
- package/build/contrib/systems/physics-system/subsystems/collision-detection/intersection-checkers/box-box/check-boxes-intersection.js +5 -3
- package/build/contrib/systems/physics-system/subsystems/collision-detection/intersection-checkers/box-box/utils.d.ts +1 -0
- package/build/contrib/systems/physics-system/subsystems/collision-detection/intersection-checkers/box-box/utils.js +2 -1
- package/build/contrib/systems/physics-system/subsystems/collision-detection/intersection-checkers/box-capsule/check-box-and-capsule-intersection.js +4 -1
- package/build/contrib/systems/physics-system/subsystems/collision-detection/intersection-checkers/box-segment/check-box-and-segment-intersection.js +4 -2
- package/build/contrib/systems/physics-system/subsystems/collision-detection/intersection-checkers/common/points.d.ts +2 -0
- package/build/contrib/systems/physics-system/subsystems/collision-detection/intersection-checkers/common/points.js +16 -0
- package/build/contrib/systems/physics-system/subsystems/collision-detection/intersection-checkers/index.js +2 -0
- package/build/contrib/systems/physics-system/subsystems/collision-detection/intersection-checkers/tests/helpers.js +3 -14
- package/build/contrib/systems/physics-system/subsystems/collision-detection/query-utils.d.ts +5 -0
- package/build/contrib/systems/physics-system/subsystems/collision-detection/query-utils.js +97 -81
- package/build/contrib/systems/physics-system/subsystems/collision-detection/shape-cast-checkers/tests/helpers.js +2 -7
- package/build/contrib/systems/physics-system/subsystems/collision-detection/tests/assertions.d.ts +1 -0
- package/build/contrib/systems/physics-system/subsystems/collision-detection/tests/assertions.js +7 -0
- package/build/contrib/systems/physics-system/subsystems/collision-detection/types.d.ts +0 -15
- package/build/contrib/systems/physics-system/subsystems/collision-detection/utils.d.ts +3 -0
- package/build/contrib/systems/physics-system/subsystems/collision-detection/utils.js +9 -0
- package/build/contrib/systems/physics-system/subsystems/constraint-solver/contact-state-manager.d.ts +63 -0
- package/build/contrib/systems/physics-system/subsystems/constraint-solver/contact-state-manager.js +170 -0
- package/build/contrib/systems/physics-system/subsystems/constraint-solver/contact-utils.d.ts +5 -0
- package/build/contrib/systems/physics-system/subsystems/constraint-solver/contact-utils.js +41 -0
- package/build/contrib/systems/physics-system/subsystems/constraint-solver/impulse-utils.d.ts +16 -0
- package/build/contrib/systems/physics-system/subsystems/constraint-solver/impulse-utils.js +77 -0
- package/build/contrib/systems/physics-system/subsystems/constraint-solver/index.d.ts +53 -4
- package/build/contrib/systems/physics-system/subsystems/constraint-solver/index.js +334 -116
- package/build/contrib/systems/physics-system/subsystems/constraint-solver/one-way-validator.d.ts +11 -0
- package/build/contrib/{utils → systems/physics-system/subsystems/constraint-solver}/one-way-validator.js +22 -25
- package/build/contrib/systems/physics-system/subsystems/constraint-solver/sleep-support-tracker.d.ts +13 -0
- package/build/contrib/systems/physics-system/subsystems/constraint-solver/sleep-support-tracker.js +42 -0
- package/build/contrib/systems/physics-system/subsystems/constraint-solver/tests/helpers.d.ts +4 -0
- package/build/contrib/systems/physics-system/subsystems/constraint-solver/tests/helpers.js +20 -0
- package/build/contrib/systems/physics-system/subsystems/physics/index.d.ts +15 -4
- package/build/contrib/systems/physics-system/subsystems/physics/index.js +131 -53
- package/build/contrib/systems/physics-system/subsystems/physics/mass-properties.d.ts +2 -0
- package/build/contrib/systems/physics-system/subsystems/physics/mass-properties.js +55 -0
- package/build/contrib/systems/physics-system/tests/helpers.d.ts +5 -2
- package/build/contrib/systems/physics-system/tests/helpers.js +11 -2
- package/build/contrib/systems/physics-system/types.d.ts +18 -2
- package/build/contrib/systems/renderer/actor-render-tree.js +15 -6
- package/build/contrib/systems/renderer/filters/index.d.ts +1 -1
- package/build/contrib/systems/renderer/filters/index.js +1 -1
- package/build/contrib/systems/renderer/material/index.d.ts +2 -1
- package/build/contrib/systems/renderer/material/index.js +1 -1
- package/build/contrib/systems/renderer/renderer.d.ts +2 -2
- package/build/contrib/systems/renderer/renderer.js +3 -4
- package/build/contrib/systems/renderer/types.d.ts +0 -3
- package/build/engine/data-lib/index.d.ts +1 -1
- package/build/engine/data-lib/index.js +1 -1
- package/build/engine/data-lib/pool.d.ts +9 -0
- package/build/engine/data-lib/pool.js +19 -0
- package/build/engine/engine.js +4 -1
- package/build/engine/game-loop.d.ts +3 -1
- package/build/engine/game-loop.js +11 -8
- package/build/engine/math-lib/math/ops.d.ts +16 -0
- package/build/engine/math-lib/math/ops.js +25 -0
- package/build/engine/scene/scene-manager.d.ts +4 -1
- package/build/engine/scene/scene-manager.js +5 -1
- package/build/engine/system/index.d.ts +1 -1
- package/build/engine/system/system.d.ts +10 -11
- package/build/engine/system/system.js +5 -2
- package/build/engine/time.d.ts +54 -0
- package/build/engine/time.js +77 -0
- package/build/index.d.ts +2 -1
- package/package.json +1 -1
- package/build/contrib/systems/physics-system/subsystems/collision-detection/dispersion-calculator/index.d.ts +0 -11
- package/build/contrib/systems/physics-system/subsystems/collision-detection/dispersion-calculator/index.js +0 -41
- package/build/contrib/utils/one-way-validator.d.ts +0 -12
- package/build/engine/data-lib/sort/index.d.ts +0 -1
- package/build/engine/data-lib/sort/index.js +0 -1
- package/build/engine/data-lib/sort/insertion-sort.d.ts +0 -1
- package/build/engine/data-lib/sort/insertion-sort.js +0 -14
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { Vector2 } from '../../../../../engine/math-lib';
|
|
1
2
|
import { Collider, Transform } from '../../../../components';
|
|
2
3
|
import { geometryBuilders } from './geometry-builders';
|
|
3
4
|
import { aabbBuilders } from './aabb-builders';
|
|
@@ -10,7 +11,7 @@ export function buildQueryProxy(type, params) {
|
|
|
10
11
|
aabb: aabbBuilders[type](geometry),
|
|
11
12
|
geometry,
|
|
12
13
|
layer: params.layer,
|
|
13
|
-
excludedActors: params.excludeActors
|
|
14
|
+
excludedActors: params.excludeActors?.length
|
|
14
15
|
? new Set(params.excludeActors)
|
|
15
16
|
: undefined,
|
|
16
17
|
actorFilter: params.actorFilter,
|
|
@@ -62,130 +63,145 @@ export const getActorCastQueryType = (params) => {
|
|
|
62
63
|
return null;
|
|
63
64
|
}
|
|
64
65
|
};
|
|
66
|
+
export const makeCastHit = () => ({
|
|
67
|
+
actor: undefined,
|
|
68
|
+
point: { x: 0, y: 0 },
|
|
69
|
+
normal: new Vector2(0, 0),
|
|
70
|
+
distance: 0,
|
|
71
|
+
});
|
|
72
|
+
const cloneCastHit = (hit) => ({
|
|
73
|
+
actor: hit.actor,
|
|
74
|
+
point: hit.point,
|
|
75
|
+
normal: hit.normal,
|
|
76
|
+
distance: hit.distance,
|
|
77
|
+
});
|
|
78
|
+
export const makeOverlapHit = () => ({
|
|
79
|
+
actor: undefined,
|
|
80
|
+
normal: new Vector2(0, 0),
|
|
81
|
+
penetration: 0,
|
|
82
|
+
contactPoints: [],
|
|
83
|
+
});
|
|
84
|
+
const cloneOverlapHit = (hit) => ({
|
|
85
|
+
actor: hit.actor,
|
|
86
|
+
normal: hit.normal,
|
|
87
|
+
penetration: hit.penetration,
|
|
88
|
+
contactPoints: hit.contactPoints,
|
|
89
|
+
});
|
|
65
90
|
export const overlap = (type, queryProxy, proxies) => {
|
|
91
|
+
const scratch = makeOverlapHit();
|
|
66
92
|
const hits = [];
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
if (!checker) {
|
|
71
|
-
continue;
|
|
72
|
-
}
|
|
73
|
-
const intersection = checker(queryProxy.geometry, proxy.geometry);
|
|
74
|
-
if (!intersection) {
|
|
75
|
-
continue;
|
|
76
|
-
}
|
|
77
|
-
const hit = {
|
|
78
|
-
actor: proxy.actor,
|
|
79
|
-
normal: intersection.normal.clone().multiplyNumber(-1),
|
|
80
|
-
penetration: intersection.penetration,
|
|
81
|
-
contactPoints: intersection.contactPoints,
|
|
82
|
-
};
|
|
83
|
-
if (queryProxy.hitFilter && !queryProxy.hitFilter(hit)) {
|
|
84
|
-
continue;
|
|
85
|
-
}
|
|
86
|
-
hits.push(hit);
|
|
87
|
-
}
|
|
93
|
+
overlapEach(type, queryProxy, proxies, scratch, (hit) => {
|
|
94
|
+
hits.push(cloneOverlapHit(hit));
|
|
95
|
+
});
|
|
88
96
|
return hits;
|
|
89
97
|
};
|
|
90
98
|
export const raycast = (queryProxy, proxies) => {
|
|
99
|
+
const scratch = makeCastHit();
|
|
91
100
|
let nearestDistance = Infinity;
|
|
92
101
|
let nearestHit = null;
|
|
93
|
-
|
|
94
|
-
const collider = proxy.actor.getComponent(Collider);
|
|
95
|
-
const hit = raycastCheckers.ray[collider.shape.type](queryProxy.geometry, proxy.geometry);
|
|
96
|
-
if (!hit) {
|
|
97
|
-
continue;
|
|
98
|
-
}
|
|
99
|
-
const castHit = {
|
|
100
|
-
actor: proxy.actor,
|
|
101
|
-
point: hit.point,
|
|
102
|
-
normal: hit.normal,
|
|
103
|
-
distance: hit.distance,
|
|
104
|
-
};
|
|
105
|
-
if (queryProxy.hitFilter && !queryProxy.hitFilter(castHit)) {
|
|
106
|
-
continue;
|
|
107
|
-
}
|
|
102
|
+
raycastEach(queryProxy, proxies, scratch, (hit) => {
|
|
108
103
|
if (hit.distance < nearestDistance) {
|
|
109
|
-
nearestHit = castHit;
|
|
110
104
|
nearestDistance = hit.distance;
|
|
105
|
+
nearestHit = nearestHit ?? makeCastHit();
|
|
106
|
+
nearestHit.actor = hit.actor;
|
|
107
|
+
nearestHit.point = hit.point;
|
|
108
|
+
nearestHit.normal = hit.normal;
|
|
109
|
+
nearestHit.distance = hit.distance;
|
|
111
110
|
}
|
|
112
|
-
}
|
|
111
|
+
});
|
|
113
112
|
return nearestHit;
|
|
114
113
|
};
|
|
115
114
|
export const raycastAll = (queryProxy, proxies) => {
|
|
115
|
+
const scratch = makeCastHit();
|
|
116
116
|
const hits = [];
|
|
117
|
+
raycastEach(queryProxy, proxies, scratch, (hit) => {
|
|
118
|
+
hits.push(cloneCastHit(hit));
|
|
119
|
+
});
|
|
120
|
+
hits.sort((arg1, arg2) => arg1.distance - arg2.distance);
|
|
121
|
+
return hits;
|
|
122
|
+
};
|
|
123
|
+
export const shapeCast = (type, queryProxy, proxies) => {
|
|
124
|
+
const scratch = makeCastHit();
|
|
125
|
+
let nearestDistance = Infinity;
|
|
126
|
+
let nearestHit = null;
|
|
127
|
+
shapeCastEach(type, queryProxy, proxies, scratch, (hit) => {
|
|
128
|
+
if (hit.distance < nearestDistance) {
|
|
129
|
+
nearestDistance = hit.distance;
|
|
130
|
+
nearestHit = nearestHit ?? makeCastHit();
|
|
131
|
+
nearestHit.actor = hit.actor;
|
|
132
|
+
nearestHit.point = hit.point;
|
|
133
|
+
nearestHit.normal = hit.normal;
|
|
134
|
+
nearestHit.distance = hit.distance;
|
|
135
|
+
}
|
|
136
|
+
});
|
|
137
|
+
return nearestHit;
|
|
138
|
+
};
|
|
139
|
+
export const shapeCastAll = (type, queryProxy, proxies) => {
|
|
140
|
+
const scratch = makeCastHit();
|
|
141
|
+
const hits = [];
|
|
142
|
+
shapeCastEach(type, queryProxy, proxies, scratch, (hit) => {
|
|
143
|
+
hits.push(cloneCastHit(hit));
|
|
144
|
+
});
|
|
145
|
+
hits.sort((arg1, arg2) => arg1.distance - arg2.distance);
|
|
146
|
+
return hits;
|
|
147
|
+
};
|
|
148
|
+
export const raycastEach = (queryProxy, proxies, hit, callback) => {
|
|
117
149
|
for (const proxy of proxies) {
|
|
118
150
|
const collider = proxy.actor.getComponent(Collider);
|
|
119
|
-
const
|
|
120
|
-
if (!
|
|
151
|
+
const result = raycastCheckers.ray[collider.shape.type](queryProxy.geometry, proxy.geometry);
|
|
152
|
+
if (!result) {
|
|
121
153
|
continue;
|
|
122
154
|
}
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
};
|
|
129
|
-
if (queryProxy.hitFilter && !queryProxy.hitFilter(castHit)) {
|
|
155
|
+
hit.actor = proxy.actor;
|
|
156
|
+
hit.point = result.point;
|
|
157
|
+
hit.normal = result.normal;
|
|
158
|
+
hit.distance = result.distance;
|
|
159
|
+
if (queryProxy.hitFilter && !queryProxy.hitFilter(hit)) {
|
|
130
160
|
continue;
|
|
131
161
|
}
|
|
132
|
-
|
|
162
|
+
callback(hit);
|
|
133
163
|
}
|
|
134
|
-
hits.sort((arg1, arg2) => arg1.distance - arg2.distance);
|
|
135
|
-
return hits;
|
|
136
164
|
};
|
|
137
|
-
export const
|
|
138
|
-
let nearestDistance = Infinity;
|
|
139
|
-
let nearestHit = null;
|
|
165
|
+
export const shapeCastEach = (type, queryProxy, proxies, hit, callback) => {
|
|
140
166
|
for (const proxy of proxies) {
|
|
141
167
|
const collider = proxy.actor.getComponent(Collider);
|
|
142
168
|
const checker = shapeCastCheckers[type]?.[collider.shape.type];
|
|
143
169
|
if (!checker) {
|
|
144
170
|
continue;
|
|
145
171
|
}
|
|
146
|
-
const
|
|
147
|
-
if (!
|
|
172
|
+
const result = checker(queryProxy.geometry, proxy.geometry);
|
|
173
|
+
if (!result) {
|
|
148
174
|
continue;
|
|
149
175
|
}
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
distance: castHit.distance,
|
|
155
|
-
};
|
|
176
|
+
hit.actor = proxy.actor;
|
|
177
|
+
hit.point = result.point;
|
|
178
|
+
hit.normal = result.normal;
|
|
179
|
+
hit.distance = result.distance;
|
|
156
180
|
if (queryProxy.hitFilter && !queryProxy.hitFilter(hit)) {
|
|
157
181
|
continue;
|
|
158
182
|
}
|
|
159
|
-
|
|
160
|
-
nearestHit = hit;
|
|
161
|
-
nearestDistance = castHit.distance;
|
|
162
|
-
}
|
|
183
|
+
callback(hit);
|
|
163
184
|
}
|
|
164
|
-
return nearestHit;
|
|
165
185
|
};
|
|
166
|
-
export const
|
|
167
|
-
const hits = [];
|
|
186
|
+
export const overlapEach = (type, queryProxy, proxies, hit, callback) => {
|
|
168
187
|
for (const proxy of proxies) {
|
|
169
188
|
const collider = proxy.actor.getComponent(Collider);
|
|
170
|
-
const checker =
|
|
189
|
+
const checker = intersectionCheckers[type]?.[collider.shape.type];
|
|
171
190
|
if (!checker) {
|
|
172
191
|
continue;
|
|
173
192
|
}
|
|
174
|
-
const
|
|
175
|
-
if (!
|
|
193
|
+
const intersection = checker(queryProxy.geometry, proxy.geometry);
|
|
194
|
+
if (!intersection) {
|
|
176
195
|
continue;
|
|
177
196
|
}
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
};
|
|
197
|
+
intersection.normal.multiplyNumber(-1);
|
|
198
|
+
hit.actor = proxy.actor;
|
|
199
|
+
hit.normal = intersection.normal;
|
|
200
|
+
hit.penetration = intersection.penetration;
|
|
201
|
+
hit.contactPoints = intersection.contactPoints;
|
|
184
202
|
if (queryProxy.hitFilter && !queryProxy.hitFilter(hit)) {
|
|
185
203
|
continue;
|
|
186
204
|
}
|
|
187
|
-
|
|
205
|
+
callback(hit);
|
|
188
206
|
}
|
|
189
|
-
hits.sort((arg1, arg2) => arg1.distance - arg2.distance);
|
|
190
|
-
return hits;
|
|
191
207
|
};
|
|
@@ -2,6 +2,7 @@ import { Vector2 } from '../../../../../../../engine/math-lib';
|
|
|
2
2
|
import { buildBoxCastGeometry } from '../../geometry-builders/build-box-cast-geometry';
|
|
3
3
|
import { buildCapsuleCastGeometry } from '../../geometry-builders/build-capsule-cast-geometry';
|
|
4
4
|
import { buildCircleCastGeometry } from '../../geometry-builders/build-circle-cast-geometry';
|
|
5
|
+
import { expectHit } from '../../tests/assertions';
|
|
5
6
|
export const createCircleCastGeometry = (centerX, centerY, radius, directionX, directionY, maxDistance) => buildCircleCastGeometry({
|
|
6
7
|
shape: {
|
|
7
8
|
type: 'circle',
|
|
@@ -30,10 +31,4 @@ export const createBoxCastGeometry = (centerX, centerY, sizeX, sizeY, directionX
|
|
|
30
31
|
direction: new Vector2(directionX, directionY),
|
|
31
32
|
maxDistance,
|
|
32
33
|
});
|
|
33
|
-
export const expectShapeCastHit = (hit) =>
|
|
34
|
-
expect(hit).not.toBe(false);
|
|
35
|
-
if (hit === false) {
|
|
36
|
-
throw new Error('Expected shape-cast hit, received false');
|
|
37
|
-
}
|
|
38
|
-
return hit;
|
|
39
|
-
};
|
|
34
|
+
export const expectShapeCastHit = (hit) => expectHit(hit, 'shape-cast hit');
|
package/build/contrib/systems/physics-system/subsystems/collision-detection/tests/assertions.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const expectHit: <T>(hit: false | T, label: string) => T;
|
|
@@ -2,7 +2,6 @@ import type { Vector2, Point } from '../../../../../engine/math-lib';
|
|
|
2
2
|
import type { Actor } from '../../../../../engine/actor';
|
|
3
3
|
import type { CastHit, OverlapHit } from '../../types';
|
|
4
4
|
import type { DynamicAABBTreeEntryId } from './dynamic-aabb-tree';
|
|
5
|
-
import type { DispersionCalculator } from './dispersion-calculator';
|
|
6
5
|
export type { Point };
|
|
7
6
|
export interface AABB {
|
|
8
7
|
min: Point;
|
|
@@ -83,7 +82,6 @@ export interface ActorProxy {
|
|
|
83
82
|
aabb: AABB;
|
|
84
83
|
geometry: Geometry;
|
|
85
84
|
orientationData: OrientationData;
|
|
86
|
-
edges: Record<Axis, [SortedItem, SortedItem]>;
|
|
87
85
|
treeEntryId: DynamicAABBTreeEntryId;
|
|
88
86
|
layer: string;
|
|
89
87
|
}
|
|
@@ -96,19 +94,6 @@ export interface QueryProxy {
|
|
|
96
94
|
hitFilter?: (hit: OverlapHit | CastHit) => boolean;
|
|
97
95
|
}
|
|
98
96
|
export type Proxy = ActorProxy | QueryProxy;
|
|
99
|
-
export interface SortedItem {
|
|
100
|
-
proxy: ActorProxy;
|
|
101
|
-
value: number;
|
|
102
|
-
}
|
|
103
|
-
export interface AxisEntry {
|
|
104
|
-
sortedList: SortedItem[];
|
|
105
|
-
dispersionCalculator: DispersionCalculator;
|
|
106
|
-
}
|
|
107
|
-
export type Axis = 'x' | 'y';
|
|
108
|
-
export interface Axes {
|
|
109
|
-
x: AxisEntry;
|
|
110
|
-
y: AxisEntry;
|
|
111
|
-
}
|
|
112
97
|
export type ProxyPair = [ActorProxy, ActorProxy];
|
|
113
98
|
export interface Contact {
|
|
114
99
|
actor1: Actor;
|
|
@@ -1,5 +1,8 @@
|
|
|
1
|
+
import type { ActorProxy } from './types';
|
|
1
2
|
export declare const isZero: (value: number) => boolean;
|
|
2
3
|
export declare const isDefinitelyPositive: (value: number) => boolean;
|
|
3
4
|
export declare const isDefinitelyNegative: (value: number) => boolean;
|
|
4
5
|
export declare const isGreaterThan: (left: number, right: number) => boolean;
|
|
5
6
|
export declare const isLessThan: (left: number, right: number) => boolean;
|
|
7
|
+
export declare const isStatic: (proxy: ActorProxy) => boolean;
|
|
8
|
+
export declare const isDisabled: (proxy: ActorProxy) => boolean;
|
|
@@ -1,6 +1,15 @@
|
|
|
1
|
+
import { RigidBody, Collider } from '../../../../components';
|
|
1
2
|
import { INTERSECTION_EPSILON } from './constants';
|
|
2
3
|
export const isZero = (value) => Math.abs(value) <= INTERSECTION_EPSILON;
|
|
3
4
|
export const isDefinitelyPositive = (value) => value > INTERSECTION_EPSILON;
|
|
4
5
|
export const isDefinitelyNegative = (value) => value < -INTERSECTION_EPSILON;
|
|
5
6
|
export const isGreaterThan = (left, right) => isDefinitelyPositive(left - right);
|
|
6
7
|
export const isLessThan = (left, right) => isDefinitelyNegative(left - right);
|
|
8
|
+
export const isStatic = (proxy) => {
|
|
9
|
+
const rigidBody = proxy.actor.getComponent(RigidBody);
|
|
10
|
+
return rigidBody?.type === 'static';
|
|
11
|
+
};
|
|
12
|
+
export const isDisabled = (proxy) => {
|
|
13
|
+
const collider = proxy.actor.getComponent(Collider);
|
|
14
|
+
return collider?.disabled === true;
|
|
15
|
+
};
|
package/build/contrib/systems/physics-system/subsystems/constraint-solver/contact-state-manager.d.ts
ADDED
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import type { Actor } from '../../../../../engine/actor';
|
|
2
|
+
import { RigidBody } from '../../../../components/rigid-body';
|
|
3
|
+
import type { Contact } from '../collision-detection/types';
|
|
4
|
+
export interface ContactPoint {
|
|
5
|
+
positionX: number;
|
|
6
|
+
positionY: number;
|
|
7
|
+
normalImpulse: number;
|
|
8
|
+
tangentImpulse: number;
|
|
9
|
+
biasImpulse: number;
|
|
10
|
+
anchorAX: number;
|
|
11
|
+
anchorAY: number;
|
|
12
|
+
anchorBX: number;
|
|
13
|
+
anchorBY: number;
|
|
14
|
+
normalMass: number;
|
|
15
|
+
tangentMass: number;
|
|
16
|
+
velocityBias: number;
|
|
17
|
+
}
|
|
18
|
+
export interface ContactState {
|
|
19
|
+
contact: Contact;
|
|
20
|
+
actor1: Actor;
|
|
21
|
+
actor2: Actor;
|
|
22
|
+
bodyA: RigidBody;
|
|
23
|
+
bodyB: RigidBody;
|
|
24
|
+
invMassA: number;
|
|
25
|
+
invInertiaA: number;
|
|
26
|
+
invMassB: number;
|
|
27
|
+
invInertiaB: number;
|
|
28
|
+
normalX: number;
|
|
29
|
+
normalY: number;
|
|
30
|
+
tangentX: number;
|
|
31
|
+
tangentY: number;
|
|
32
|
+
friction: number;
|
|
33
|
+
restitution: number;
|
|
34
|
+
k01: number;
|
|
35
|
+
determinant: number;
|
|
36
|
+
blockSolvable: boolean;
|
|
37
|
+
active: boolean;
|
|
38
|
+
warmStartAllowed: boolean;
|
|
39
|
+
skipBias: boolean;
|
|
40
|
+
point0: ContactPoint;
|
|
41
|
+
point1: ContactPoint;
|
|
42
|
+
pointCount: number;
|
|
43
|
+
version: number;
|
|
44
|
+
}
|
|
45
|
+
export declare class ContactStateManager {
|
|
46
|
+
private stateMap;
|
|
47
|
+
private states;
|
|
48
|
+
private version;
|
|
49
|
+
constructor();
|
|
50
|
+
updateVersion(): void;
|
|
51
|
+
acquire(contact: Contact): ContactState;
|
|
52
|
+
pruneStaleStates(): void;
|
|
53
|
+
forEach(callback: (state: ContactState) => void): void;
|
|
54
|
+
clearWarmStartImpulses(state: ContactState): void;
|
|
55
|
+
private clearFrameImpulses;
|
|
56
|
+
private get;
|
|
57
|
+
private set;
|
|
58
|
+
private delete;
|
|
59
|
+
private createState;
|
|
60
|
+
private canPreserveImpulses;
|
|
61
|
+
private isPointClose;
|
|
62
|
+
private updateContactIdentity;
|
|
63
|
+
}
|
package/build/contrib/systems/physics-system/subsystems/constraint-solver/contact-state-manager.js
ADDED
|
@@ -0,0 +1,170 @@
|
|
|
1
|
+
import { RigidBody } from '../../../../components/rigid-body';
|
|
2
|
+
const CONTACT_NORMAL_MIN_DOT = 0.98;
|
|
3
|
+
const CONTACT_POINT_MAX_DISTANCE = 0.2;
|
|
4
|
+
const CONTACT_POINT_MAX_DISTANCE_SQUARED = CONTACT_POINT_MAX_DISTANCE * CONTACT_POINT_MAX_DISTANCE;
|
|
5
|
+
const createContactPoint = () => ({
|
|
6
|
+
positionX: 0,
|
|
7
|
+
positionY: 0,
|
|
8
|
+
normalImpulse: 0,
|
|
9
|
+
tangentImpulse: 0,
|
|
10
|
+
biasImpulse: 0,
|
|
11
|
+
anchorAX: 0,
|
|
12
|
+
anchorAY: 0,
|
|
13
|
+
anchorBX: 0,
|
|
14
|
+
anchorBY: 0,
|
|
15
|
+
normalMass: 0,
|
|
16
|
+
tangentMass: 0,
|
|
17
|
+
velocityBias: 0,
|
|
18
|
+
});
|
|
19
|
+
export class ContactStateManager {
|
|
20
|
+
stateMap;
|
|
21
|
+
states;
|
|
22
|
+
version;
|
|
23
|
+
constructor() {
|
|
24
|
+
this.stateMap = new Map();
|
|
25
|
+
this.states = [];
|
|
26
|
+
this.version = 0;
|
|
27
|
+
}
|
|
28
|
+
updateVersion() {
|
|
29
|
+
this.version += 1;
|
|
30
|
+
}
|
|
31
|
+
acquire(contact) {
|
|
32
|
+
let state = this.get(contact.actor1, contact.actor2);
|
|
33
|
+
if (!state) {
|
|
34
|
+
state = this.createState(contact);
|
|
35
|
+
this.set(contact.actor1, contact.actor2, state);
|
|
36
|
+
this.set(contact.actor2, contact.actor1, state);
|
|
37
|
+
this.states.push(state);
|
|
38
|
+
}
|
|
39
|
+
else {
|
|
40
|
+
state.contact = contact;
|
|
41
|
+
state.actor1 = contact.actor1;
|
|
42
|
+
state.actor2 = contact.actor2;
|
|
43
|
+
}
|
|
44
|
+
if (!this.canPreserveImpulses(state, contact)) {
|
|
45
|
+
this.clearWarmStartImpulses(state);
|
|
46
|
+
}
|
|
47
|
+
this.clearFrameImpulses(state);
|
|
48
|
+
this.updateContactIdentity(state, contact);
|
|
49
|
+
state.version = this.version;
|
|
50
|
+
return state;
|
|
51
|
+
}
|
|
52
|
+
pruneStaleStates() {
|
|
53
|
+
let stateIndex = 0;
|
|
54
|
+
for (const state of this.states) {
|
|
55
|
+
if (state.version === this.version ||
|
|
56
|
+
(state.bodyA.sleeping && state.bodyB.sleeping)) {
|
|
57
|
+
this.states[stateIndex] = state;
|
|
58
|
+
stateIndex += 1;
|
|
59
|
+
continue;
|
|
60
|
+
}
|
|
61
|
+
this.delete(state.actor1, state.actor2);
|
|
62
|
+
this.delete(state.actor2, state.actor1);
|
|
63
|
+
}
|
|
64
|
+
this.states.length = stateIndex;
|
|
65
|
+
}
|
|
66
|
+
forEach(callback) {
|
|
67
|
+
this.states.forEach(callback);
|
|
68
|
+
}
|
|
69
|
+
clearWarmStartImpulses(state) {
|
|
70
|
+
state.point0.normalImpulse = 0;
|
|
71
|
+
state.point0.tangentImpulse = 0;
|
|
72
|
+
state.point1.normalImpulse = 0;
|
|
73
|
+
state.point1.tangentImpulse = 0;
|
|
74
|
+
}
|
|
75
|
+
clearFrameImpulses(state) {
|
|
76
|
+
state.point0.biasImpulse = 0;
|
|
77
|
+
state.point1.biasImpulse = 0;
|
|
78
|
+
}
|
|
79
|
+
get(actor1, actor2) {
|
|
80
|
+
return this.stateMap.get(actor1)?.get(actor2);
|
|
81
|
+
}
|
|
82
|
+
set(actor1, actor2, state) {
|
|
83
|
+
let actorStates = this.stateMap.get(actor1);
|
|
84
|
+
if (!actorStates) {
|
|
85
|
+
actorStates = new Map();
|
|
86
|
+
this.stateMap.set(actor1, actorStates);
|
|
87
|
+
}
|
|
88
|
+
actorStates.set(actor2, state);
|
|
89
|
+
}
|
|
90
|
+
delete(actor1, actor2) {
|
|
91
|
+
const actorStates = this.stateMap.get(actor1);
|
|
92
|
+
if (!actorStates) {
|
|
93
|
+
return;
|
|
94
|
+
}
|
|
95
|
+
actorStates.delete(actor2);
|
|
96
|
+
if (actorStates.size === 0) {
|
|
97
|
+
this.stateMap.delete(actor1);
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
createState(contact) {
|
|
101
|
+
const rigidBody1 = contact.actor1.getComponent(RigidBody);
|
|
102
|
+
const rigidBody2 = contact.actor2.getComponent(RigidBody);
|
|
103
|
+
return {
|
|
104
|
+
contact,
|
|
105
|
+
actor1: contact.actor1,
|
|
106
|
+
actor2: contact.actor2,
|
|
107
|
+
bodyA: rigidBody1,
|
|
108
|
+
bodyB: rigidBody2,
|
|
109
|
+
invMassA: 0,
|
|
110
|
+
invInertiaA: 0,
|
|
111
|
+
invMassB: 0,
|
|
112
|
+
invInertiaB: 0,
|
|
113
|
+
normalX: contact.normal.x,
|
|
114
|
+
normalY: contact.normal.y,
|
|
115
|
+
tangentX: -contact.normal.y,
|
|
116
|
+
tangentY: contact.normal.x,
|
|
117
|
+
friction: 0,
|
|
118
|
+
restitution: 0,
|
|
119
|
+
k01: 0,
|
|
120
|
+
determinant: 0,
|
|
121
|
+
blockSolvable: false,
|
|
122
|
+
active: false,
|
|
123
|
+
warmStartAllowed: false,
|
|
124
|
+
skipBias: false,
|
|
125
|
+
point0: createContactPoint(),
|
|
126
|
+
point1: createContactPoint(),
|
|
127
|
+
pointCount: 0,
|
|
128
|
+
version: this.version,
|
|
129
|
+
};
|
|
130
|
+
}
|
|
131
|
+
canPreserveImpulses(state, contact) {
|
|
132
|
+
const contactPoints = contact.contactPoints;
|
|
133
|
+
if (state.pointCount !== contactPoints.length) {
|
|
134
|
+
return false;
|
|
135
|
+
}
|
|
136
|
+
if (state.normalX * contact.normal.x + state.normalY * contact.normal.y <
|
|
137
|
+
CONTACT_NORMAL_MIN_DOT) {
|
|
138
|
+
return false;
|
|
139
|
+
}
|
|
140
|
+
if (contactPoints[0] &&
|
|
141
|
+
!this.isPointClose(state.point0.positionX, state.point0.positionY, contactPoints[0].x, contactPoints[0].y)) {
|
|
142
|
+
return false;
|
|
143
|
+
}
|
|
144
|
+
if (contactPoints[1] &&
|
|
145
|
+
!this.isPointClose(state.point1.positionX, state.point1.positionY, contactPoints[1].x, contactPoints[1].y)) {
|
|
146
|
+
return false;
|
|
147
|
+
}
|
|
148
|
+
return true;
|
|
149
|
+
}
|
|
150
|
+
isPointClose(point1X, point1Y, point2X, point2Y) {
|
|
151
|
+
const distanceX = point1X - point2X;
|
|
152
|
+
const distanceY = point1Y - point2Y;
|
|
153
|
+
return (distanceX * distanceX + distanceY * distanceY <=
|
|
154
|
+
CONTACT_POINT_MAX_DISTANCE_SQUARED);
|
|
155
|
+
}
|
|
156
|
+
updateContactIdentity(state, contact) {
|
|
157
|
+
const contactPoints = contact.contactPoints;
|
|
158
|
+
state.normalX = contact.normal.x;
|
|
159
|
+
state.normalY = contact.normal.y;
|
|
160
|
+
state.pointCount = contactPoints.length;
|
|
161
|
+
if (contactPoints[0]) {
|
|
162
|
+
state.point0.positionX = contactPoints[0].x;
|
|
163
|
+
state.point0.positionY = contactPoints[0].y;
|
|
164
|
+
}
|
|
165
|
+
if (contactPoints[1]) {
|
|
166
|
+
state.point1.positionX = contactPoints[1].x;
|
|
167
|
+
state.point1.positionY = contactPoints[1].y;
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import type { Actor } from '../../../../../engine/actor';
|
|
2
|
+
import { type Vector2 } from '../../../../../engine/math-lib';
|
|
3
|
+
import type { Contact } from '../collision-detection/types';
|
|
4
|
+
export declare const shouldWakeSleepingContact: (contact: Contact, contactSpeedThreshold: number) => boolean;
|
|
5
|
+
export declare const isSleepSupportContact: (contact: Contact, actor: Actor, gravity: Vector2) => boolean;
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { VectorOps } from '../../../../../engine/math-lib';
|
|
2
|
+
import { RigidBody } from '../../../../components/rigid-body';
|
|
3
|
+
import { Transform } from '../../../../components/transform';
|
|
4
|
+
import { SUPPORT_MIN_GRAVITY_DOT } from '../../consts';
|
|
5
|
+
const getMinNormalVelocity = (contact) => {
|
|
6
|
+
const rigidBody1 = contact.actor1.getComponent(RigidBody);
|
|
7
|
+
const rigidBody2 = contact.actor2.getComponent(RigidBody);
|
|
8
|
+
const transform1 = contact.actor1.getComponent(Transform);
|
|
9
|
+
const transform2 = contact.actor2.getComponent(Transform);
|
|
10
|
+
const { normal } = contact;
|
|
11
|
+
let minVelocity = null;
|
|
12
|
+
for (const point of contact.contactPoints) {
|
|
13
|
+
const anchor1X = point.x - transform1.world.position.x;
|
|
14
|
+
const anchor1Y = point.y - transform1.world.position.y;
|
|
15
|
+
const anchor2X = point.x - transform2.world.position.x;
|
|
16
|
+
const anchor2Y = point.y - transform2.world.position.y;
|
|
17
|
+
const velocity1X = rigidBody1.linearVelocity.x - rigidBody1.angularVelocity * anchor1Y;
|
|
18
|
+
const velocity1Y = rigidBody1.linearVelocity.y + rigidBody1.angularVelocity * anchor1X;
|
|
19
|
+
const velocity2X = rigidBody2.linearVelocity.x - rigidBody2.angularVelocity * anchor2Y;
|
|
20
|
+
const velocity2Y = rigidBody2.linearVelocity.y + rigidBody2.angularVelocity * anchor2X;
|
|
21
|
+
const velocity = (velocity2X - velocity1X) * normal.x +
|
|
22
|
+
(velocity2Y - velocity1Y) * normal.y;
|
|
23
|
+
if (minVelocity === null || velocity < minVelocity) {
|
|
24
|
+
minVelocity = velocity;
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
return minVelocity;
|
|
28
|
+
};
|
|
29
|
+
export const shouldWakeSleepingContact = (contact, contactSpeedThreshold) => {
|
|
30
|
+
const minNormalVelocity = getMinNormalVelocity(contact);
|
|
31
|
+
return (minNormalVelocity !== null && -minNormalVelocity > contactSpeedThreshold);
|
|
32
|
+
};
|
|
33
|
+
export const isSleepSupportContact = (contact, actor, gravity) => {
|
|
34
|
+
const gravityMagnitude = gravity.magnitude;
|
|
35
|
+
if (gravityMagnitude === 0) {
|
|
36
|
+
return false;
|
|
37
|
+
}
|
|
38
|
+
const normalGravityDot = VectorOps.dotProduct(contact.normal, gravity);
|
|
39
|
+
const supportDot = contact.actor1 === actor ? normalGravityDot : -normalGravityDot;
|
|
40
|
+
return supportDot / gravityMagnitude > SUPPORT_MIN_GRAVITY_DOT;
|
|
41
|
+
};
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { RigidBody } from '../../../../components/rigid-body';
|
|
2
|
+
import type { ContactPoint, ContactState } from './contact-state-manager';
|
|
3
|
+
export declare const getContactRestitution: (rigidBody1: RigidBody, rigidBody2: RigidBody) => number;
|
|
4
|
+
export declare const getContactFriction: (rigidBody1: RigidBody, rigidBody2: RigidBody) => number;
|
|
5
|
+
/**
|
|
6
|
+
* Returns the effective mass at a contact point along a unit direction.
|
|
7
|
+
* It represents how strongly the two bodies resist an impulse applied at
|
|
8
|
+
* that point in that direction.
|
|
9
|
+
*/
|
|
10
|
+
export declare const getEffectiveMass: (invMassA: number, invInertiaA: number, anchorAX: number, anchorAY: number, invMassB: number, invInertiaB: number, anchorBX: number, anchorBY: number, directionX: number, directionY: number) => number;
|
|
11
|
+
export declare const getNormalVelocity: (state: ContactState, point: ContactPoint) => number;
|
|
12
|
+
export declare const getTangentVelocity: (state: ContactState, point: ContactPoint) => number;
|
|
13
|
+
export declare const getPrevNormalVelocity: (state: ContactState, point: ContactPoint) => number;
|
|
14
|
+
export declare const getBiasNormalVelocity: (state: ContactState, point: ContactPoint) => number;
|
|
15
|
+
export declare const applyImpulse: (state: ContactState, point: ContactPoint, impulseX: number, impulseY: number) => void;
|
|
16
|
+
export declare const applyBiasImpulse: (state: ContactState, point: ContactPoint, impulseX: number, impulseY: number) => void;
|