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
|
@@ -3,6 +3,7 @@ export { KeyboardControl, type KeyboardControlConfig, } from './keyboard-control
|
|
|
3
3
|
export { Collider, type ColliderConfig, type ColliderShape, type ColliderType, type BoxColliderShape, type CircleColliderShape, type SegmentColliderShape, type CapsuleColliderShape, } from './collider';
|
|
4
4
|
export { RigidBody, type RigidBodyConfig } from './rigid-body';
|
|
5
5
|
export { CharacterBody, type CharacterBodyConfig } from './character-body';
|
|
6
|
+
export { Interpolation, type InterpolationConfig, type InterpolationMode, } from './interpolation';
|
|
6
7
|
export { Animatable, type AnimatableConfig } from './animatable';
|
|
7
8
|
export { Sprite, type SpriteConfig } from './sprite';
|
|
8
9
|
export { Transform, type TransformConfig } from './transform';
|
|
@@ -3,6 +3,7 @@ export { KeyboardControl, } from './keyboard-control';
|
|
|
3
3
|
export { Collider, } from './collider';
|
|
4
4
|
export { RigidBody } from './rigid-body';
|
|
5
5
|
export { CharacterBody } from './character-body';
|
|
6
|
+
export { Interpolation, } from './interpolation';
|
|
6
7
|
export { Animatable } from './animatable';
|
|
7
8
|
export { Sprite } from './sprite';
|
|
8
9
|
export { Transform } from './transform';
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
import { Component } from '../../../engine/component';
|
|
2
|
+
export type InterpolationMode = 'interpolate' | 'extrapolate';
|
|
3
|
+
export interface InterpolationConfig {
|
|
4
|
+
mode?: InterpolationMode;
|
|
5
|
+
snapThreshold?: number;
|
|
6
|
+
disabled?: boolean;
|
|
7
|
+
}
|
|
8
|
+
/**
|
|
9
|
+
* Component that smooths rendering of actors moved during fixed updates.
|
|
10
|
+
*
|
|
11
|
+
* Interpolator keeps local-space snapshots of the actor's Transform around
|
|
12
|
+
* each fixed step and blends them into the render-facing
|
|
13
|
+
* `renderX`/`renderY`/`renderRotation` values every render frame using
|
|
14
|
+
* `Time.alpha`. The renderer prefers these values over the Transform.
|
|
15
|
+
*
|
|
16
|
+
* The Transform component always holds the authoritative simulation state.
|
|
17
|
+
* Interpolated values are only visible to the renderer and to consumers of
|
|
18
|
+
* InterpolatorAPI, so simulation code can never accidentally read a
|
|
19
|
+
* visually smoothed but physically incorrect position.
|
|
20
|
+
*
|
|
21
|
+
* @example
|
|
22
|
+
* ```typescript
|
|
23
|
+
* actor.setComponent(new Interpolation({ mode: 'interpolate' }));
|
|
24
|
+
*
|
|
25
|
+
* // After teleporting the actor, skip smoothing for the jump:
|
|
26
|
+
* actor.getComponent(Transform).world.position.x = 500;
|
|
27
|
+
* actor.getComponent(Interpolation).snap();
|
|
28
|
+
* ```
|
|
29
|
+
*
|
|
30
|
+
* @category Components
|
|
31
|
+
*/
|
|
32
|
+
export declare class Interpolation extends Component {
|
|
33
|
+
/**
|
|
34
|
+
* How render values are produced. `interpolate` blends between the last
|
|
35
|
+
* two fixed steps (smooth, adds up to one fixed step of visual latency).
|
|
36
|
+
* `extrapolate` projects the latest step forward using the rigid body
|
|
37
|
+
* velocity (no added latency, may briefly overshoot on impacts).
|
|
38
|
+
*
|
|
39
|
+
* `extrapolate` uses the world-space rigid body velocity against
|
|
40
|
+
* local-space snapshots, so it is intended for root-level actors.
|
|
41
|
+
*/
|
|
42
|
+
mode: InterpolationMode;
|
|
43
|
+
/**
|
|
44
|
+
* Maximum distance in world units treated as continuous movement between
|
|
45
|
+
* two fixed steps. Larger jumps snap instead of gliding. `0` disables
|
|
46
|
+
* the automatic snap detection.
|
|
47
|
+
*/
|
|
48
|
+
snapThreshold: number;
|
|
49
|
+
/** Whether smoothing is turned off. The renderer falls back to Transform. */
|
|
50
|
+
disabled: boolean;
|
|
51
|
+
/** @internal Local-space position X from the previous fixed step */
|
|
52
|
+
_prevX: number;
|
|
53
|
+
/** @internal Local-space position Y from the previous fixed step */
|
|
54
|
+
_prevY: number;
|
|
55
|
+
/** @internal Local-space rotation from the previous fixed step */
|
|
56
|
+
_prevRotation: number;
|
|
57
|
+
/** @internal Local-space position X from the latest fixed step */
|
|
58
|
+
_currX: number;
|
|
59
|
+
/** @internal Local-space position Y from the latest fixed step */
|
|
60
|
+
_currY: number;
|
|
61
|
+
/** @internal Local-space rotation from the latest fixed step */
|
|
62
|
+
_currRotation: number;
|
|
63
|
+
/** @internal Whether snapshots have been initialized since (re)enabling */
|
|
64
|
+
_initialized: boolean;
|
|
65
|
+
/** @internal Whether smoothing should be skipped at the next opportunity */
|
|
66
|
+
_snapRequested: boolean;
|
|
67
|
+
/** Render-facing local-space position X, written by Interpolator */
|
|
68
|
+
renderX: number;
|
|
69
|
+
/** Render-facing local-space position Y, written by Interpolator */
|
|
70
|
+
renderY: number;
|
|
71
|
+
/** Render-facing local-space rotation, written by Interpolator */
|
|
72
|
+
renderRotation: number;
|
|
73
|
+
constructor(config?: InterpolationConfig);
|
|
74
|
+
/**
|
|
75
|
+
* Whether the render-facing values hold a valid snapshot yet. `false`
|
|
76
|
+
* until the Interpolator takes its first snapshot after the component is
|
|
77
|
+
* (re)enabled.
|
|
78
|
+
*/
|
|
79
|
+
get initialized(): boolean;
|
|
80
|
+
/**
|
|
81
|
+
* Requests an immediate jump to the Transform instead of
|
|
82
|
+
* smoothing towards it. Call right after teleporting the actor.
|
|
83
|
+
*/
|
|
84
|
+
snap(): void;
|
|
85
|
+
}
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
import { Component } from '../../../engine/component';
|
|
2
|
+
/**
|
|
3
|
+
* Component that smooths rendering of actors moved during fixed updates.
|
|
4
|
+
*
|
|
5
|
+
* Interpolator keeps local-space snapshots of the actor's Transform around
|
|
6
|
+
* each fixed step and blends them into the render-facing
|
|
7
|
+
* `renderX`/`renderY`/`renderRotation` values every render frame using
|
|
8
|
+
* `Time.alpha`. The renderer prefers these values over the Transform.
|
|
9
|
+
*
|
|
10
|
+
* The Transform component always holds the authoritative simulation state.
|
|
11
|
+
* Interpolated values are only visible to the renderer and to consumers of
|
|
12
|
+
* InterpolatorAPI, so simulation code can never accidentally read a
|
|
13
|
+
* visually smoothed but physically incorrect position.
|
|
14
|
+
*
|
|
15
|
+
* @example
|
|
16
|
+
* ```typescript
|
|
17
|
+
* actor.setComponent(new Interpolation({ mode: 'interpolate' }));
|
|
18
|
+
*
|
|
19
|
+
* // After teleporting the actor, skip smoothing for the jump:
|
|
20
|
+
* actor.getComponent(Transform).world.position.x = 500;
|
|
21
|
+
* actor.getComponent(Interpolation).snap();
|
|
22
|
+
* ```
|
|
23
|
+
*
|
|
24
|
+
* @category Components
|
|
25
|
+
*/
|
|
26
|
+
export class Interpolation extends Component {
|
|
27
|
+
/**
|
|
28
|
+
* How render values are produced. `interpolate` blends between the last
|
|
29
|
+
* two fixed steps (smooth, adds up to one fixed step of visual latency).
|
|
30
|
+
* `extrapolate` projects the latest step forward using the rigid body
|
|
31
|
+
* velocity (no added latency, may briefly overshoot on impacts).
|
|
32
|
+
*
|
|
33
|
+
* `extrapolate` uses the world-space rigid body velocity against
|
|
34
|
+
* local-space snapshots, so it is intended for root-level actors.
|
|
35
|
+
*/
|
|
36
|
+
mode;
|
|
37
|
+
/**
|
|
38
|
+
* Maximum distance in world units treated as continuous movement between
|
|
39
|
+
* two fixed steps. Larger jumps snap instead of gliding. `0` disables
|
|
40
|
+
* the automatic snap detection.
|
|
41
|
+
*/
|
|
42
|
+
snapThreshold;
|
|
43
|
+
/** Whether smoothing is turned off. The renderer falls back to Transform. */
|
|
44
|
+
disabled;
|
|
45
|
+
/** @internal Local-space position X from the previous fixed step */
|
|
46
|
+
_prevX;
|
|
47
|
+
/** @internal Local-space position Y from the previous fixed step */
|
|
48
|
+
_prevY;
|
|
49
|
+
/** @internal Local-space rotation from the previous fixed step */
|
|
50
|
+
_prevRotation;
|
|
51
|
+
/** @internal Local-space position X from the latest fixed step */
|
|
52
|
+
_currX;
|
|
53
|
+
/** @internal Local-space position Y from the latest fixed step */
|
|
54
|
+
_currY;
|
|
55
|
+
/** @internal Local-space rotation from the latest fixed step */
|
|
56
|
+
_currRotation;
|
|
57
|
+
/** @internal Whether snapshots have been initialized since (re)enabling */
|
|
58
|
+
_initialized;
|
|
59
|
+
/** @internal Whether smoothing should be skipped at the next opportunity */
|
|
60
|
+
_snapRequested;
|
|
61
|
+
/** Render-facing local-space position X, written by Interpolator */
|
|
62
|
+
renderX;
|
|
63
|
+
/** Render-facing local-space position Y, written by Interpolator */
|
|
64
|
+
renderY;
|
|
65
|
+
/** Render-facing local-space rotation, written by Interpolator */
|
|
66
|
+
renderRotation;
|
|
67
|
+
constructor(config = {}) {
|
|
68
|
+
super();
|
|
69
|
+
const { mode = 'interpolate', snapThreshold = 0, disabled = false, } = config;
|
|
70
|
+
this.mode = mode;
|
|
71
|
+
this.snapThreshold = snapThreshold;
|
|
72
|
+
this.disabled = disabled;
|
|
73
|
+
this._prevX = 0;
|
|
74
|
+
this._prevY = 0;
|
|
75
|
+
this._prevRotation = 0;
|
|
76
|
+
this._currX = 0;
|
|
77
|
+
this._currY = 0;
|
|
78
|
+
this._currRotation = 0;
|
|
79
|
+
this._initialized = false;
|
|
80
|
+
this._snapRequested = false;
|
|
81
|
+
this.renderX = 0;
|
|
82
|
+
this.renderY = 0;
|
|
83
|
+
this.renderRotation = 0;
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* Whether the render-facing values hold a valid snapshot yet. `false`
|
|
87
|
+
* until the Interpolator takes its first snapshot after the component is
|
|
88
|
+
* (re)enabled.
|
|
89
|
+
*/
|
|
90
|
+
get initialized() {
|
|
91
|
+
return this._initialized;
|
|
92
|
+
}
|
|
93
|
+
/**
|
|
94
|
+
* Requests an immediate jump to the Transform instead of
|
|
95
|
+
* smoothing towards it. Call right after teleporting the actor.
|
|
96
|
+
*/
|
|
97
|
+
snap() {
|
|
98
|
+
this._snapRequested = true;
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
Interpolation.componentName = 'Interpolation';
|
|
@@ -31,6 +31,13 @@ interface PointImpulse {
|
|
|
31
31
|
* impulses, gravity, collisions, and rotation. Static and kinematic bodies can
|
|
32
32
|
* participate in collisions but are not moved by solver impulses.
|
|
33
33
|
*
|
|
34
|
+
* Physics is simulated in world space.
|
|
35
|
+
*
|
|
36
|
+
* Rigid bodies may be parented only to actors with static transforms. A moving
|
|
37
|
+
* parent (for example, a dynamic or kinematic rigid body) and the physics
|
|
38
|
+
* simulation would both control the child's transform, so the result is
|
|
39
|
+
* undefined.
|
|
40
|
+
*
|
|
34
41
|
* @example
|
|
35
42
|
* ```typescript
|
|
36
43
|
* // Create a dynamic rigid body
|
|
@@ -115,6 +122,7 @@ export declare class RigidBody extends Component {
|
|
|
115
122
|
/**
|
|
116
123
|
* Sets the mass used by dynamic bodies.
|
|
117
124
|
*
|
|
125
|
+
* Mass is an authored, kilogram-like scalar.
|
|
118
126
|
* Non-positive values make the body immovable by forces and impulses.
|
|
119
127
|
*/
|
|
120
128
|
set mass(value: number);
|
|
@@ -7,6 +7,13 @@ import { Vector2 } from '../../../engine/math-lib';
|
|
|
7
7
|
* impulses, gravity, collisions, and rotation. Static and kinematic bodies can
|
|
8
8
|
* participate in collisions but are not moved by solver impulses.
|
|
9
9
|
*
|
|
10
|
+
* Physics is simulated in world space.
|
|
11
|
+
*
|
|
12
|
+
* Rigid bodies may be parented only to actors with static transforms. A moving
|
|
13
|
+
* parent (for example, a dynamic or kinematic rigid body) and the physics
|
|
14
|
+
* simulation would both control the child's transform, so the result is
|
|
15
|
+
* undefined.
|
|
16
|
+
*
|
|
10
17
|
* @example
|
|
11
18
|
* ```typescript
|
|
12
19
|
* // Create a dynamic rigid body
|
|
@@ -134,6 +141,7 @@ export class RigidBody extends Component {
|
|
|
134
141
|
/**
|
|
135
142
|
* Sets the mass used by dynamic bodies.
|
|
136
143
|
*
|
|
144
|
+
* Mass is an authored, kilogram-like scalar.
|
|
137
145
|
* Non-positive values make the body immovable by forces and impulses.
|
|
138
146
|
*/
|
|
139
147
|
set mass(value) {
|
|
@@ -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
|
+
};
|