dacha 0.18.0-alpha.9 → 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 +8 -0
- package/build/contrib/components/rigid-body/index.js +8 -0
- 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 +3 -1
- package/build/contrib/systems/physics-system/consts.js +4 -1
- package/build/contrib/systems/physics-system/physics-system.js +7 -1
- 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 +130 -124
- 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/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/physics/mass-properties.js +1 -1
- package/build/contrib/systems/physics-system/types.d.ts +12 -2
- package/build/contrib/systems/renderer/actor-render-tree.js +15 -6
- 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/game-loop.js +3 -3
- package/build/engine/math-lib/math/ops.d.ts +16 -0
- package/build/engine/math-lib/math/ops.js +25 -0
- 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/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,47 +1,42 @@
|
|
|
1
1
|
import { ActorQuery } from '../../../../../engine/actor';
|
|
2
|
-
import { Transform, Collider
|
|
2
|
+
import { Transform, Collider } from '../../../../components';
|
|
3
3
|
import { AddActor, RemoveActor } from '../../../../../engine/events';
|
|
4
|
-
import {
|
|
4
|
+
import { Pool } from '../../../../../engine/data-lib';
|
|
5
5
|
import { DynamicAABBTree } from './dynamic-aabb-tree';
|
|
6
6
|
import { geometryBuilders } from './geometry-builders';
|
|
7
7
|
import { aabbBuilders } from './aabb-builders';
|
|
8
8
|
import { intersectionCheckers } from './intersection-checkers';
|
|
9
|
-
import { DispersionCalculator } from './dispersion-calculator';
|
|
10
9
|
import { checkTransform, checkCollider, getOrientationData, } from './reorientation-checkers';
|
|
11
|
-
import { buildQueryProxy, buildActorQueryProxy, raycast, raycastAll, overlap, getOverlapQueryType, shapeCast, shapeCastAll, getShapeCastQueryType, getActorCastQueryType, } from './query-utils';
|
|
10
|
+
import { buildQueryProxy, buildActorQueryProxy, raycast, raycastAll, raycastEach, overlap, overlapEach, getOverlapQueryType, shapeCast, shapeCastAll, shapeCastEach, getShapeCastQueryType, getActorCastQueryType, makeCastHit, makeOverlapHit, } from './query-utils';
|
|
11
|
+
import { isStatic, isDisabled } from './utils';
|
|
12
12
|
export class CollisionDetectionSubsystem {
|
|
13
13
|
actorQuery;
|
|
14
|
-
axis;
|
|
15
14
|
queryTree;
|
|
16
15
|
proxiesByActorId;
|
|
17
16
|
proxyPairs;
|
|
18
17
|
contacts;
|
|
19
18
|
actorIdsToDelete;
|
|
20
19
|
collisionMatrix;
|
|
21
|
-
|
|
20
|
+
candidateBufferPool;
|
|
21
|
+
castHitPool;
|
|
22
|
+
overlapHitPool;
|
|
22
23
|
constructor(options) {
|
|
23
24
|
const settings = options.globalOptions.physics;
|
|
24
25
|
this.actorQuery = new ActorQuery({
|
|
25
26
|
scene: options.scene,
|
|
26
27
|
filter: [Collider, Transform],
|
|
27
28
|
});
|
|
28
|
-
this.axis = {
|
|
29
|
-
x: {
|
|
30
|
-
sortedList: [],
|
|
31
|
-
dispersionCalculator: new DispersionCalculator('x'),
|
|
32
|
-
},
|
|
33
|
-
y: {
|
|
34
|
-
sortedList: [],
|
|
35
|
-
dispersionCalculator: new DispersionCalculator('y'),
|
|
36
|
-
},
|
|
37
|
-
};
|
|
38
29
|
this.queryTree = new DynamicAABBTree();
|
|
39
30
|
this.proxiesByActorId = new Map();
|
|
40
31
|
this.proxyPairs = [];
|
|
41
32
|
this.contacts = [];
|
|
42
33
|
this.actorIdsToDelete = new Set();
|
|
43
34
|
this.collisionMatrix = settings?.collisionMatrix ?? {};
|
|
44
|
-
this.
|
|
35
|
+
this.candidateBufferPool = new Pool(() => [], (buffer) => {
|
|
36
|
+
buffer.length = 0;
|
|
37
|
+
});
|
|
38
|
+
this.castHitPool = new Pool(makeCastHit);
|
|
39
|
+
this.overlapHitPool = new Pool(makeOverlapHit);
|
|
45
40
|
this.actorQuery.getActors().forEach((actor) => this.addProxy(actor));
|
|
46
41
|
this.actorQuery.addEventListener(AddActor, this.handleActorAdd);
|
|
47
42
|
this.actorQuery.addEventListener(RemoveActor, this.handleActorRemove);
|
|
@@ -54,18 +49,15 @@ export class CollisionDetectionSubsystem {
|
|
|
54
49
|
}
|
|
55
50
|
raycast(params) {
|
|
56
51
|
const queryProxy = buildQueryProxy('ray', params);
|
|
57
|
-
this.
|
|
58
|
-
return raycast(queryProxy, this.queryCandidates);
|
|
52
|
+
return this.withCandidates(queryProxy, (candidates) => raycast(queryProxy, candidates));
|
|
59
53
|
}
|
|
60
54
|
raycastAll(params) {
|
|
61
55
|
const queryProxy = buildQueryProxy('ray', params);
|
|
62
|
-
this.
|
|
63
|
-
return raycastAll(queryProxy, this.queryCandidates);
|
|
56
|
+
return this.withCandidates(queryProxy, (candidates) => raycastAll(queryProxy, candidates));
|
|
64
57
|
}
|
|
65
58
|
overlapShape(params) {
|
|
66
59
|
const queryProxy = buildQueryProxy(params.shape.type, params);
|
|
67
|
-
this.
|
|
68
|
-
return overlap(params.shape.type, queryProxy, this.queryCandidates);
|
|
60
|
+
return this.withCandidates(queryProxy, (candidates) => overlap(params.shape.type, queryProxy, candidates));
|
|
69
61
|
}
|
|
70
62
|
overlapActor(params) {
|
|
71
63
|
const queryType = getOverlapQueryType(params);
|
|
@@ -73,20 +65,17 @@ export class CollisionDetectionSubsystem {
|
|
|
73
65
|
return [];
|
|
74
66
|
}
|
|
75
67
|
const queryProxy = buildActorQueryProxy(queryType, params);
|
|
76
|
-
this.
|
|
77
|
-
return overlap(queryType, queryProxy, this.queryCandidates);
|
|
68
|
+
return this.withCandidates(queryProxy, (candidates) => overlap(queryType, queryProxy, candidates));
|
|
78
69
|
}
|
|
79
70
|
shapeCast(params) {
|
|
80
71
|
const queryType = getShapeCastQueryType(params);
|
|
81
72
|
const queryProxy = buildQueryProxy(queryType, params);
|
|
82
|
-
this.
|
|
83
|
-
return shapeCast(queryType, queryProxy, this.queryCandidates);
|
|
73
|
+
return this.withCandidates(queryProxy, (candidates) => shapeCast(queryType, queryProxy, candidates));
|
|
84
74
|
}
|
|
85
75
|
shapeCastAll(params) {
|
|
86
76
|
const queryType = getShapeCastQueryType(params);
|
|
87
77
|
const queryProxy = buildQueryProxy(queryType, params);
|
|
88
|
-
this.
|
|
89
|
-
return shapeCastAll(queryType, queryProxy, this.queryCandidates);
|
|
78
|
+
return this.withCandidates(queryProxy, (candidates) => shapeCastAll(queryType, queryProxy, candidates));
|
|
90
79
|
}
|
|
91
80
|
castActor(params) {
|
|
92
81
|
const queryType = getActorCastQueryType(params);
|
|
@@ -94,8 +83,7 @@ export class CollisionDetectionSubsystem {
|
|
|
94
83
|
return null;
|
|
95
84
|
}
|
|
96
85
|
const queryProxy = buildActorQueryProxy(queryType, params);
|
|
97
|
-
this.
|
|
98
|
-
return shapeCast(queryType, queryProxy, this.queryCandidates);
|
|
86
|
+
return this.withCandidates(queryProxy, (candidates) => shapeCast(queryType, queryProxy, candidates));
|
|
99
87
|
}
|
|
100
88
|
castActorAll(params) {
|
|
101
89
|
const queryType = getActorCastQueryType(params);
|
|
@@ -103,8 +91,76 @@ export class CollisionDetectionSubsystem {
|
|
|
103
91
|
return [];
|
|
104
92
|
}
|
|
105
93
|
const queryProxy = buildActorQueryProxy(queryType, params);
|
|
106
|
-
this.
|
|
107
|
-
|
|
94
|
+
return this.withCandidates(queryProxy, (candidates) => shapeCastAll(queryType, queryProxy, candidates));
|
|
95
|
+
}
|
|
96
|
+
raycastEach(params, callback) {
|
|
97
|
+
const queryProxy = buildQueryProxy('ray', params);
|
|
98
|
+
this.withCandidates(queryProxy, (candidates) => {
|
|
99
|
+
const hit = this.castHitPool.acquire();
|
|
100
|
+
try {
|
|
101
|
+
raycastEach(queryProxy, candidates, hit, callback);
|
|
102
|
+
}
|
|
103
|
+
finally {
|
|
104
|
+
this.castHitPool.release(hit);
|
|
105
|
+
}
|
|
106
|
+
});
|
|
107
|
+
}
|
|
108
|
+
shapeCastEach(params, callback) {
|
|
109
|
+
const queryType = getShapeCastQueryType(params);
|
|
110
|
+
const queryProxy = buildQueryProxy(queryType, params);
|
|
111
|
+
this.withCandidates(queryProxy, (candidates) => {
|
|
112
|
+
const hit = this.castHitPool.acquire();
|
|
113
|
+
try {
|
|
114
|
+
shapeCastEach(queryType, queryProxy, candidates, hit, callback);
|
|
115
|
+
}
|
|
116
|
+
finally {
|
|
117
|
+
this.castHitPool.release(hit);
|
|
118
|
+
}
|
|
119
|
+
});
|
|
120
|
+
}
|
|
121
|
+
overlapEach(params, callback) {
|
|
122
|
+
const queryProxy = buildQueryProxy(params.shape.type, params);
|
|
123
|
+
this.withCandidates(queryProxy, (candidates) => {
|
|
124
|
+
const hit = this.overlapHitPool.acquire();
|
|
125
|
+
try {
|
|
126
|
+
overlapEach(params.shape.type, queryProxy, candidates, hit, callback);
|
|
127
|
+
}
|
|
128
|
+
finally {
|
|
129
|
+
this.overlapHitPool.release(hit);
|
|
130
|
+
}
|
|
131
|
+
});
|
|
132
|
+
}
|
|
133
|
+
castActorEach(params, callback) {
|
|
134
|
+
const queryType = getActorCastQueryType(params);
|
|
135
|
+
if (!queryType) {
|
|
136
|
+
return;
|
|
137
|
+
}
|
|
138
|
+
const queryProxy = buildActorQueryProxy(queryType, params);
|
|
139
|
+
this.withCandidates(queryProxy, (candidates) => {
|
|
140
|
+
const hit = this.castHitPool.acquire();
|
|
141
|
+
try {
|
|
142
|
+
shapeCastEach(queryType, queryProxy, candidates, hit, callback);
|
|
143
|
+
}
|
|
144
|
+
finally {
|
|
145
|
+
this.castHitPool.release(hit);
|
|
146
|
+
}
|
|
147
|
+
});
|
|
148
|
+
}
|
|
149
|
+
overlapActorEach(params, callback) {
|
|
150
|
+
const queryType = getOverlapQueryType(params);
|
|
151
|
+
if (!queryType) {
|
|
152
|
+
return;
|
|
153
|
+
}
|
|
154
|
+
const queryProxy = buildActorQueryProxy(queryType, params);
|
|
155
|
+
this.withCandidates(queryProxy, (candidates) => {
|
|
156
|
+
const hit = this.overlapHitPool.acquire();
|
|
157
|
+
try {
|
|
158
|
+
overlapEach(queryType, queryProxy, candidates, hit, callback);
|
|
159
|
+
}
|
|
160
|
+
finally {
|
|
161
|
+
this.overlapHitPool.release(hit);
|
|
162
|
+
}
|
|
163
|
+
});
|
|
108
164
|
}
|
|
109
165
|
handleActorAdd = (event) => {
|
|
110
166
|
this.addProxy(event.actor);
|
|
@@ -138,10 +194,6 @@ export class CollisionDetectionSubsystem {
|
|
|
138
194
|
layer: collider.layer,
|
|
139
195
|
};
|
|
140
196
|
proxy.treeEntryId = this.queryTree.insert(aabb, proxy);
|
|
141
|
-
this.axis.x.dispersionCalculator.addToSample(aabb);
|
|
142
|
-
this.addToSortedList(proxy, 'x');
|
|
143
|
-
this.axis.y.dispersionCalculator.addToSample(aabb);
|
|
144
|
-
this.addToSortedList(proxy, 'y');
|
|
145
197
|
this.proxiesByActorId.set(actor.id, proxy);
|
|
146
198
|
}
|
|
147
199
|
updateProxy(actor) {
|
|
@@ -150,72 +202,34 @@ export class CollisionDetectionSubsystem {
|
|
|
150
202
|
const geometry = geometryBuilders[collider.shape.type](collider, transform);
|
|
151
203
|
const aabb = aabbBuilders[collider.shape.type](geometry);
|
|
152
204
|
const proxy = this.proxiesByActorId.get(actor.id);
|
|
153
|
-
const prevAABB = proxy.aabb;
|
|
154
205
|
proxy.aabb = aabb;
|
|
155
206
|
proxy.geometry = geometry;
|
|
156
207
|
proxy.orientationData = getOrientationData(actor);
|
|
157
208
|
proxy.layer = collider.layer;
|
|
158
209
|
this.queryTree.update(proxy.treeEntryId, aabb);
|
|
159
|
-
this.axis.x.dispersionCalculator.removeFromSample(prevAABB);
|
|
160
|
-
this.axis.x.dispersionCalculator.addToSample(aabb);
|
|
161
|
-
this.updateSortedList(proxy, 'x');
|
|
162
|
-
this.axis.y.dispersionCalculator.removeFromSample(prevAABB);
|
|
163
|
-
this.axis.y.dispersionCalculator.addToSample(aabb);
|
|
164
|
-
this.updateSortedList(proxy, 'y');
|
|
165
|
-
}
|
|
166
|
-
addToSortedList(proxy, axis) {
|
|
167
|
-
const min = { value: proxy.aabb.min[axis], proxy };
|
|
168
|
-
const max = { value: proxy.aabb.max[axis], proxy };
|
|
169
|
-
this.axis[axis].sortedList.push(min, max);
|
|
170
|
-
proxy.edges ??= {};
|
|
171
|
-
proxy.edges[axis] = [min, max];
|
|
172
|
-
}
|
|
173
|
-
updateSortedList(proxy, axis) {
|
|
174
|
-
const [min, max] = proxy.edges[axis];
|
|
175
|
-
min.value = proxy.aabb.min[axis];
|
|
176
|
-
min.proxy = proxy;
|
|
177
|
-
max.value = proxy.aabb.max[axis];
|
|
178
|
-
max.proxy = proxy;
|
|
179
|
-
}
|
|
180
|
-
clearSortedList(axis) {
|
|
181
|
-
this.axis[axis].sortedList = this.axis[axis].sortedList.filter((item) => !this.actorIdsToDelete.has(item.proxy.actor.id));
|
|
182
|
-
}
|
|
183
|
-
getAxes() {
|
|
184
|
-
const xDispersion = this.axis.x.dispersionCalculator.getDispersion();
|
|
185
|
-
const yDispersion = this.axis.y.dispersionCalculator.getDispersion();
|
|
186
|
-
return xDispersion >= yDispersion ? ['x', 'y'] : ['y', 'x'];
|
|
187
|
-
}
|
|
188
|
-
areStaticBodies(proxy1, proxy2) {
|
|
189
|
-
const { actor: actor1 } = proxy1;
|
|
190
|
-
const { actor: actor2 } = proxy2;
|
|
191
|
-
const rigidBody1 = actor1.getComponent(RigidBody);
|
|
192
|
-
const rigidBody2 = actor2.getComponent(RigidBody);
|
|
193
|
-
return rigidBody1?.type === 'static' && rigidBody2?.type === 'static';
|
|
194
|
-
}
|
|
195
|
-
testAABB(proxy1, proxy2, axis) {
|
|
196
|
-
const aabb1 = proxy1.aabb;
|
|
197
|
-
const aabb2 = proxy2.aabb;
|
|
198
|
-
return (aabb1.max[axis] >= aabb2.min[axis] && aabb1.min[axis] <= aabb2.max[axis]);
|
|
199
210
|
}
|
|
200
211
|
testCollisionLayers(proxy1, proxy2) {
|
|
201
212
|
return (this.collisionMatrix[proxy1.layer]?.[proxy2.layer] ??
|
|
202
213
|
this.collisionMatrix[proxy2.layer]?.[proxy1.layer] ??
|
|
203
214
|
true);
|
|
204
215
|
}
|
|
205
|
-
|
|
206
|
-
const
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
216
|
+
withCandidates(queryProxy, run) {
|
|
217
|
+
const candidates = this.candidateBufferPool.acquire();
|
|
218
|
+
try {
|
|
219
|
+
this.collectQueryCandidates(queryProxy, candidates);
|
|
220
|
+
return run(candidates);
|
|
221
|
+
}
|
|
222
|
+
finally {
|
|
223
|
+
this.candidateBufferPool.release(candidates);
|
|
224
|
+
}
|
|
211
225
|
}
|
|
212
|
-
collectQueryCandidates(queryProxy) {
|
|
226
|
+
collectQueryCandidates(queryProxy, out) {
|
|
213
227
|
let candidateIndex = 0;
|
|
214
228
|
this.queryTree.query(queryProxy.aabb, (proxy) => {
|
|
215
229
|
if (queryProxy.excludedActors?.has(proxy.actor)) {
|
|
216
230
|
return;
|
|
217
231
|
}
|
|
218
|
-
if (
|
|
232
|
+
if (isDisabled(proxy)) {
|
|
219
233
|
return;
|
|
220
234
|
}
|
|
221
235
|
if (queryProxy.layer !== undefined &&
|
|
@@ -225,44 +239,40 @@ export class CollisionDetectionSubsystem {
|
|
|
225
239
|
if (queryProxy.actorFilter && !queryProxy.actorFilter(proxy.actor)) {
|
|
226
240
|
return;
|
|
227
241
|
}
|
|
228
|
-
|
|
242
|
+
out[candidateIndex] = proxy;
|
|
229
243
|
candidateIndex += 1;
|
|
230
244
|
});
|
|
231
|
-
|
|
245
|
+
out.length = candidateIndex;
|
|
232
246
|
}
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
let proxyPairIndex = 0;
|
|
239
|
-
for (const item of sortedList) {
|
|
240
|
-
const { proxy } = item;
|
|
241
|
-
if (!activeProxies.has(proxy)) {
|
|
242
|
-
activeProxies.forEach((activeProxy) => {
|
|
243
|
-
if (!this.testState(proxy, activeProxy)) {
|
|
244
|
-
return;
|
|
245
|
-
}
|
|
246
|
-
if (!this.testAABB(proxy, activeProxy, secondAxis)) {
|
|
247
|
-
return;
|
|
248
|
-
}
|
|
249
|
-
if (this.areStaticBodies(proxy, activeProxy)) {
|
|
250
|
-
return;
|
|
251
|
-
}
|
|
252
|
-
if (!this.testCollisionLayers(proxy, activeProxy)) {
|
|
253
|
-
return;
|
|
254
|
-
}
|
|
255
|
-
this.proxyPairs[proxyPairIndex] = [proxy, activeProxy];
|
|
256
|
-
proxyPairIndex += 1;
|
|
257
|
-
});
|
|
258
|
-
activeProxies.add(proxy);
|
|
247
|
+
collectPairs() {
|
|
248
|
+
let pairIndex = 0;
|
|
249
|
+
this.proxiesByActorId.forEach((proxy) => {
|
|
250
|
+
if (isStatic(proxy)) {
|
|
251
|
+
return;
|
|
259
252
|
}
|
|
260
|
-
|
|
261
|
-
|
|
253
|
+
if (isDisabled(proxy)) {
|
|
254
|
+
return;
|
|
262
255
|
}
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
256
|
+
this.queryTree.query(proxy.aabb, (other) => {
|
|
257
|
+
if (other === proxy) {
|
|
258
|
+
return;
|
|
259
|
+
}
|
|
260
|
+
// Deduplicate dynamic-dynamic pairs
|
|
261
|
+
if (!isStatic(other) && proxy.treeEntryId >= other.treeEntryId) {
|
|
262
|
+
return;
|
|
263
|
+
}
|
|
264
|
+
if (isDisabled(other)) {
|
|
265
|
+
return;
|
|
266
|
+
}
|
|
267
|
+
if (!this.testCollisionLayers(proxy, other)) {
|
|
268
|
+
return;
|
|
269
|
+
}
|
|
270
|
+
this.proxyPairs[pairIndex] = [proxy, other];
|
|
271
|
+
pairIndex += 1;
|
|
272
|
+
});
|
|
273
|
+
});
|
|
274
|
+
if (this.proxyPairs.length > pairIndex) {
|
|
275
|
+
this.proxyPairs.length = pairIndex;
|
|
266
276
|
}
|
|
267
277
|
}
|
|
268
278
|
checkOnIntersection(proxyPair) {
|
|
@@ -293,13 +303,9 @@ export class CollisionDetectionSubsystem {
|
|
|
293
303
|
if (this.actorIdsToDelete.size === 0) {
|
|
294
304
|
return;
|
|
295
305
|
}
|
|
296
|
-
this.clearSortedList('x');
|
|
297
|
-
this.clearSortedList('y');
|
|
298
306
|
this.actorIdsToDelete.forEach((id) => {
|
|
299
307
|
const proxy = this.proxiesByActorId.get(id);
|
|
300
308
|
this.queryTree.remove(proxy.treeEntryId);
|
|
301
|
-
this.axis.x.dispersionCalculator.removeFromSample(proxy.aabb);
|
|
302
|
-
this.axis.y.dispersionCalculator.removeFromSample(proxy.aabb);
|
|
303
309
|
this.proxiesByActorId.delete(id);
|
|
304
310
|
});
|
|
305
311
|
this.actorIdsToDelete.clear();
|
|
@@ -312,7 +318,7 @@ export class CollisionDetectionSubsystem {
|
|
|
312
318
|
}
|
|
313
319
|
this.updateProxy(actor);
|
|
314
320
|
});
|
|
315
|
-
this.
|
|
321
|
+
this.collectPairs();
|
|
316
322
|
let contactIndex = 0;
|
|
317
323
|
this.proxyPairs.forEach((proxyPair) => {
|
|
318
324
|
const intersection = this.checkOnIntersection(proxyPair);
|
package/build/contrib/systems/physics-system/subsystems/collision-detection/query-utils.d.ts
CHANGED
|
@@ -10,9 +10,14 @@ export declare function buildActorQueryProxy(type: OverlapQueryType, params: Ove
|
|
|
10
10
|
export declare const getOverlapQueryType: (params: OverlapActorParams) => OverlapQueryType | null;
|
|
11
11
|
export declare const getShapeCastQueryType: (params: ShapeCastParams) => ShapeCastQueryType;
|
|
12
12
|
export declare const getActorCastQueryType: (params: CastActorParams) => ShapeCastQueryType | null;
|
|
13
|
+
export declare const makeCastHit: () => CastHit;
|
|
14
|
+
export declare const makeOverlapHit: () => OverlapHit;
|
|
13
15
|
export declare const overlap: (type: OverlapQueryType, queryProxy: QueryProxy, proxies: Iterable<ActorProxy>) => OverlapHit[];
|
|
14
16
|
export declare const raycast: (queryProxy: QueryProxy, proxies: Iterable<ActorProxy>) => CastHit | null;
|
|
15
17
|
export declare const raycastAll: (queryProxy: QueryProxy, proxies: Iterable<ActorProxy>) => CastHit[];
|
|
16
18
|
export declare const shapeCast: (type: ShapeCastQueryType, queryProxy: QueryProxy, proxies: Iterable<ActorProxy>) => CastHit | null;
|
|
17
19
|
export declare const shapeCastAll: (type: ShapeCastQueryType, queryProxy: QueryProxy, proxies: Iterable<ActorProxy>) => CastHit[];
|
|
20
|
+
export declare const raycastEach: (queryProxy: QueryProxy, proxies: Iterable<ActorProxy>, hit: CastHit, callback: (hit: CastHit) => void) => void;
|
|
21
|
+
export declare const shapeCastEach: (type: ShapeCastQueryType, queryProxy: QueryProxy, proxies: Iterable<ActorProxy>, hit: CastHit, callback: (hit: CastHit) => void) => void;
|
|
22
|
+
export declare const overlapEach: (type: OverlapQueryType, queryProxy: QueryProxy, proxies: Iterable<ActorProxy>, hit: OverlapHit, callback: (hit: OverlapHit) => void) => void;
|
|
18
23
|
export {};
|
|
@@ -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,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;
|