dacha 0.18.0-alpha.4 → 0.18.0-alpha.6
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/audio-source/index.d.ts +1 -1
- package/build/contrib/components/audio-source/index.js +1 -1
- package/build/contrib/components/character-body/index.d.ts +72 -0
- package/build/contrib/components/character-body/index.js +90 -0
- package/build/contrib/components/collider/index.d.ts +9 -9
- package/build/contrib/components/collider/index.js +6 -6
- package/build/contrib/components/index.d.ts +1 -0
- package/build/contrib/components/index.js +1 -0
- package/build/contrib/events/index.d.ts +19 -39
- package/build/contrib/events/index.js +3 -21
- package/build/contrib/systems/audio-system/api.d.ts +38 -0
- package/build/contrib/systems/audio-system/api.js +44 -0
- package/build/contrib/systems/audio-system/index.d.ts +4 -3
- package/build/contrib/systems/audio-system/index.js +24 -30
- package/build/contrib/systems/character-controller/index.d.ts +32 -0
- package/build/contrib/systems/character-controller/index.js +262 -0
- package/build/contrib/systems/character-controller/utils.d.ts +2 -0
- package/build/contrib/systems/character-controller/utils.js +9 -0
- package/build/contrib/systems/index.d.ts +2 -1
- package/build/contrib/systems/index.js +2 -1
- package/build/contrib/systems/physics-system/api.d.ts +50 -8
- package/build/contrib/systems/physics-system/api.js +51 -10
- package/build/contrib/systems/physics-system/physics-system.d.ts +1 -0
- package/build/contrib/systems/physics-system/physics-system.js +22 -3
- package/build/contrib/systems/physics-system/subsystems/collision-detection/geometry-builders/build-box-cast-geometry.d.ts +4 -2
- package/build/contrib/systems/physics-system/subsystems/collision-detection/geometry-builders/build-box-cast-geometry.js +7 -4
- package/build/contrib/systems/physics-system/subsystems/collision-detection/geometry-builders/build-box-geometry.d.ts +4 -4
- package/build/contrib/systems/physics-system/subsystems/collision-detection/geometry-builders/build-box-geometry.js +22 -22
- package/build/contrib/systems/physics-system/subsystems/collision-detection/geometry-builders/build-capsule-cast-geometry.d.ts +4 -2
- package/build/contrib/systems/physics-system/subsystems/collision-detection/geometry-builders/build-capsule-cast-geometry.js +14 -10
- package/build/contrib/systems/physics-system/subsystems/collision-detection/geometry-builders/build-capsule-geometry.d.ts +4 -4
- package/build/contrib/systems/physics-system/subsystems/collision-detection/geometry-builders/build-capsule-geometry.js +27 -15
- package/build/contrib/systems/physics-system/subsystems/collision-detection/geometry-builders/build-circle-cast-geometry.d.ts +4 -2
- package/build/contrib/systems/physics-system/subsystems/collision-detection/geometry-builders/build-circle-cast-geometry.js +10 -6
- package/build/contrib/systems/physics-system/subsystems/collision-detection/geometry-builders/build-circle-geometry.d.ts +4 -4
- package/build/contrib/systems/physics-system/subsystems/collision-detection/geometry-builders/build-circle-geometry.js +24 -18
- package/build/contrib/systems/physics-system/subsystems/collision-detection/geometry-builders/build-ray-geometry.js +1 -1
- package/build/contrib/systems/physics-system/subsystems/collision-detection/geometry-builders/build-segment-geometry.d.ts +2 -2
- package/build/contrib/systems/physics-system/subsystems/collision-detection/geometry-builders/build-segment-geometry.js +9 -5
- package/build/contrib/systems/physics-system/subsystems/collision-detection/geometry-builders/index.d.ts +2 -2
- package/build/contrib/systems/physics-system/subsystems/collision-detection/index.d.ts +5 -3
- package/build/contrib/systems/physics-system/subsystems/collision-detection/index.js +34 -1
- package/build/contrib/systems/physics-system/subsystems/collision-detection/query-utils.d.ts +8 -5
- package/build/contrib/systems/physics-system/subsystems/collision-detection/query-utils.js +116 -48
- package/build/contrib/systems/physics-system/subsystems/collision-detection/types.d.ts +7 -0
- package/build/contrib/systems/physics-system/subsystems/constraint-solver/index.d.ts +2 -5
- package/build/contrib/systems/physics-system/subsystems/constraint-solver/index.js +11 -45
- package/build/contrib/systems/physics-system/subsystems/physics/index.d.ts +9 -3
- package/build/contrib/systems/physics-system/subsystems/physics/index.js +8 -5
- package/build/contrib/systems/physics-system/tests/helpers.d.ts +1 -1
- package/build/contrib/systems/physics-system/tests/helpers.js +3 -2
- package/build/contrib/systems/physics-system/types.d.ts +87 -43
- package/build/contrib/systems/renderer/builders/shape-builder/utils.js +38 -62
- package/build/contrib/utils/one-way-validator.d.ts +12 -0
- package/build/contrib/utils/one-way-validator.js +53 -0
- package/build/engine/consts.d.ts +2 -0
- package/build/engine/consts.js +2 -0
- package/build/engine/game-loop.d.ts +6 -2
- package/build/engine/game-loop.js +27 -6
- package/build/engine/math-lib/vector/vector2.d.ts +8 -0
- package/build/engine/math-lib/vector/vector2.js +11 -1
- package/build/events/index.d.ts +2 -2
- package/build/events/index.js +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1,262 @@
|
|
|
1
|
+
import { ActorQuery } from '../../../engine/actor';
|
|
2
|
+
import { SceneSystem } from '../../../engine/system';
|
|
3
|
+
import { Vector2, VectorOps } from '../../../engine/math-lib';
|
|
4
|
+
import { Collider, CharacterBody, RigidBody, Transform, } from '../../components';
|
|
5
|
+
import { PhysicsAPI } from '../physics-system';
|
|
6
|
+
import { OneWayValidator } from '../../utils/one-way-validator';
|
|
7
|
+
import { CharacterHit } from '../../events';
|
|
8
|
+
import { clipAgainstNormal } from './utils';
|
|
9
|
+
const DISTANCE_EPSILON = 0.000001;
|
|
10
|
+
const SNAP_EPSILON = 0.000001;
|
|
11
|
+
/**
|
|
12
|
+
* Kinematic character controller system with sweep/slide collision movement.
|
|
13
|
+
*
|
|
14
|
+
* The system expects actors to have `CharacterBody`, `Transform`,
|
|
15
|
+
* `Collider`, and a kinematic `RigidBody`. Put this system before
|
|
16
|
+
* `PhysicsSystem` in system configuration so `movePosition()` targets are
|
|
17
|
+
* consumed by physics in the same fixed step.
|
|
18
|
+
*
|
|
19
|
+
* @category Systems
|
|
20
|
+
*/
|
|
21
|
+
export class CharacterController extends SceneSystem {
|
|
22
|
+
actorQuery;
|
|
23
|
+
world;
|
|
24
|
+
oneWayValidator;
|
|
25
|
+
constructor(options) {
|
|
26
|
+
super();
|
|
27
|
+
this.world = options.world;
|
|
28
|
+
this.actorQuery = new ActorQuery({
|
|
29
|
+
scene: options.scene,
|
|
30
|
+
filter: [CharacterBody, Transform, Collider, RigidBody],
|
|
31
|
+
});
|
|
32
|
+
this.oneWayValidator = new OneWayValidator();
|
|
33
|
+
}
|
|
34
|
+
onSceneDestroy() {
|
|
35
|
+
this.actorQuery.destroy();
|
|
36
|
+
}
|
|
37
|
+
isBlockingHit(actor, hit) {
|
|
38
|
+
const rigidBody = hit.actor.getComponent(RigidBody);
|
|
39
|
+
if (!rigidBody || rigidBody.disabled) {
|
|
40
|
+
return false;
|
|
41
|
+
}
|
|
42
|
+
if (!rigidBody?.oneWay || !rigidBody.oneWayNormal) {
|
|
43
|
+
return true;
|
|
44
|
+
}
|
|
45
|
+
return this.oneWayValidator.validate(hit.actor, actor, hit.normal);
|
|
46
|
+
}
|
|
47
|
+
isWalkable(actor, normal) {
|
|
48
|
+
const character = actor.getComponent(CharacterBody);
|
|
49
|
+
return (VectorOps.dotProduct(normal, character.upDirection) >=
|
|
50
|
+
Math.cos(character.maxSlopeAngle));
|
|
51
|
+
}
|
|
52
|
+
isRecoverableOverlap(actor, hit) {
|
|
53
|
+
const rigidBody = hit.actor.getComponent(RigidBody);
|
|
54
|
+
if (!rigidBody || rigidBody.disabled || rigidBody.type === 'dynamic') {
|
|
55
|
+
return false;
|
|
56
|
+
}
|
|
57
|
+
if (!rigidBody.oneWay || !rigidBody.oneWayNormal) {
|
|
58
|
+
return true;
|
|
59
|
+
}
|
|
60
|
+
return this.oneWayValidator.validate(hit.actor, actor, hit.normal);
|
|
61
|
+
}
|
|
62
|
+
resetGroundState(character) {
|
|
63
|
+
if (character.onGround) {
|
|
64
|
+
character.groundActor = null;
|
|
65
|
+
character.groundNormal = character.upDirection.clone();
|
|
66
|
+
character.onGround = false;
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
resetState(character) {
|
|
70
|
+
this.resetGroundState(character);
|
|
71
|
+
character.onWall = false;
|
|
72
|
+
character.onCeiling = false;
|
|
73
|
+
}
|
|
74
|
+
cast(actor, position, displacement, hitFilter) {
|
|
75
|
+
if (displacement.squaredMagnitude <= DISTANCE_EPSILON) {
|
|
76
|
+
return null;
|
|
77
|
+
}
|
|
78
|
+
const physicsApi = this.world.systemApi.get(PhysicsAPI);
|
|
79
|
+
const character = actor.getComponent(CharacterBody);
|
|
80
|
+
const transform = actor.getComponent(Transform);
|
|
81
|
+
const distance = displacement.magnitude;
|
|
82
|
+
return physicsApi.castActor({
|
|
83
|
+
actor,
|
|
84
|
+
offset: {
|
|
85
|
+
x: position.x - transform.world.position.x,
|
|
86
|
+
y: position.y - transform.world.position.y,
|
|
87
|
+
},
|
|
88
|
+
direction: displacement,
|
|
89
|
+
maxDistance: distance + character.skinWidth,
|
|
90
|
+
hitFilter,
|
|
91
|
+
});
|
|
92
|
+
}
|
|
93
|
+
castMotion(actor, position, displacement) {
|
|
94
|
+
return this.cast(actor, position, displacement, (hit) => {
|
|
95
|
+
if (hit.distance <= DISTANCE_EPSILON &&
|
|
96
|
+
VectorOps.dotProduct(displacement, hit.normal) > DISTANCE_EPSILON) {
|
|
97
|
+
return false;
|
|
98
|
+
}
|
|
99
|
+
return this.isBlockingHit(actor, hit);
|
|
100
|
+
});
|
|
101
|
+
}
|
|
102
|
+
castGround(actor, position, displacement) {
|
|
103
|
+
return this.cast(actor, position, displacement, (hit) => this.isBlockingHit(actor, hit) && this.isWalkable(actor, hit.normal));
|
|
104
|
+
}
|
|
105
|
+
recoverOverlaps(actor, position) {
|
|
106
|
+
const character = actor.getComponent(CharacterBody);
|
|
107
|
+
if (!character._needsRecovery) {
|
|
108
|
+
return;
|
|
109
|
+
}
|
|
110
|
+
const transform = actor.getComponent(Transform);
|
|
111
|
+
const physicsApi = this.world.systemApi.get(PhysicsAPI);
|
|
112
|
+
for (let i = 0; i < character.maxRecoveries; i += 1) {
|
|
113
|
+
const hits = physicsApi.overlapActor({
|
|
114
|
+
actor,
|
|
115
|
+
offset: {
|
|
116
|
+
x: position.x - transform.world.position.x,
|
|
117
|
+
y: position.y - transform.world.position.y,
|
|
118
|
+
},
|
|
119
|
+
});
|
|
120
|
+
let recovered = false;
|
|
121
|
+
for (const hit of hits) {
|
|
122
|
+
if (!this.isRecoverableOverlap(actor, hit)) {
|
|
123
|
+
continue;
|
|
124
|
+
}
|
|
125
|
+
const correction = hit.penetration + character.skinWidth;
|
|
126
|
+
if (correction <= DISTANCE_EPSILON) {
|
|
127
|
+
continue;
|
|
128
|
+
}
|
|
129
|
+
position.x += hit.normal.x * correction;
|
|
130
|
+
position.y += hit.normal.y * correction;
|
|
131
|
+
recovered = true;
|
|
132
|
+
}
|
|
133
|
+
if (!recovered) {
|
|
134
|
+
character._needsRecovery = false;
|
|
135
|
+
break;
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
handleHit(actor, hit) {
|
|
140
|
+
const character = actor.getComponent(CharacterBody);
|
|
141
|
+
let kind;
|
|
142
|
+
if (character.motionMode === 'surface') {
|
|
143
|
+
const upDot = VectorOps.dotProduct(hit.normal, character.upDirection);
|
|
144
|
+
const threshold = Math.cos(character.maxSlopeAngle);
|
|
145
|
+
if (upDot >= threshold) {
|
|
146
|
+
kind = 'ground';
|
|
147
|
+
character.onGround = true;
|
|
148
|
+
character.groundNormal = hit.normal;
|
|
149
|
+
character.groundActor = hit.actor;
|
|
150
|
+
}
|
|
151
|
+
else if (upDot <= -threshold) {
|
|
152
|
+
kind = 'ceiling';
|
|
153
|
+
character.onCeiling = true;
|
|
154
|
+
}
|
|
155
|
+
else {
|
|
156
|
+
kind = 'wall';
|
|
157
|
+
character.onWall = true;
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
else {
|
|
161
|
+
kind = 'wall';
|
|
162
|
+
character.onWall = true;
|
|
163
|
+
}
|
|
164
|
+
actor.dispatchEvent(CharacterHit, {
|
|
165
|
+
actor: hit.actor,
|
|
166
|
+
point: hit.point,
|
|
167
|
+
normal: hit.normal,
|
|
168
|
+
distance: hit.distance,
|
|
169
|
+
kind,
|
|
170
|
+
});
|
|
171
|
+
}
|
|
172
|
+
move(actor, position, displacement) {
|
|
173
|
+
if (displacement.squaredMagnitude <= DISTANCE_EPSILON) {
|
|
174
|
+
return;
|
|
175
|
+
}
|
|
176
|
+
const character = actor.getComponent(CharacterBody);
|
|
177
|
+
for (let i = 0; i < character.maxSlides; i += 1) {
|
|
178
|
+
if (displacement.squaredMagnitude <= DISTANCE_EPSILON) {
|
|
179
|
+
break;
|
|
180
|
+
}
|
|
181
|
+
const distance = displacement.magnitude;
|
|
182
|
+
const hit = this.castMotion(actor, position, displacement);
|
|
183
|
+
if (!hit) {
|
|
184
|
+
position.add(displacement);
|
|
185
|
+
break;
|
|
186
|
+
}
|
|
187
|
+
const safeDistance = Math.max(hit.distance - character.skinWidth, 0);
|
|
188
|
+
const direction = displacement.clone().normalize();
|
|
189
|
+
position.x += direction.x * safeDistance;
|
|
190
|
+
position.y += direction.y * safeDistance;
|
|
191
|
+
this.handleHit(actor, hit);
|
|
192
|
+
clipAgainstNormal(character.velocity, hit.normal);
|
|
193
|
+
const remainingDistance = Math.max(distance - safeDistance, 0);
|
|
194
|
+
displacement.x = direction.x * remainingDistance;
|
|
195
|
+
displacement.y = direction.y * remainingDistance;
|
|
196
|
+
clipAgainstNormal(displacement, hit.normal);
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
updateGroundState(actor, target, skipSnapping) {
|
|
200
|
+
const character = actor.getComponent(CharacterBody);
|
|
201
|
+
if (skipSnapping) {
|
|
202
|
+
this.resetGroundState(character);
|
|
203
|
+
return;
|
|
204
|
+
}
|
|
205
|
+
const probeDistance = Math.max(character.groundSnapDistance, character.skinWidth);
|
|
206
|
+
const probeDirection = character.upDirection
|
|
207
|
+
.clone()
|
|
208
|
+
.multiplyNumber(-probeDistance);
|
|
209
|
+
const hit = this.castGround(actor, target, probeDirection);
|
|
210
|
+
if (!hit) {
|
|
211
|
+
this.resetGroundState(character);
|
|
212
|
+
return;
|
|
213
|
+
}
|
|
214
|
+
character.onGround = true;
|
|
215
|
+
character.groundNormal = hit.normal;
|
|
216
|
+
character.groundActor = hit.actor;
|
|
217
|
+
const snapDistance = Math.max(hit.distance - character.skinWidth, 0);
|
|
218
|
+
const snapDirection = character.upDirection
|
|
219
|
+
.clone()
|
|
220
|
+
.multiplyNumber(-snapDistance);
|
|
221
|
+
target.x += snapDirection.x;
|
|
222
|
+
target.y += snapDirection.y;
|
|
223
|
+
}
|
|
224
|
+
fixedUpdate(options) {
|
|
225
|
+
if (!this.world.systemApi.has(PhysicsAPI)) {
|
|
226
|
+
return;
|
|
227
|
+
}
|
|
228
|
+
const deltaTimeInSeconds = options.deltaTime / 1000;
|
|
229
|
+
this.oneWayValidator.update();
|
|
230
|
+
this.actorQuery.getActors().forEach((actor) => {
|
|
231
|
+
const transform = actor.getComponent(Transform);
|
|
232
|
+
const character = actor.getComponent(CharacterBody);
|
|
233
|
+
const rigidBody = actor.getComponent(RigidBody);
|
|
234
|
+
const collider = actor.getComponent(Collider);
|
|
235
|
+
this.resetState(character);
|
|
236
|
+
if (character.disabled ||
|
|
237
|
+
rigidBody.disabled ||
|
|
238
|
+
collider.disabled ||
|
|
239
|
+
rigidBody.type !== 'kinematic') {
|
|
240
|
+
character._displacement.multiplyNumber(0);
|
|
241
|
+
return;
|
|
242
|
+
}
|
|
243
|
+
const position = new Vector2(transform.world.position.x, transform.world.position.y);
|
|
244
|
+
this.recoverOverlaps(actor, position);
|
|
245
|
+
const displacement = character.velocity
|
|
246
|
+
.clone()
|
|
247
|
+
.multiplyNumber(deltaTimeInSeconds)
|
|
248
|
+
.add(character._displacement);
|
|
249
|
+
const movingUp = VectorOps.dotProduct(displacement, character.upDirection) >
|
|
250
|
+
SNAP_EPSILON;
|
|
251
|
+
this.move(actor, position, displacement);
|
|
252
|
+
this.updateGroundState(actor, position, movingUp || character.motionMode === 'free');
|
|
253
|
+
if (Math.abs(position.x - transform.world.position.x) > DISTANCE_EPSILON ||
|
|
254
|
+
Math.abs(position.y - transform.world.position.y) > DISTANCE_EPSILON) {
|
|
255
|
+
rigidBody.movePosition(position);
|
|
256
|
+
}
|
|
257
|
+
character._displacement.multiplyNumber(0);
|
|
258
|
+
});
|
|
259
|
+
this.oneWayValidator.lateUpdate();
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
CharacterController.systemName = 'CharacterController';
|
|
@@ -3,6 +3,7 @@ export { CameraSystem, CameraAPI } from './camera-system';
|
|
|
3
3
|
export { GameStatsMeter } from './game-stats-meter';
|
|
4
4
|
export { KeyboardInputSystem } from './keyboard-input-system';
|
|
5
5
|
export { KeyboardControlSystem } from './keyboard-control-system';
|
|
6
|
+
export { CharacterController } from './character-controller';
|
|
6
7
|
export { MouseControlSystem } from './mouse-control-system';
|
|
7
8
|
export { MouseInputSystem } from './mouse-input-system';
|
|
8
9
|
export { PhysicsSystem, PhysicsAPI } from './physics-system';
|
|
@@ -10,5 +11,5 @@ export { BehaviorSystem, Behavior } from './behavior-system';
|
|
|
10
11
|
export type { BehaviorOptions } from './behavior-system';
|
|
11
12
|
export { UIBridge } from './ui-bridge';
|
|
12
13
|
export type { UIOptions, UIInitFn, UIDestroyFn, LoadUIFn } from './ui-bridge';
|
|
13
|
-
export { AudioSystem } from './audio-system';
|
|
14
|
+
export { AudioSystem, AudioAPI } from './audio-system';
|
|
14
15
|
export { Renderer, RendererAPI, FilterEffect, Shader } from './renderer';
|
|
@@ -3,10 +3,11 @@ export { CameraSystem, CameraAPI } from './camera-system';
|
|
|
3
3
|
export { GameStatsMeter } from './game-stats-meter';
|
|
4
4
|
export { KeyboardInputSystem } from './keyboard-input-system';
|
|
5
5
|
export { KeyboardControlSystem } from './keyboard-control-system';
|
|
6
|
+
export { CharacterController } from './character-controller';
|
|
6
7
|
export { MouseControlSystem } from './mouse-control-system';
|
|
7
8
|
export { MouseInputSystem } from './mouse-input-system';
|
|
8
9
|
export { PhysicsSystem, PhysicsAPI } from './physics-system';
|
|
9
10
|
export { BehaviorSystem, Behavior } from './behavior-system';
|
|
10
11
|
export { UIBridge } from './ui-bridge';
|
|
11
|
-
export { AudioSystem } from './audio-system';
|
|
12
|
+
export { AudioSystem, AudioAPI } from './audio-system';
|
|
12
13
|
export { Renderer, RendererAPI, FilterEffect, Shader } from './renderer';
|
|
@@ -1,6 +1,17 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
import type {
|
|
3
|
-
|
|
1
|
+
import type { Vector2 } from '../../../engine/math-lib';
|
|
2
|
+
import type { CastHit, OverlapHit, RaycastParams, OverlapParams, OverlapActorParams, ShapeCastParams, CastActorParams } from './types';
|
|
3
|
+
export interface PhysicsAPIHandlers {
|
|
4
|
+
raycast(params: RaycastParams): CastHit | null;
|
|
5
|
+
raycastAll(params: RaycastParams): CastHit[];
|
|
6
|
+
overlapShape(params: OverlapParams): OverlapHit[];
|
|
7
|
+
overlapActor(params: OverlapActorParams): OverlapHit[];
|
|
8
|
+
shapeCast(params: ShapeCastParams): CastHit | null;
|
|
9
|
+
shapeCastAll(params: ShapeCastParams): CastHit[];
|
|
10
|
+
castActor(params: CastActorParams): CastHit | null;
|
|
11
|
+
castActorAll(params: CastActorParams): CastHit[];
|
|
12
|
+
getGravity(): Vector2;
|
|
13
|
+
setGravity(gravity: Vector2): void;
|
|
14
|
+
}
|
|
4
15
|
/**
|
|
5
16
|
* API that provides methods for performing physics queries such as raycasting and overlap tests.
|
|
6
17
|
*
|
|
@@ -12,8 +23,18 @@ import type { CastHit, RaycastParams, OverlapParams, ShapeCastParams } from './t
|
|
|
12
23
|
* @category Systems
|
|
13
24
|
*/
|
|
14
25
|
export declare class PhysicsAPI {
|
|
15
|
-
private
|
|
16
|
-
constructor(
|
|
26
|
+
private handlers;
|
|
27
|
+
constructor(handlers: PhysicsAPIHandlers);
|
|
28
|
+
/**
|
|
29
|
+
* Current gravity vector.
|
|
30
|
+
*/
|
|
31
|
+
get gravity(): Vector2;
|
|
32
|
+
/**
|
|
33
|
+
* Sets the gravity vector.
|
|
34
|
+
*
|
|
35
|
+
* @param gravity - New gravity vector
|
|
36
|
+
*/
|
|
37
|
+
set gravity(gravity: Vector2);
|
|
17
38
|
/**
|
|
18
39
|
* Casts a ray and returns the nearest hit, if any.
|
|
19
40
|
*
|
|
@@ -35,12 +56,19 @@ export declare class PhysicsAPI {
|
|
|
35
56
|
*/
|
|
36
57
|
raycastAll(params: RaycastParams): CastHit[];
|
|
37
58
|
/**
|
|
38
|
-
* Returns all
|
|
59
|
+
* Returns all collider intersections for the given query shape.
|
|
39
60
|
*
|
|
40
61
|
* @param params - Overlap parameters
|
|
41
|
-
* @returns
|
|
62
|
+
* @returns All overlap hits
|
|
42
63
|
*/
|
|
43
|
-
overlapShape(params: OverlapParams):
|
|
64
|
+
overlapShape(params: OverlapParams): OverlapHit[];
|
|
65
|
+
/**
|
|
66
|
+
* Returns all collider intersections for an actor's collider.
|
|
67
|
+
*
|
|
68
|
+
* @param params - Actor overlap parameters
|
|
69
|
+
* @returns All overlap hits
|
|
70
|
+
*/
|
|
71
|
+
overlapActor(params: OverlapActorParams): OverlapHit[];
|
|
44
72
|
/**
|
|
45
73
|
* Casts a shape and returns the nearest hit, if any.
|
|
46
74
|
*
|
|
@@ -55,4 +83,18 @@ export declare class PhysicsAPI {
|
|
|
55
83
|
* @returns All hits sorted from nearest to farthest
|
|
56
84
|
*/
|
|
57
85
|
shapeCastAll(params: ShapeCastParams): CastHit[];
|
|
86
|
+
/**
|
|
87
|
+
* Casts an actor's collider and returns the nearest hit, if any.
|
|
88
|
+
*
|
|
89
|
+
* @param params - Actor cast parameters
|
|
90
|
+
* @returns The nearest hit or `null` when nothing is hit
|
|
91
|
+
*/
|
|
92
|
+
castActor(params: CastActorParams): CastHit | null;
|
|
93
|
+
/**
|
|
94
|
+
* Casts an actor's collider and returns all hits sorted by distance.
|
|
95
|
+
*
|
|
96
|
+
* @param params - Actor cast parameters
|
|
97
|
+
* @returns All hits sorted from nearest to farthest
|
|
98
|
+
*/
|
|
99
|
+
castActorAll(params: CastActorParams): CastHit[];
|
|
58
100
|
}
|
|
@@ -9,9 +9,23 @@
|
|
|
9
9
|
* @category Systems
|
|
10
10
|
*/
|
|
11
11
|
export class PhysicsAPI {
|
|
12
|
-
|
|
13
|
-
constructor(
|
|
14
|
-
this.
|
|
12
|
+
handlers;
|
|
13
|
+
constructor(handlers) {
|
|
14
|
+
this.handlers = handlers;
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Current gravity vector.
|
|
18
|
+
*/
|
|
19
|
+
get gravity() {
|
|
20
|
+
return this.handlers.getGravity();
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Sets the gravity vector.
|
|
24
|
+
*
|
|
25
|
+
* @param gravity - New gravity vector
|
|
26
|
+
*/
|
|
27
|
+
set gravity(gravity) {
|
|
28
|
+
this.handlers.setGravity(gravity);
|
|
15
29
|
}
|
|
16
30
|
/**
|
|
17
31
|
* Casts a ray and returns the nearest hit, if any.
|
|
@@ -23,7 +37,7 @@ export class PhysicsAPI {
|
|
|
23
37
|
* @returns The nearest hit or `null` when nothing is hit
|
|
24
38
|
*/
|
|
25
39
|
raycast(params) {
|
|
26
|
-
return this.
|
|
40
|
+
return this.handlers.raycast(params);
|
|
27
41
|
}
|
|
28
42
|
/**
|
|
29
43
|
* Casts a ray and returns all hits sorted by distance.
|
|
@@ -35,16 +49,25 @@ export class PhysicsAPI {
|
|
|
35
49
|
* @returns All hits sorted from nearest to farthest
|
|
36
50
|
*/
|
|
37
51
|
raycastAll(params) {
|
|
38
|
-
return this.
|
|
52
|
+
return this.handlers.raycastAll(params);
|
|
39
53
|
}
|
|
40
54
|
/**
|
|
41
|
-
* Returns all
|
|
55
|
+
* Returns all collider intersections for the given query shape.
|
|
42
56
|
*
|
|
43
57
|
* @param params - Overlap parameters
|
|
44
|
-
* @returns
|
|
58
|
+
* @returns All overlap hits
|
|
45
59
|
*/
|
|
46
60
|
overlapShape(params) {
|
|
47
|
-
return this.
|
|
61
|
+
return this.handlers.overlapShape(params);
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* Returns all collider intersections for an actor's collider.
|
|
65
|
+
*
|
|
66
|
+
* @param params - Actor overlap parameters
|
|
67
|
+
* @returns All overlap hits
|
|
68
|
+
*/
|
|
69
|
+
overlapActor(params) {
|
|
70
|
+
return this.handlers.overlapActor(params);
|
|
48
71
|
}
|
|
49
72
|
/**
|
|
50
73
|
* Casts a shape and returns the nearest hit, if any.
|
|
@@ -53,7 +76,7 @@ export class PhysicsAPI {
|
|
|
53
76
|
* @returns The nearest hit or `null` when nothing is hit
|
|
54
77
|
*/
|
|
55
78
|
shapeCast(params) {
|
|
56
|
-
return this.
|
|
79
|
+
return this.handlers.shapeCast(params);
|
|
57
80
|
}
|
|
58
81
|
/**
|
|
59
82
|
* Casts a shape and returns all hits sorted by distance.
|
|
@@ -62,6 +85,24 @@ export class PhysicsAPI {
|
|
|
62
85
|
* @returns All hits sorted from nearest to farthest
|
|
63
86
|
*/
|
|
64
87
|
shapeCastAll(params) {
|
|
65
|
-
return this.
|
|
88
|
+
return this.handlers.shapeCastAll(params);
|
|
89
|
+
}
|
|
90
|
+
/**
|
|
91
|
+
* Casts an actor's collider and returns the nearest hit, if any.
|
|
92
|
+
*
|
|
93
|
+
* @param params - Actor cast parameters
|
|
94
|
+
* @returns The nearest hit or `null` when nothing is hit
|
|
95
|
+
*/
|
|
96
|
+
castActor(params) {
|
|
97
|
+
return this.handlers.castActor(params);
|
|
98
|
+
}
|
|
99
|
+
/**
|
|
100
|
+
* Casts an actor's collider and returns all hits sorted by distance.
|
|
101
|
+
*
|
|
102
|
+
* @param params - Actor cast parameters
|
|
103
|
+
* @returns All hits sorted from nearest to farthest
|
|
104
|
+
*/
|
|
105
|
+
castActorAll(params) {
|
|
106
|
+
return this.handlers.castActorAll(params);
|
|
66
107
|
}
|
|
67
108
|
}
|
|
@@ -16,6 +16,7 @@ export declare class PhysicsSystem extends SceneSystem {
|
|
|
16
16
|
private collisionBroadcastSubsystem;
|
|
17
17
|
private constraintSolver;
|
|
18
18
|
private physicsApi;
|
|
19
|
+
private gravity;
|
|
19
20
|
constructor(options: SceneSystemOptions);
|
|
20
21
|
onSceneEnter(): void;
|
|
21
22
|
onSceneExit(): void;
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { SceneSystem } from '../../../engine/system';
|
|
2
|
+
import { Vector2 } from '../../../engine/math-lib';
|
|
2
3
|
import { PhysicsSubsystem, CollisionDetectionSubsystem, CollisionBroadcastSubsystem, ConstraintSolver, } from './subsystems';
|
|
3
4
|
import { PhysicsAPI } from './api';
|
|
4
5
|
/**
|
|
@@ -17,14 +18,33 @@ export class PhysicsSystem extends SceneSystem {
|
|
|
17
18
|
collisionBroadcastSubsystem;
|
|
18
19
|
constraintSolver;
|
|
19
20
|
physicsApi;
|
|
21
|
+
gravity;
|
|
20
22
|
constructor(options) {
|
|
21
23
|
super();
|
|
24
|
+
const { gravityX = 0, gravityY = 0 } = options;
|
|
25
|
+
this.gravity = new Vector2(gravityX, gravityY);
|
|
22
26
|
this.world = options.world;
|
|
23
|
-
this.physicsSubsystem = new PhysicsSubsystem(
|
|
27
|
+
this.physicsSubsystem = new PhysicsSubsystem({
|
|
28
|
+
scene: options.scene,
|
|
29
|
+
getGravity: () => this.gravity,
|
|
30
|
+
});
|
|
24
31
|
this.collisionDetectionSubsystem = new CollisionDetectionSubsystem(options);
|
|
25
32
|
this.collisionBroadcastSubsystem = new CollisionBroadcastSubsystem();
|
|
26
33
|
this.constraintSolver = new ConstraintSolver();
|
|
27
|
-
this.physicsApi = new PhysicsAPI(
|
|
34
|
+
this.physicsApi = new PhysicsAPI({
|
|
35
|
+
raycast: (params) => this.collisionDetectionSubsystem.raycast(params),
|
|
36
|
+
raycastAll: (params) => this.collisionDetectionSubsystem.raycastAll(params),
|
|
37
|
+
overlapShape: (params) => this.collisionDetectionSubsystem.overlapShape(params),
|
|
38
|
+
overlapActor: (params) => this.collisionDetectionSubsystem.overlapActor(params),
|
|
39
|
+
shapeCast: (params) => this.collisionDetectionSubsystem.shapeCast(params),
|
|
40
|
+
shapeCastAll: (params) => this.collisionDetectionSubsystem.shapeCastAll(params),
|
|
41
|
+
castActor: (params) => this.collisionDetectionSubsystem.castActor(params),
|
|
42
|
+
castActorAll: (params) => this.collisionDetectionSubsystem.castActorAll(params),
|
|
43
|
+
getGravity: () => this.gravity,
|
|
44
|
+
setGravity: (gravity) => {
|
|
45
|
+
this.gravity = gravity;
|
|
46
|
+
},
|
|
47
|
+
});
|
|
28
48
|
}
|
|
29
49
|
onSceneEnter() {
|
|
30
50
|
this.world.systemApi.register(this.physicsApi);
|
|
@@ -33,7 +53,6 @@ export class PhysicsSystem extends SceneSystem {
|
|
|
33
53
|
this.world.systemApi.unregister(PhysicsAPI);
|
|
34
54
|
}
|
|
35
55
|
onSceneDestroy() {
|
|
36
|
-
this.world.systemApi.unregister(PhysicsAPI);
|
|
37
56
|
this.physicsSubsystem.destroy();
|
|
38
57
|
this.collisionDetectionSubsystem.destroy();
|
|
39
58
|
}
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import type { Collider, Transform } from '../../../../../components';
|
|
1
2
|
import type { BoxCastGeometry } from '../types';
|
|
2
|
-
import type { BoxCastParams } from '../../../types';
|
|
3
|
-
export declare function buildBoxCastGeometry(
|
|
3
|
+
import type { BoxCastParams, CastActorParams } from '../../../types';
|
|
4
|
+
export declare function buildBoxCastGeometry(castParams: BoxCastParams): BoxCastGeometry;
|
|
5
|
+
export declare function buildBoxCastGeometry(collider: Collider, transform: Transform, castParams: CastActorParams): BoxCastGeometry;
|
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
import { buildBoxGeometry } from './build-box-geometry';
|
|
2
|
-
export function buildBoxCastGeometry(
|
|
3
|
-
const
|
|
2
|
+
export function buildBoxCastGeometry(castParamsOrCollider, transform, castParams) {
|
|
3
|
+
const params = castParams ?? castParamsOrCollider;
|
|
4
|
+
const box = transform !== undefined
|
|
5
|
+
? buildBoxGeometry(castParamsOrCollider, transform, castParams)
|
|
6
|
+
: buildBoxGeometry(castParamsOrCollider);
|
|
4
7
|
let minX = Infinity;
|
|
5
8
|
let maxX = -Infinity;
|
|
6
9
|
let minY = Infinity;
|
|
@@ -14,8 +17,8 @@ export function buildBoxCastGeometry(shapeCast) {
|
|
|
14
17
|
return {
|
|
15
18
|
...box,
|
|
16
19
|
origin: box.center,
|
|
17
|
-
direction:
|
|
18
|
-
maxDistance:
|
|
20
|
+
direction: params.direction.clone().normalize(),
|
|
21
|
+
maxDistance: params.maxDistance,
|
|
19
22
|
halfExtents: {
|
|
20
23
|
x: (maxX - minX) / 2,
|
|
21
24
|
y: (maxY - minY) / 2,
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { Collider, Transform } from '../../../../../components';
|
|
2
|
-
import type { BoxGeometry } from '../types';
|
|
3
|
-
import type { OverlapBoxParams } from '../../../types';
|
|
4
|
-
export declare function buildBoxGeometry(
|
|
5
|
-
export declare function buildBoxGeometry(collider: Collider, transform: Transform): BoxGeometry;
|
|
2
|
+
import type { ActorGeometryParams, BoxGeometry } from '../types';
|
|
3
|
+
import type { OverlapBoxParams, BoxCastParams } from '../../../types';
|
|
4
|
+
export declare function buildBoxGeometry(queryParams: OverlapBoxParams | BoxCastParams): BoxGeometry;
|
|
5
|
+
export declare function buildBoxGeometry(collider: Collider, transform: Transform, params?: ActorGeometryParams): BoxGeometry;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { VectorOps } from '../../../../../../engine/math-lib';
|
|
2
|
-
export function buildBoxGeometry(
|
|
3
|
-
let
|
|
4
|
-
let
|
|
2
|
+
export function buildBoxGeometry(colliderOrQueryParams, transform, params) {
|
|
3
|
+
let offsetX;
|
|
4
|
+
let offsetY;
|
|
5
5
|
let sizeX;
|
|
6
6
|
let sizeY;
|
|
7
7
|
let positionX;
|
|
@@ -10,29 +10,29 @@ export function buildBoxGeometry(colliderOrOverlap, transform) {
|
|
|
10
10
|
let scaleX;
|
|
11
11
|
let scaleY;
|
|
12
12
|
if (transform !== undefined) {
|
|
13
|
-
const collider =
|
|
13
|
+
const collider = colliderOrQueryParams;
|
|
14
14
|
if (collider.shape.type !== 'box') {
|
|
15
15
|
throw new Error(`Expected box collider, got ${collider.shape.type}.`);
|
|
16
16
|
}
|
|
17
|
-
|
|
18
|
-
|
|
17
|
+
offsetX = collider.offset.x;
|
|
18
|
+
offsetY = collider.offset.y;
|
|
19
19
|
sizeX = collider.shape.size.x;
|
|
20
20
|
sizeY = collider.shape.size.y;
|
|
21
|
-
positionX = transform.world.position.x;
|
|
22
|
-
positionY = transform.world.position.y;
|
|
21
|
+
positionX = transform.world.position.x + (params?.offset?.x ?? 0);
|
|
22
|
+
positionY = transform.world.position.y + (params?.offset?.y ?? 0);
|
|
23
23
|
rotation = transform.world.rotation;
|
|
24
24
|
scaleX = transform.world.scale.x;
|
|
25
25
|
scaleY = transform.world.scale.y;
|
|
26
26
|
}
|
|
27
27
|
else {
|
|
28
|
-
const
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
sizeX =
|
|
32
|
-
sizeY =
|
|
33
|
-
positionX =
|
|
34
|
-
positionY =
|
|
35
|
-
rotation =
|
|
28
|
+
const queryShape = colliderOrQueryParams.shape;
|
|
29
|
+
offsetX = 0;
|
|
30
|
+
offsetY = 0;
|
|
31
|
+
sizeX = queryShape.size.x;
|
|
32
|
+
sizeY = queryShape.size.y;
|
|
33
|
+
positionX = queryShape.center.x;
|
|
34
|
+
positionY = queryShape.center.y;
|
|
35
|
+
rotation = queryShape.rotation ?? 0;
|
|
36
36
|
scaleX = 1;
|
|
37
37
|
scaleY = 1;
|
|
38
38
|
}
|
|
@@ -42,12 +42,12 @@ export function buildBoxGeometry(colliderOrOverlap, transform) {
|
|
|
42
42
|
const y2 = sizeY / 2;
|
|
43
43
|
const cos = Math.cos(rotation);
|
|
44
44
|
const sin = Math.sin(rotation);
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
45
|
+
const center = VectorOps.rotatePoint({
|
|
46
|
+
x: offsetX * scaleX,
|
|
47
|
+
y: offsetY * scaleY,
|
|
48
|
+
}, rotation);
|
|
49
|
+
center.x += positionX;
|
|
50
|
+
center.y += positionY;
|
|
51
51
|
const points = [
|
|
52
52
|
{ x: x1, y: y1 },
|
|
53
53
|
{ x: x1, y: y2 },
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import type { Collider, Transform } from '../../../../../components';
|
|
1
2
|
import type { CapsuleCastGeometry } from '../types';
|
|
2
|
-
import type { CapsuleCastParams } from '../../../types';
|
|
3
|
-
export declare function buildCapsuleCastGeometry(
|
|
3
|
+
import type { CapsuleCastParams, CastActorParams } from '../../../types';
|
|
4
|
+
export declare function buildCapsuleCastGeometry(castParams: CapsuleCastParams): CapsuleCastGeometry;
|
|
5
|
+
export declare function buildCapsuleCastGeometry(collider: Collider, transform: Transform, castParams: CastActorParams): CapsuleCastGeometry;
|