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
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import { RigidBody, Transform } from '../../components';
|
|
2
|
+
import { VectorOps } from '../../../engine/math-lib';
|
|
3
|
+
export class OneWayValidator {
|
|
4
|
+
ignoredOneWayContacts;
|
|
5
|
+
touchedActors;
|
|
6
|
+
oneWayContactUpdateIndex;
|
|
7
|
+
constructor() {
|
|
8
|
+
this.ignoredOneWayContacts = new Map();
|
|
9
|
+
this.touchedActors = new Set();
|
|
10
|
+
this.oneWayContactUpdateIndex = 0;
|
|
11
|
+
}
|
|
12
|
+
clearOneWayContacts() {
|
|
13
|
+
this.touchedActors.forEach((actor) => {
|
|
14
|
+
const ignoredContacts = this.ignoredOneWayContacts.get(actor);
|
|
15
|
+
if (!ignoredContacts) {
|
|
16
|
+
return;
|
|
17
|
+
}
|
|
18
|
+
ignoredContacts.forEach((lastSeenUpdate, otherActor) => {
|
|
19
|
+
if (lastSeenUpdate !== this.oneWayContactUpdateIndex) {
|
|
20
|
+
ignoredContacts.delete(otherActor);
|
|
21
|
+
}
|
|
22
|
+
});
|
|
23
|
+
if (ignoredContacts.size === 0) {
|
|
24
|
+
this.ignoredOneWayContacts.delete(actor);
|
|
25
|
+
}
|
|
26
|
+
});
|
|
27
|
+
if (this.ignoredOneWayContacts.size === 0) {
|
|
28
|
+
this.oneWayContactUpdateIndex = 0;
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
trackOneWayContact(actor, oneWayActor) {
|
|
32
|
+
let ignoredContacts = this.ignoredOneWayContacts.get(actor);
|
|
33
|
+
if (!ignoredContacts) {
|
|
34
|
+
ignoredContacts = new Map();
|
|
35
|
+
this.ignoredOneWayContacts.set(actor, ignoredContacts);
|
|
36
|
+
}
|
|
37
|
+
ignoredContacts.set(oneWayActor, this.oneWayContactUpdateIndex);
|
|
38
|
+
}
|
|
39
|
+
touch(actor) {
|
|
40
|
+
this.touchedActors.add(actor);
|
|
41
|
+
}
|
|
42
|
+
shouldBlock(oneWayActor, otherActor, normal) {
|
|
43
|
+
if (this.ignoredOneWayContacts.get(otherActor)?.has(oneWayActor)) {
|
|
44
|
+
this.trackOneWayContact(otherActor, oneWayActor);
|
|
45
|
+
return false;
|
|
46
|
+
}
|
|
47
|
+
const rigidBody = oneWayActor.getComponent(RigidBody);
|
|
48
|
+
const transform = oneWayActor.getComponent(Transform);
|
|
49
|
+
const oneWayNormal = VectorOps.rotatePoint(rigidBody.oneWayNormal, transform.world.rotation);
|
|
50
|
+
if (VectorOps.dotProduct(oneWayNormal, normal) > 0) {
|
|
51
|
+
return true;
|
|
52
|
+
}
|
|
53
|
+
this.trackOneWayContact(otherActor, oneWayActor);
|
|
54
|
+
return false;
|
|
55
|
+
}
|
|
56
|
+
delete(actor) {
|
|
57
|
+
this.ignoredOneWayContacts.delete(actor);
|
|
58
|
+
this.touchedActors.delete(actor);
|
|
59
|
+
this.ignoredOneWayContacts.forEach((ignoredContacts, trackedActor) => {
|
|
60
|
+
ignoredContacts.delete(actor);
|
|
61
|
+
if (ignoredContacts.size === 0) {
|
|
62
|
+
this.ignoredOneWayContacts.delete(trackedActor);
|
|
63
|
+
}
|
|
64
|
+
});
|
|
65
|
+
}
|
|
66
|
+
update() {
|
|
67
|
+
this.oneWayContactUpdateIndex += 1;
|
|
68
|
+
}
|
|
69
|
+
lateUpdate() {
|
|
70
|
+
this.clearOneWayContacts();
|
|
71
|
+
this.touchedActors.clear();
|
|
72
|
+
}
|
|
73
|
+
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { WorldSystem } from '../../../engine/system';
|
|
2
|
-
import type { WorldSystemOptions
|
|
2
|
+
import type { WorldSystemOptions } from '../../../engine/system';
|
|
3
3
|
import type { Scene } from '../../../engine/scene';
|
|
4
4
|
/**
|
|
5
5
|
* Game statistics meter that tracks and reports performance metrics
|
|
@@ -13,12 +13,13 @@ import type { Scene } from '../../../engine/scene';
|
|
|
13
13
|
*/
|
|
14
14
|
export declare class GameStatsMeter extends WorldSystem {
|
|
15
15
|
private world;
|
|
16
|
+
private time;
|
|
16
17
|
private actorQuery?;
|
|
17
18
|
private frequency;
|
|
18
19
|
private fps;
|
|
19
|
-
private
|
|
20
|
+
private elapsed;
|
|
20
21
|
constructor(options: WorldSystemOptions);
|
|
21
22
|
onSceneEnter(scene: Scene): void;
|
|
22
23
|
onSceneExit(): void;
|
|
23
|
-
update(
|
|
24
|
+
update(): void;
|
|
24
25
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { WorldSystem } from '../../../engine/system';
|
|
2
2
|
import { GameStatsUpdate } from '../../events';
|
|
3
3
|
import { ActorQuery } from '../../../engine/actor';
|
|
4
|
-
const
|
|
4
|
+
const DEFAULT_FREQUENCY = 1;
|
|
5
5
|
/**
|
|
6
6
|
* Game statistics meter that tracks and reports performance metrics
|
|
7
7
|
*
|
|
@@ -14,17 +14,19 @@ const MS_IN_SEC = 1000;
|
|
|
14
14
|
*/
|
|
15
15
|
export class GameStatsMeter extends WorldSystem {
|
|
16
16
|
world;
|
|
17
|
+
time;
|
|
17
18
|
actorQuery;
|
|
18
19
|
frequency;
|
|
19
20
|
fps;
|
|
20
|
-
|
|
21
|
+
elapsed;
|
|
21
22
|
constructor(options) {
|
|
22
23
|
super();
|
|
23
24
|
const { world, frequency } = options;
|
|
24
25
|
this.world = world;
|
|
25
|
-
this.
|
|
26
|
+
this.time = options.time;
|
|
27
|
+
this.frequency = frequency || DEFAULT_FREQUENCY;
|
|
26
28
|
this.fps = 0;
|
|
27
|
-
this.
|
|
29
|
+
this.elapsed = 0;
|
|
28
30
|
}
|
|
29
31
|
onSceneEnter(scene) {
|
|
30
32
|
this.actorQuery = new ActorQuery({ scene, filter: [] });
|
|
@@ -32,17 +34,16 @@ export class GameStatsMeter extends WorldSystem {
|
|
|
32
34
|
onSceneExit() {
|
|
33
35
|
this.actorQuery = undefined;
|
|
34
36
|
}
|
|
35
|
-
update(
|
|
36
|
-
const { deltaTime } = options;
|
|
37
|
+
update() {
|
|
37
38
|
this.fps += 1;
|
|
38
|
-
this.
|
|
39
|
-
if (this.
|
|
39
|
+
this.elapsed += this.time.deltaTime;
|
|
40
|
+
if (this.elapsed >= this.frequency) {
|
|
40
41
|
this.world.dispatchEvent(GameStatsUpdate, {
|
|
41
|
-
fps:
|
|
42
|
+
fps: this.fps / this.elapsed,
|
|
42
43
|
actorsCount: this.actorQuery?.getActors().size ?? 0,
|
|
43
44
|
});
|
|
44
45
|
this.fps = 0;
|
|
45
|
-
this.
|
|
46
|
+
this.elapsed = 0;
|
|
46
47
|
}
|
|
47
48
|
}
|
|
48
49
|
}
|
|
@@ -4,6 +4,8 @@ export { GameStatsMeter } from './game-stats-meter';
|
|
|
4
4
|
export { KeyboardInputSystem } from './keyboard-input-system';
|
|
5
5
|
export { KeyboardControlSystem } from './keyboard-control-system';
|
|
6
6
|
export { CharacterController } from './character-controller';
|
|
7
|
+
export { Interpolator, InterpolatorAPI } from './interpolator';
|
|
8
|
+
export type { RenderTransform } from './interpolator';
|
|
7
9
|
export { MouseControlSystem } from './mouse-control-system';
|
|
8
10
|
export { MouseInputSystem } from './mouse-input-system';
|
|
9
11
|
export { PhysicsSystem, PhysicsAPI } from './physics-system';
|
|
@@ -4,6 +4,7 @@ export { GameStatsMeter } from './game-stats-meter';
|
|
|
4
4
|
export { KeyboardInputSystem } from './keyboard-input-system';
|
|
5
5
|
export { KeyboardControlSystem } from './keyboard-control-system';
|
|
6
6
|
export { CharacterController } from './character-controller';
|
|
7
|
+
export { Interpolator, InterpolatorAPI } from './interpolator';
|
|
7
8
|
export { MouseControlSystem } from './mouse-control-system';
|
|
8
9
|
export { MouseInputSystem } from './mouse-input-system';
|
|
9
10
|
export { PhysicsSystem, PhysicsAPI } from './physics-system';
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import type { Actor } from '../../../engine/actor';
|
|
2
|
+
import type { Time } from '../../../engine/time';
|
|
3
|
+
export interface RenderTransform {
|
|
4
|
+
x: number;
|
|
5
|
+
y: number;
|
|
6
|
+
rotation: number;
|
|
7
|
+
}
|
|
8
|
+
interface InterpolatorAPIOptions {
|
|
9
|
+
time: Time;
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* Public API for reading render-facing (visually smoothed) transforms.
|
|
13
|
+
*
|
|
14
|
+
* Retrieve it via `world.systemApi.get(InterpolatorAPI)`. Use it in
|
|
15
|
+
* systems and behaviors that position visuals against moving actors —
|
|
16
|
+
* e.g. a camera-follow script — instead of reading the authoritative
|
|
17
|
+
* Transform, which advances in fixed steps.
|
|
18
|
+
*
|
|
19
|
+
* Values are computed from the current `Time.alpha`, so this API is only
|
|
20
|
+
* meaningful during the update phase (not inside `fixedUpdate`).
|
|
21
|
+
*
|
|
22
|
+
* @category Systems
|
|
23
|
+
*/
|
|
24
|
+
export declare class InterpolatorAPI {
|
|
25
|
+
private time;
|
|
26
|
+
constructor(options: InterpolatorAPIOptions);
|
|
27
|
+
/**
|
|
28
|
+
* Returns the world-space transform the actor is rendered with this
|
|
29
|
+
* frame. Falls back to the Transform for actors (and
|
|
30
|
+
* ancestors) without an active Interpolation component.
|
|
31
|
+
*/
|
|
32
|
+
getRenderTransform(actor: Actor): RenderTransform;
|
|
33
|
+
/**
|
|
34
|
+
* Requests an immediate visual jump to the actor's
|
|
35
|
+
* Transform. Call right after teleporting the actor.
|
|
36
|
+
*/
|
|
37
|
+
snap(actor: Actor): void;
|
|
38
|
+
private composeRenderWorldMatrix;
|
|
39
|
+
}
|
|
40
|
+
export {};
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import { Matrix } from '../../../engine/math-lib';
|
|
2
|
+
import { Interpolation } from '../../components/interpolation';
|
|
3
|
+
import { Transform } from '../../components/transform';
|
|
4
|
+
import { computeRenderValues } from './utils';
|
|
5
|
+
/**
|
|
6
|
+
* Public API for reading render-facing (visually smoothed) transforms.
|
|
7
|
+
*
|
|
8
|
+
* Retrieve it via `world.systemApi.get(InterpolatorAPI)`. Use it in
|
|
9
|
+
* systems and behaviors that position visuals against moving actors —
|
|
10
|
+
* e.g. a camera-follow script — instead of reading the authoritative
|
|
11
|
+
* Transform, which advances in fixed steps.
|
|
12
|
+
*
|
|
13
|
+
* Values are computed from the current `Time.alpha`, so this API is only
|
|
14
|
+
* meaningful during the update phase (not inside `fixedUpdate`).
|
|
15
|
+
*
|
|
16
|
+
* @category Systems
|
|
17
|
+
*/
|
|
18
|
+
export class InterpolatorAPI {
|
|
19
|
+
time;
|
|
20
|
+
constructor(options) {
|
|
21
|
+
this.time = options.time;
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Returns the world-space transform the actor is rendered with this
|
|
25
|
+
* frame. Falls back to the Transform for actors (and
|
|
26
|
+
* ancestors) without an active Interpolation component.
|
|
27
|
+
*/
|
|
28
|
+
getRenderTransform(actor) {
|
|
29
|
+
const matrix = this.composeRenderWorldMatrix(actor);
|
|
30
|
+
return {
|
|
31
|
+
x: matrix.tx,
|
|
32
|
+
y: matrix.ty,
|
|
33
|
+
rotation: Math.atan2(matrix.b, matrix.a),
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Requests an immediate visual jump to the actor's
|
|
38
|
+
* Transform. Call right after teleporting the actor.
|
|
39
|
+
*/
|
|
40
|
+
snap(actor) {
|
|
41
|
+
const interpolation = actor.getComponent(Interpolation);
|
|
42
|
+
interpolation?.snap();
|
|
43
|
+
}
|
|
44
|
+
composeRenderWorldMatrix(actor) {
|
|
45
|
+
const transform = actor.getComponent(Transform);
|
|
46
|
+
const interpolation = actor.getComponent(Interpolation);
|
|
47
|
+
const useRender = interpolation !== undefined &&
|
|
48
|
+
!interpolation.disabled &&
|
|
49
|
+
interpolation.initialized;
|
|
50
|
+
if (useRender) {
|
|
51
|
+
computeRenderValues(actor, interpolation, this.time.alpha, this.time.fixedDeltaTime);
|
|
52
|
+
}
|
|
53
|
+
const x = useRender ? interpolation.renderX : transform.local.position.x;
|
|
54
|
+
const y = useRender ? interpolation.renderY : transform.local.position.y;
|
|
55
|
+
const rotation = useRender
|
|
56
|
+
? interpolation.renderRotation
|
|
57
|
+
: transform.local.rotation;
|
|
58
|
+
const { scale } = transform.local;
|
|
59
|
+
const cos = Math.cos(rotation);
|
|
60
|
+
const sin = Math.sin(rotation);
|
|
61
|
+
const localMatrix = new Matrix(cos * scale.x, sin * scale.x, -sin * scale.y, cos * scale.y, x, y);
|
|
62
|
+
const parentTransform = transform.getParentComponent();
|
|
63
|
+
if (!parentTransform?.actor) {
|
|
64
|
+
return localMatrix;
|
|
65
|
+
}
|
|
66
|
+
const result = new Matrix(1, 0, 0, 1, 0, 0);
|
|
67
|
+
Matrix.multiply(result, this.composeRenderWorldMatrix(parentTransform.actor), localMatrix);
|
|
68
|
+
return result;
|
|
69
|
+
}
|
|
70
|
+
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { SceneSystem } from '../../../engine/system';
|
|
2
|
+
import type { SceneSystemOptions } from '../../../engine/system';
|
|
3
|
+
/**
|
|
4
|
+
* System that produces smooth render-facing transforms for actors moved
|
|
5
|
+
* during fixed updates.
|
|
6
|
+
*
|
|
7
|
+
* During `fixedUpdate` it snapshots the local Transform of every actor with
|
|
8
|
+
* an Interpolation component. During `update` it blends the last two
|
|
9
|
+
* snapshots using `Time.alpha` and writes the result into the component's
|
|
10
|
+
* `renderX`/`renderY`/`renderRotation`, which the renderer prefers over the
|
|
11
|
+
* Transform.
|
|
12
|
+
*
|
|
13
|
+
* Ordering: place this system AFTER every system that moves transforms in
|
|
14
|
+
* fixed updates (`PhysicsSystem`, `CharacterController`, behavior scripts
|
|
15
|
+
* that move actors in `fixedUpdate`) and BEFORE `Renderer` in the system
|
|
16
|
+
* configuration.
|
|
17
|
+
*
|
|
18
|
+
* @category Systems
|
|
19
|
+
*/
|
|
20
|
+
export declare class Interpolator extends SceneSystem {
|
|
21
|
+
private actorQuery;
|
|
22
|
+
private time;
|
|
23
|
+
private world;
|
|
24
|
+
private api;
|
|
25
|
+
constructor(options: SceneSystemOptions);
|
|
26
|
+
onSceneEnter(): void;
|
|
27
|
+
onSceneExit(): void;
|
|
28
|
+
onSceneDestroy(): void;
|
|
29
|
+
fixedUpdate(): void;
|
|
30
|
+
update(): void;
|
|
31
|
+
}
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
import { ActorQuery } from '../../../engine/actor';
|
|
2
|
+
import { SceneSystem } from '../../../engine/system';
|
|
3
|
+
import { Interpolation } from '../../components/interpolation';
|
|
4
|
+
import { Transform } from '../../components/transform';
|
|
5
|
+
import { InterpolatorAPI } from './api';
|
|
6
|
+
import { snapToTransform, computeRenderValues } from './utils';
|
|
7
|
+
/**
|
|
8
|
+
* System that produces smooth render-facing transforms for actors moved
|
|
9
|
+
* during fixed updates.
|
|
10
|
+
*
|
|
11
|
+
* During `fixedUpdate` it snapshots the local Transform of every actor with
|
|
12
|
+
* an Interpolation component. During `update` it blends the last two
|
|
13
|
+
* snapshots using `Time.alpha` and writes the result into the component's
|
|
14
|
+
* `renderX`/`renderY`/`renderRotation`, which the renderer prefers over the
|
|
15
|
+
* Transform.
|
|
16
|
+
*
|
|
17
|
+
* Ordering: place this system AFTER every system that moves transforms in
|
|
18
|
+
* fixed updates (`PhysicsSystem`, `CharacterController`, behavior scripts
|
|
19
|
+
* that move actors in `fixedUpdate`) and BEFORE `Renderer` in the system
|
|
20
|
+
* configuration.
|
|
21
|
+
*
|
|
22
|
+
* @category Systems
|
|
23
|
+
*/
|
|
24
|
+
export class Interpolator extends SceneSystem {
|
|
25
|
+
actorQuery;
|
|
26
|
+
time;
|
|
27
|
+
world;
|
|
28
|
+
api;
|
|
29
|
+
constructor(options) {
|
|
30
|
+
super();
|
|
31
|
+
this.time = options.time;
|
|
32
|
+
this.world = options.world;
|
|
33
|
+
this.actorQuery = new ActorQuery({
|
|
34
|
+
scene: options.scene,
|
|
35
|
+
filter: [Interpolation, Transform],
|
|
36
|
+
});
|
|
37
|
+
this.api = new InterpolatorAPI({ time: options.time });
|
|
38
|
+
}
|
|
39
|
+
onSceneEnter() {
|
|
40
|
+
this.world.systemApi.register(this.api);
|
|
41
|
+
}
|
|
42
|
+
onSceneExit() {
|
|
43
|
+
this.world.systemApi.unregister(InterpolatorAPI);
|
|
44
|
+
}
|
|
45
|
+
onSceneDestroy() {
|
|
46
|
+
this.actorQuery.destroy();
|
|
47
|
+
}
|
|
48
|
+
fixedUpdate() {
|
|
49
|
+
for (const actor of this.actorQuery.getActors()) {
|
|
50
|
+
const interpolation = actor.getComponent(Interpolation);
|
|
51
|
+
const { local } = actor.getComponent(Transform);
|
|
52
|
+
if (interpolation.disabled) {
|
|
53
|
+
interpolation._initialized = false;
|
|
54
|
+
continue;
|
|
55
|
+
}
|
|
56
|
+
if (!interpolation._initialized || interpolation._snapRequested) {
|
|
57
|
+
snapToTransform(interpolation, local);
|
|
58
|
+
continue;
|
|
59
|
+
}
|
|
60
|
+
interpolation._prevX = interpolation._currX;
|
|
61
|
+
interpolation._prevY = interpolation._currY;
|
|
62
|
+
interpolation._prevRotation = interpolation._currRotation;
|
|
63
|
+
interpolation._currX = local.position.x;
|
|
64
|
+
interpolation._currY = local.position.y;
|
|
65
|
+
interpolation._currRotation = local.rotation;
|
|
66
|
+
const threshold = interpolation.snapThreshold;
|
|
67
|
+
if (threshold > 0) {
|
|
68
|
+
const dx = interpolation._currX - interpolation._prevX;
|
|
69
|
+
const dy = interpolation._currY - interpolation._prevY;
|
|
70
|
+
if (dx * dx + dy * dy > threshold * threshold) {
|
|
71
|
+
interpolation._prevX = interpolation._currX;
|
|
72
|
+
interpolation._prevY = interpolation._currY;
|
|
73
|
+
interpolation._prevRotation = interpolation._currRotation;
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
update() {
|
|
79
|
+
const { alpha, fixedDeltaTime } = this.time;
|
|
80
|
+
for (const actor of this.actorQuery.getActors()) {
|
|
81
|
+
const interpolation = actor.getComponent(Interpolation);
|
|
82
|
+
if (interpolation.disabled) {
|
|
83
|
+
continue;
|
|
84
|
+
}
|
|
85
|
+
if (interpolation._snapRequested) {
|
|
86
|
+
snapToTransform(interpolation, actor.getComponent(Transform).local);
|
|
87
|
+
continue;
|
|
88
|
+
}
|
|
89
|
+
if (!interpolation._initialized) {
|
|
90
|
+
continue;
|
|
91
|
+
}
|
|
92
|
+
computeRenderValues(actor, interpolation, alpha, fixedDeltaTime);
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
Interpolator.systemName = 'Interpolator';
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { Actor } from '../../../../engine/actor';
|
|
2
|
+
import { Scene } from '../../../../engine/scene';
|
|
3
|
+
import { World } from '../../../../engine/world';
|
|
4
|
+
import { Time } from '../../../../engine/time';
|
|
5
|
+
import type { InterpolationConfig } from '../../../components/interpolation';
|
|
6
|
+
import { Interpolator } from '../system';
|
|
7
|
+
export declare const createScene: () => Scene;
|
|
8
|
+
export declare const createInterpolator: (scene: Scene) => {
|
|
9
|
+
system: Interpolator;
|
|
10
|
+
world: World;
|
|
11
|
+
time: Time;
|
|
12
|
+
};
|
|
13
|
+
export declare const createInterpolatedActor: (id: string, x: number, y: number, config?: InterpolationConfig) => Actor;
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { Actor, ActorCreator, ActorSpawner } from '../../../../engine/actor';
|
|
2
|
+
import { Scene } from '../../../../engine/scene';
|
|
3
|
+
import { TemplateCollection } from '../../../../engine/template';
|
|
4
|
+
import { World } from '../../../../engine/world';
|
|
5
|
+
import { Time } from '../../../../engine/time';
|
|
6
|
+
import { Interpolation } from '../../../components/interpolation';
|
|
7
|
+
import { Transform } from '../../../components/transform';
|
|
8
|
+
import { Interpolator } from '../system';
|
|
9
|
+
export const createScene = () => {
|
|
10
|
+
const templateCollection = new TemplateCollection();
|
|
11
|
+
const actorCreator = new ActorCreator([], templateCollection);
|
|
12
|
+
return new Scene({
|
|
13
|
+
id: 'scene',
|
|
14
|
+
name: 'scene',
|
|
15
|
+
actors: [],
|
|
16
|
+
actorCreator,
|
|
17
|
+
templateCollection,
|
|
18
|
+
});
|
|
19
|
+
};
|
|
20
|
+
export const createInterpolator = (scene) => {
|
|
21
|
+
const world = new World({ id: 'world', name: 'world' });
|
|
22
|
+
const templateCollection = new TemplateCollection();
|
|
23
|
+
const actorCreator = new ActorCreator([], templateCollection);
|
|
24
|
+
const time = new Time();
|
|
25
|
+
time.fixedDeltaTime = 0.1;
|
|
26
|
+
world.appendChild(scene);
|
|
27
|
+
const system = new Interpolator({
|
|
28
|
+
scene,
|
|
29
|
+
world,
|
|
30
|
+
actorSpawner: new ActorSpawner(actorCreator),
|
|
31
|
+
globalOptions: {},
|
|
32
|
+
templateCollection,
|
|
33
|
+
time,
|
|
34
|
+
});
|
|
35
|
+
system.onSceneEnter?.();
|
|
36
|
+
return { system, world, time };
|
|
37
|
+
};
|
|
38
|
+
export const createInterpolatedActor = (id, x, y, config = {}) => {
|
|
39
|
+
const actor = new Actor({ id, name: id });
|
|
40
|
+
const transform = actor.getComponent(Transform);
|
|
41
|
+
transform.local.position.x = x;
|
|
42
|
+
transform.local.position.y = y;
|
|
43
|
+
actor.setComponent(new Interpolation(config));
|
|
44
|
+
return actor;
|
|
45
|
+
};
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import type { Actor } from '../../../engine/actor';
|
|
2
|
+
import type { Interpolation } from '../../components/interpolation';
|
|
3
|
+
import type { LocalTransform } from '../../components/transform/local-transform';
|
|
4
|
+
export declare const snapToTransform: (interpolation: Interpolation, local: LocalTransform) => void;
|
|
5
|
+
export declare const computeRenderValues: (actor: Actor, interpolation: Interpolation, alpha: number, fixedDeltaTime: number) => void;
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { MathOps } from '../../../engine/math-lib';
|
|
2
|
+
import { RigidBody } from '../../components/rigid-body';
|
|
3
|
+
export const snapToTransform = (interpolation, local) => {
|
|
4
|
+
interpolation._prevX = local.position.x;
|
|
5
|
+
interpolation._prevY = local.position.y;
|
|
6
|
+
interpolation._prevRotation = local.rotation;
|
|
7
|
+
interpolation._currX = local.position.x;
|
|
8
|
+
interpolation._currY = local.position.y;
|
|
9
|
+
interpolation._currRotation = local.rotation;
|
|
10
|
+
interpolation.renderX = local.position.x;
|
|
11
|
+
interpolation.renderY = local.position.y;
|
|
12
|
+
interpolation.renderRotation = local.rotation;
|
|
13
|
+
interpolation._initialized = true;
|
|
14
|
+
interpolation._snapRequested = false;
|
|
15
|
+
};
|
|
16
|
+
export const computeRenderValues = (actor, interpolation, alpha, fixedDeltaTime) => {
|
|
17
|
+
if (interpolation.mode === 'extrapolate') {
|
|
18
|
+
const rigidBody = actor.getComponent(RigidBody);
|
|
19
|
+
if (rigidBody !== undefined && !rigidBody.disabled) {
|
|
20
|
+
const timeAhead = alpha * fixedDeltaTime;
|
|
21
|
+
interpolation.renderX =
|
|
22
|
+
interpolation._currX + rigidBody.linearVelocity.x * timeAhead;
|
|
23
|
+
interpolation.renderY =
|
|
24
|
+
interpolation._currY + rigidBody.linearVelocity.y * timeAhead;
|
|
25
|
+
interpolation.renderRotation = rigidBody.lockRotation
|
|
26
|
+
? interpolation._currRotation
|
|
27
|
+
: interpolation._currRotation + rigidBody.angularVelocity * timeAhead;
|
|
28
|
+
return;
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
interpolation.renderX =
|
|
32
|
+
interpolation._prevX +
|
|
33
|
+
(interpolation._currX - interpolation._prevX) * alpha;
|
|
34
|
+
interpolation.renderY =
|
|
35
|
+
interpolation._prevY +
|
|
36
|
+
(interpolation._currY - interpolation._prevY) * alpha;
|
|
37
|
+
interpolation.renderRotation =
|
|
38
|
+
interpolation._prevRotation +
|
|
39
|
+
MathOps.getAngleDelta(interpolation._prevRotation, interpolation._currRotation) *
|
|
40
|
+
alpha;
|
|
41
|
+
};
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { Vector2 } from '../../../engine/math-lib';
|
|
2
|
-
import type { CastHit, OverlapHit, RaycastParams, OverlapParams, OverlapActorParams, ShapeCastParams, CastActorParams } from './types';
|
|
2
|
+
import type { CastHit, OverlapHit, RaycastParams, OverlapParams, OverlapActorParams, ShapeCastParams, CastActorParams, CastHitCallback, OverlapHitCallback } from './types';
|
|
3
3
|
export interface PhysicsAPIHandlers {
|
|
4
4
|
raycast(params: RaycastParams): CastHit | null;
|
|
5
5
|
raycastAll(params: RaycastParams): CastHit[];
|
|
@@ -9,6 +9,11 @@ export interface PhysicsAPIHandlers {
|
|
|
9
9
|
shapeCastAll(params: ShapeCastParams): CastHit[];
|
|
10
10
|
castActor(params: CastActorParams): CastHit | null;
|
|
11
11
|
castActorAll(params: CastActorParams): CastHit[];
|
|
12
|
+
raycastEach(params: RaycastParams, callback: CastHitCallback): void;
|
|
13
|
+
shapeCastEach(params: ShapeCastParams, callback: CastHitCallback): void;
|
|
14
|
+
overlapEach(params: OverlapParams, callback: OverlapHitCallback): void;
|
|
15
|
+
castActorEach(params: CastActorParams, callback: CastHitCallback): void;
|
|
16
|
+
overlapActorEach(params: OverlapActorParams, callback: OverlapHitCallback): void;
|
|
12
17
|
getGravity(): Vector2;
|
|
13
18
|
setGravity(gravity: Vector2): void;
|
|
14
19
|
}
|
|
@@ -55,6 +60,13 @@ export declare class PhysicsAPI {
|
|
|
55
60
|
* @returns All hits sorted from nearest to farthest
|
|
56
61
|
*/
|
|
57
62
|
raycastAll(params: RaycastParams): CastHit[];
|
|
63
|
+
/**
|
|
64
|
+
* Casts a ray and invokes `callback` for every hit.
|
|
65
|
+
*
|
|
66
|
+
* @param params - Raycast parameters
|
|
67
|
+
* @param callback - Invoked once per hit with a reused hit object
|
|
68
|
+
*/
|
|
69
|
+
raycastEach(params: RaycastParams, callback: CastHitCallback): void;
|
|
58
70
|
/**
|
|
59
71
|
* Returns all collider intersections for the given query shape.
|
|
60
72
|
*
|
|
@@ -62,6 +74,13 @@ export declare class PhysicsAPI {
|
|
|
62
74
|
* @returns All overlap hits
|
|
63
75
|
*/
|
|
64
76
|
overlapShape(params: OverlapParams): OverlapHit[];
|
|
77
|
+
/**
|
|
78
|
+
* Invokes `callback` for every collider intersecting the query shape.
|
|
79
|
+
*
|
|
80
|
+
* @param params - Overlap parameters
|
|
81
|
+
* @param callback - Invoked once per overlap with a reused hit object
|
|
82
|
+
*/
|
|
83
|
+
overlapEach(params: OverlapParams, callback: OverlapHitCallback): void;
|
|
65
84
|
/**
|
|
66
85
|
* Returns all collider intersections for an actor's collider.
|
|
67
86
|
*
|
|
@@ -69,6 +88,13 @@ export declare class PhysicsAPI {
|
|
|
69
88
|
* @returns All overlap hits
|
|
70
89
|
*/
|
|
71
90
|
overlapActor(params: OverlapActorParams): OverlapHit[];
|
|
91
|
+
/**
|
|
92
|
+
* Invokes `callback` for every collider intersecting an actor's collider.
|
|
93
|
+
*
|
|
94
|
+
* @param params - Actor overlap parameters
|
|
95
|
+
* @param callback - Invoked once per overlap with a reused hit object
|
|
96
|
+
*/
|
|
97
|
+
overlapActorEach(params: OverlapActorParams, callback: OverlapHitCallback): void;
|
|
72
98
|
/**
|
|
73
99
|
* Casts a shape and returns the nearest hit, if any.
|
|
74
100
|
*
|
|
@@ -83,6 +109,13 @@ export declare class PhysicsAPI {
|
|
|
83
109
|
* @returns All hits sorted from nearest to farthest
|
|
84
110
|
*/
|
|
85
111
|
shapeCastAll(params: ShapeCastParams): CastHit[];
|
|
112
|
+
/**
|
|
113
|
+
* Casts a shape and invokes `callback` for every hit.
|
|
114
|
+
*
|
|
115
|
+
* @param params - Shape cast parameters
|
|
116
|
+
* @param callback - Invoked once per hit with a reused hit object
|
|
117
|
+
*/
|
|
118
|
+
shapeCastEach(params: ShapeCastParams, callback: CastHitCallback): void;
|
|
86
119
|
/**
|
|
87
120
|
* Casts an actor's collider and returns the nearest hit, if any.
|
|
88
121
|
*
|
|
@@ -97,4 +130,15 @@ export declare class PhysicsAPI {
|
|
|
97
130
|
* @returns All hits sorted from nearest to farthest
|
|
98
131
|
*/
|
|
99
132
|
castActorAll(params: CastActorParams): CastHit[];
|
|
133
|
+
/**
|
|
134
|
+
* Casts an actor's collider and invokes `callback` for every hit.
|
|
135
|
+
*
|
|
136
|
+
* The `hit` passed to `callback` is a single object reused across
|
|
137
|
+
* invocations and is only valid for the duration of the call. Copy any
|
|
138
|
+
* fields you need to keep. Hits are delivered in arbitrary order.
|
|
139
|
+
*
|
|
140
|
+
* @param params - Actor cast parameters
|
|
141
|
+
* @param callback - Invoked once per hit with a reused hit object
|
|
142
|
+
*/
|
|
143
|
+
castActorEach(params: CastActorParams, callback: CastHitCallback): void;
|
|
100
144
|
}
|