@phalanx-engine/physics 0.1.0 → 0.1.2
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/README.md +20 -12
- package/dist/components/InterpolationComponent.d.ts +6 -5
- package/dist/components/InterpolationComponent.d.ts.map +1 -1
- package/dist/components/InterpolationComponent.js +12 -6
- package/dist/components/TransformComponent.d.ts +8 -4
- package/dist/components/TransformComponent.d.ts.map +1 -1
- package/dist/components/TransformComponent.js +19 -11
- package/dist/systems/InterpolationSystem.d.ts +3 -1
- package/dist/systems/InterpolationSystem.d.ts.map +1 -1
- package/dist/systems/InterpolationSystem.js +19 -23
- package/package.json +3 -3
package/README.md
CHANGED
|
@@ -125,7 +125,7 @@ import {
|
|
|
125
125
|
TRANSFORM_COMPONENT_TYPE,
|
|
126
126
|
INTERPOLATION_COMPONENT_TYPE,
|
|
127
127
|
} from '@phalanx-engine/physics';
|
|
128
|
-
import { FP, FPVector3 } from '@phalanx-engine/math';
|
|
128
|
+
import { FP, FPVector3, FPQuaternion } from '@phalanx-engine/math';
|
|
129
129
|
|
|
130
130
|
// Register canonical component type symbols from phalanx-physics
|
|
131
131
|
export const ComponentType = createComponentTypeRegistry({
|
|
@@ -144,7 +144,11 @@ class MovementSystem extends GameSystem {
|
|
|
144
144
|
class RenderSystem extends GameSystem {
|
|
145
145
|
public override update(_dt: number): void {
|
|
146
146
|
const sample = this.physics?.getInterpolatedTransform(entityId);
|
|
147
|
-
if (sample)
|
|
147
|
+
if (sample) {
|
|
148
|
+
mesh.position.set(sample.position.x, sample.position.y, sample.position.z);
|
|
149
|
+
// sample.rotation is a float quaternion { x, y, z, w } — apply it as-is.
|
|
150
|
+
mesh.quaternion.set(sample.rotation.x, sample.rotation.y, sample.rotation.z, sample.rotation.w);
|
|
151
|
+
}
|
|
148
152
|
}
|
|
149
153
|
}
|
|
150
154
|
const movementSystem = new MovementSystem();
|
|
@@ -176,8 +180,9 @@ world.start();
|
|
|
176
180
|
// 4. Add transform, interpolation, and physics body to entities
|
|
177
181
|
declare const entity: { id: number; addComponent(c: unknown): void };
|
|
178
182
|
const fpPosition = FPVector3.FromFloat(0, 0, 0);
|
|
179
|
-
|
|
180
|
-
entity.addComponent(new
|
|
183
|
+
const fpRotation = FPQuaternion.Identity();
|
|
184
|
+
entity.addComponent(new TransformComponent(entity.id, fpPosition, fpRotation));
|
|
185
|
+
entity.addComponent(new InterpolationComponent(fpPosition, fpRotation));
|
|
181
186
|
entity.addComponent(new PhysicsBodyComponent(entity.id, { radius: FP.FromFloat(1.0) }));
|
|
182
187
|
world.entityManager.addEntity(entity as any);
|
|
183
188
|
|
|
@@ -282,7 +287,7 @@ class PhysicsWorld {
|
|
|
282
287
|
|
|
283
288
|
- **`getSystems()`** — Returns both `physicsSystem` (register as tick system) and `interpolationSystem` (register as frame system).
|
|
284
289
|
- **`getEntityPosition(entityId)`** — Fixed-point position for gameplay queries (e.g. ability targeting).
|
|
285
|
-
- **`getInterpolatedTransform(entityId)`** — Interpolated float
|
|
290
|
+
- **`getInterpolatedTransform(entityId)`** — Interpolated float transform for rendering, populated after `InterpolationSystem` runs. Returns an `InterpolatedTransformSample` with `position: { x, y, z }` and `rotation: { x, y, z, w }` — rotation is a float quaternion (slerped between tick samples), apply it directly to a mesh quaternion.
|
|
286
291
|
|
|
287
292
|
- **`applyImpulse(entityId, vx, vz)`** — Set body velocity (replaces, does not accumulate). Re-enables previously ejected bodies.
|
|
288
293
|
- **`isSettled(threshold?)`** — Pure query: `true` when all non-static, non-ignored bodies are below velocity threshold (default from config, falling back to `FP.FromFloat(0.01)`).
|
|
@@ -314,15 +319,18 @@ class TransformComponent extends SoAComponent<typeof TransformSoASchema.definiti
|
|
|
314
319
|
static readonly soaSchema: typeof TransformSoASchema;
|
|
315
320
|
readonly type: symbol; // TRANSFORM_COMPONENT_TYPE
|
|
316
321
|
|
|
317
|
-
constructor(entityId: number, initialPosition?: FPVector3, initialRotation?:
|
|
322
|
+
constructor(entityId: number, initialPosition?: FPVector3, initialRotation?: FPQuaternion);
|
|
318
323
|
|
|
319
|
-
fpPosition: FPVector3;
|
|
320
|
-
fpRotation:
|
|
321
|
-
|
|
324
|
+
fpPosition: FPVector3; // get/set — authoritative fixed-point position
|
|
325
|
+
fpRotation: FPQuaternion; // get/set — authoritative rotation quaternion
|
|
326
|
+
fpRotationEuler: FPVector3; // get/set — computed Euler view (radians, XYZ order)
|
|
327
|
+
fpRotationY: FixedPoint; // get/set — convenience Y-yaw (radians)
|
|
322
328
|
}
|
|
323
329
|
```
|
|
324
330
|
|
|
325
|
-
`
|
|
331
|
+
Rotation is authoritatively a quaternion (`fpRotation`). `fpRotationEuler` (XYZ Euler radians) and `fpRotationY` (yaw) are computed views over it — recomputed on each access, mirroring Unity's `Transform.rotation` / `Transform.eulerAngles`. Setting `fpRotationEuler` calls `FPQuaternion.FromEulerXYZ`; setting `fpRotationY` builds a yaw rotation around `FPVector3.Up`.
|
|
332
|
+
|
|
333
|
+
`TransformSoASchema` fields: `fpPositionX/Y/Z`, `fpRotationX/Y/Z/W` (all `i64`). Rotation defaults to the identity quaternion (`w = 1`).
|
|
326
334
|
|
|
327
335
|
### `InterpolationComponent`
|
|
328
336
|
|
|
@@ -330,10 +338,10 @@ class TransformComponent extends SoAComponent<typeof TransformSoASchema.definiti
|
|
|
330
338
|
class InterpolationComponent implements IComponent {
|
|
331
339
|
readonly type: symbol; // INTERPOLATION_COMPONENT_TYPE
|
|
332
340
|
|
|
333
|
-
constructor(initialPosition?: FPVector3, initialRotation?:
|
|
341
|
+
constructor(initialPosition?: FPVector3, initialRotation?: FPQuaternion);
|
|
334
342
|
|
|
335
343
|
snapshot(): void; // copy current → previous (called by InterpolationSystem before tick)
|
|
336
|
-
capture(fpPosition: FPVector3, fpRotation:
|
|
344
|
+
capture(fpPosition: FPVector3, fpRotation: FPQuaternion): void; // capture authoritative state after tick
|
|
337
345
|
}
|
|
338
346
|
```
|
|
339
347
|
|
|
@@ -1,15 +1,16 @@
|
|
|
1
1
|
import type { IComponent } from '@phalanx-engine/ecs';
|
|
2
|
-
import type { FPVector3 as FPVector3Type } from '@phalanx-engine/math';
|
|
2
|
+
import type { FPVector3 as FPVector3Type, FPQuaternion as FPQuaternionType } from '@phalanx-engine/math';
|
|
3
3
|
export declare const INTERPOLATION_COMPONENT_TYPE: symbol;
|
|
4
4
|
export declare class InterpolationComponent implements IComponent {
|
|
5
5
|
readonly type: symbol;
|
|
6
6
|
readonly previousFpPosition: FPVector3Type;
|
|
7
7
|
readonly currentFpPosition: FPVector3Type;
|
|
8
|
-
readonly previousFpRotation:
|
|
9
|
-
readonly currentFpRotation:
|
|
10
|
-
constructor(initialPosition?: FPVector3Type, initialRotation?:
|
|
8
|
+
readonly previousFpRotation: FPQuaternionType;
|
|
9
|
+
readonly currentFpRotation: FPQuaternionType;
|
|
10
|
+
constructor(initialPosition?: FPVector3Type, initialRotation?: FPQuaternionType);
|
|
11
11
|
snapshot(): void;
|
|
12
|
-
capture(fpPosition: FPVector3Type, fpRotation:
|
|
12
|
+
capture(fpPosition: FPVector3Type, fpRotation: FPQuaternionType): void;
|
|
13
13
|
private copyFpVector3;
|
|
14
|
+
private copyFpQuaternion;
|
|
14
15
|
}
|
|
15
16
|
//# sourceMappingURL=InterpolationComponent.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"InterpolationComponent.d.ts","sourceRoot":"","sources":["../../src/components/InterpolationComponent.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAC;AAEtD,OAAO,KAAK,
|
|
1
|
+
{"version":3,"file":"InterpolationComponent.d.ts","sourceRoot":"","sources":["../../src/components/InterpolationComponent.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAC;AAEtD,OAAO,KAAK,EACV,SAAS,IAAI,aAAa,EAC1B,YAAY,IAAI,gBAAgB,EACjC,MAAM,sBAAsB,CAAC;AAM9B,eAAO,MAAM,4BAA4B,EAAE,MAAgC,CAAC;AAU5E,qBAAa,sBAAuB,YAAW,UAAU;IACvD,SAAgB,IAAI,SAAgC;IAEpD,SAAgB,kBAAkB,EAAE,aAAa,CAAoC;IACrF,SAAgB,iBAAiB,EAAE,aAAa,CAAoC;IACpF,SAAgB,kBAAkB,EAAE,gBAAgB,CAA8C;IAClG,SAAgB,iBAAiB,EAAE,gBAAgB,CAA8C;gBAErF,eAAe,CAAC,EAAE,aAAa,EAAE,eAAe,CAAC,EAAE,gBAAgB;IAYxE,QAAQ,IAAI,IAAI;IAMhB,OAAO,CAAC,UAAU,EAAE,aAAa,EAAE,UAAU,EAAE,gBAAgB,GAAG,IAAI;IAK7E,OAAO,CAAC,aAAa;IAMrB,OAAO,CAAC,gBAAgB;CAMzB"}
|
|
@@ -4,29 +4,35 @@ export class InterpolationComponent {
|
|
|
4
4
|
type = INTERPOLATION_COMPONENT_TYPE;
|
|
5
5
|
previousFpPosition = { x: FP._0, y: FP._0, z: FP._0 };
|
|
6
6
|
currentFpPosition = { x: FP._0, y: FP._0, z: FP._0 };
|
|
7
|
-
previousFpRotation = { x: FP._0, y: FP._0, z: FP._0 };
|
|
8
|
-
currentFpRotation = { x: FP._0, y: FP._0, z: FP._0 };
|
|
7
|
+
previousFpRotation = { x: FP._0, y: FP._0, z: FP._0, w: FP._1 };
|
|
8
|
+
currentFpRotation = { x: FP._0, y: FP._0, z: FP._0, w: FP._1 };
|
|
9
9
|
constructor(initialPosition, initialRotation) {
|
|
10
10
|
if (initialPosition) {
|
|
11
11
|
this.copyFpVector3(this.previousFpPosition, initialPosition);
|
|
12
12
|
this.copyFpVector3(this.currentFpPosition, initialPosition);
|
|
13
13
|
}
|
|
14
14
|
if (initialRotation) {
|
|
15
|
-
this.
|
|
16
|
-
this.
|
|
15
|
+
this.copyFpQuaternion(this.previousFpRotation, initialRotation);
|
|
16
|
+
this.copyFpQuaternion(this.currentFpRotation, initialRotation);
|
|
17
17
|
}
|
|
18
18
|
}
|
|
19
19
|
snapshot() {
|
|
20
20
|
this.copyFpVector3(this.previousFpPosition, this.currentFpPosition);
|
|
21
|
-
this.
|
|
21
|
+
this.copyFpQuaternion(this.previousFpRotation, this.currentFpRotation);
|
|
22
22
|
}
|
|
23
23
|
capture(fpPosition, fpRotation) {
|
|
24
24
|
this.copyFpVector3(this.currentFpPosition, fpPosition);
|
|
25
|
-
this.
|
|
25
|
+
this.copyFpQuaternion(this.currentFpRotation, fpRotation);
|
|
26
26
|
}
|
|
27
27
|
copyFpVector3(target, source) {
|
|
28
28
|
target.x = source.x;
|
|
29
29
|
target.y = source.y;
|
|
30
30
|
target.z = source.z;
|
|
31
31
|
}
|
|
32
|
+
copyFpQuaternion(target, source) {
|
|
33
|
+
target.x = source.x;
|
|
34
|
+
target.y = source.y;
|
|
35
|
+
target.z = source.z;
|
|
36
|
+
target.w = source.w;
|
|
37
|
+
}
|
|
32
38
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { SoAComponent } from '@phalanx-engine/ecs';
|
|
2
|
-
import { type FixedPoint, type FPVector3 as FPVector3Type } from '@phalanx-engine/math';
|
|
2
|
+
import { type FixedPoint, type FPVector3 as FPVector3Type, type FPQuaternion as FPQuaternionType } from '@phalanx-engine/math';
|
|
3
3
|
export declare const TransformSoASchema: import("@phalanx-engine/ecs").SoASchema<{
|
|
4
4
|
fpPositionX: "i64";
|
|
5
5
|
fpPositionY: "i64";
|
|
@@ -7,6 +7,7 @@ export declare const TransformSoASchema: import("@phalanx-engine/ecs").SoASchema
|
|
|
7
7
|
fpRotationX: "i64";
|
|
8
8
|
fpRotationY: "i64";
|
|
9
9
|
fpRotationZ: "i64";
|
|
10
|
+
fpRotationW: "i64";
|
|
10
11
|
}>;
|
|
11
12
|
export declare const TRANSFORM_COMPONENT_TYPE: symbol;
|
|
12
13
|
export declare class TransformComponent extends SoAComponent<typeof TransformSoASchema.definition> {
|
|
@@ -18,14 +19,17 @@ export declare class TransformComponent extends SoAComponent<typeof TransformSoA
|
|
|
18
19
|
fpRotationX: "i64";
|
|
19
20
|
fpRotationY: "i64";
|
|
20
21
|
fpRotationZ: "i64";
|
|
22
|
+
fpRotationW: "i64";
|
|
21
23
|
}>;
|
|
22
24
|
private readonly _fpPosition;
|
|
23
25
|
private readonly _fpRotation;
|
|
24
|
-
constructor(entityId: number, initialPosition?: FPVector3Type, initialRotation?:
|
|
26
|
+
constructor(entityId: number, initialPosition?: FPVector3Type, initialRotation?: FPQuaternionType);
|
|
25
27
|
get fpPosition(): FPVector3Type;
|
|
26
28
|
set fpPosition(value: FPVector3Type);
|
|
27
|
-
get fpRotation():
|
|
28
|
-
set fpRotation(value:
|
|
29
|
+
get fpRotation(): FPQuaternionType;
|
|
30
|
+
set fpRotation(value: FPQuaternionType);
|
|
31
|
+
get fpRotationEuler(): FPVector3Type;
|
|
32
|
+
set fpRotationEuler(value: FPVector3Type);
|
|
29
33
|
get fpRotationY(): FixedPoint;
|
|
30
34
|
set fpRotationY(value: FixedPoint);
|
|
31
35
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"TransformComponent.d.ts","sourceRoot":"","sources":["../../src/components/TransformComponent.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAmB,MAAM,qBAAqB,CAAC;AACpE,OAAO,
|
|
1
|
+
{"version":3,"file":"TransformComponent.d.ts","sourceRoot":"","sources":["../../src/components/TransformComponent.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAmB,MAAM,qBAAqB,CAAC;AACpE,OAAO,EAIL,KAAK,UAAU,EACf,KAAK,SAAS,IAAI,aAAa,EAC/B,KAAK,YAAY,IAAI,gBAAgB,EACtC,MAAM,sBAAsB,CAAC;AAU9B,eAAO,MAAM,kBAAkB;;;;;;;;EAW9B,CAAC;AAMF,eAAO,MAAM,wBAAwB,EAAE,MAA4B,CAAC;AAiBpE,qBAAa,kBAAmB,SAAQ,YAAY,CAAC,OAAO,kBAAkB,CAAC,UAAU,CAAC;IACxF,SAAgB,IAAI,SAA4B;IAChD,gBAAuB,SAAS;;;;;;;;OAAsB;IAEtD,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAmD;IAC/E,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAgE;gBAG1F,QAAQ,EAAE,MAAM,EAChB,eAAe,CAAC,EAAE,aAAa,EAC/B,eAAe,CAAC,EAAE,gBAAgB;IAgBpC,IAAW,UAAU,IAAI,aAAa,CASrC;IAED,IAAW,UAAU,CAAC,KAAK,EAAE,aAAa,EAQzC;IAGD,IAAW,UAAU,IAAI,gBAAgB,CASxC;IAED,IAAW,UAAU,CAAC,KAAK,EAAE,gBAAgB,EAQ5C;IAOD,IAAW,eAAe,IAAI,aAAa,CAE1C;IAED,IAAW,eAAe,CAAC,KAAK,EAAE,aAAa,EAE9C;IAGD,IAAW,WAAW,IAAI,UAAU,CAMnC;IAED,IAAW,WAAW,CAAC,KAAK,EAAE,UAAU,EAEvC;CACF"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { SoAComponent, defineSoASchema } from '@phalanx-engine/ecs';
|
|
2
|
-
import { FP, FPVector3 } from '@phalanx-engine/math';
|
|
2
|
+
import { FP, FPVector3, FPQuaternion, } from '@phalanx-engine/math';
|
|
3
3
|
export const TransformSoASchema = defineSoASchema({
|
|
4
4
|
fpPositionX: 'i64',
|
|
5
5
|
fpPositionY: 'i64',
|
|
@@ -7,16 +7,17 @@ export const TransformSoASchema = defineSoASchema({
|
|
|
7
7
|
fpRotationX: 'i64',
|
|
8
8
|
fpRotationY: 'i64',
|
|
9
9
|
fpRotationZ: 'i64',
|
|
10
|
+
fpRotationW: 'i64',
|
|
10
11
|
}, 'Transform');
|
|
11
12
|
export const TRANSFORM_COMPONENT_TYPE = Symbol('Transform');
|
|
12
13
|
export class TransformComponent extends SoAComponent {
|
|
13
14
|
type = TRANSFORM_COMPONENT_TYPE;
|
|
14
15
|
static soaSchema = TransformSoASchema;
|
|
15
16
|
_fpPosition = { x: FP._0, y: FP._0, z: FP._0 };
|
|
16
|
-
_fpRotation = { x: FP._0, y: FP._0, z: FP._0 };
|
|
17
|
+
_fpRotation = { x: FP._0, y: FP._0, z: FP._0, w: FP._1 };
|
|
17
18
|
constructor(entityId, initialPosition, initialRotation) {
|
|
18
19
|
const position = initialPosition ?? FPVector3.Zero;
|
|
19
|
-
const rotation = initialRotation ??
|
|
20
|
+
const rotation = initialRotation ?? FPQuaternion.Identity();
|
|
20
21
|
super(TransformSoASchema, entityId, {
|
|
21
22
|
fpPositionX: FP.ToRaw(position.x),
|
|
22
23
|
fpPositionY: FP.ToRaw(position.y),
|
|
@@ -24,6 +25,7 @@ export class TransformComponent extends SoAComponent {
|
|
|
24
25
|
fpRotationX: FP.ToRaw(rotation.x),
|
|
25
26
|
fpRotationY: FP.ToRaw(rotation.y),
|
|
26
27
|
fpRotationZ: FP.ToRaw(rotation.z),
|
|
28
|
+
fpRotationW: FP.ToRaw(rotation.w),
|
|
27
29
|
});
|
|
28
30
|
}
|
|
29
31
|
get fpPosition() {
|
|
@@ -50,6 +52,7 @@ export class TransformComponent extends SoAComponent {
|
|
|
50
52
|
this._fpRotation.x = FP.FromRaw(this.store.arrays.fpRotationX[idx]);
|
|
51
53
|
this._fpRotation.y = FP.FromRaw(this.store.arrays.fpRotationY[idx]);
|
|
52
54
|
this._fpRotation.z = FP.FromRaw(this.store.arrays.fpRotationZ[idx]);
|
|
55
|
+
this._fpRotation.w = FP.FromRaw(this.store.arrays.fpRotationW[idx]);
|
|
53
56
|
return this._fpRotation;
|
|
54
57
|
}
|
|
55
58
|
set fpRotation(value) {
|
|
@@ -59,17 +62,22 @@ export class TransformComponent extends SoAComponent {
|
|
|
59
62
|
this.store.arrays.fpRotationX[idx] = FP.ToRaw(value.x);
|
|
60
63
|
this.store.arrays.fpRotationY[idx] = FP.ToRaw(value.y);
|
|
61
64
|
this.store.arrays.fpRotationZ[idx] = FP.ToRaw(value.z);
|
|
65
|
+
this.store.arrays.fpRotationW[idx] = FP.ToRaw(value.w);
|
|
66
|
+
}
|
|
67
|
+
get fpRotationEuler() {
|
|
68
|
+
return FPQuaternion.ToEulerXYZ(this.fpRotation);
|
|
69
|
+
}
|
|
70
|
+
set fpRotationEuler(value) {
|
|
71
|
+
this.fpRotation = FPQuaternion.FromEulerXYZ(value);
|
|
62
72
|
}
|
|
63
73
|
get fpRotationY() {
|
|
64
|
-
const
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
74
|
+
const q = this.fpRotation;
|
|
75
|
+
const two = FP.FromInt(2);
|
|
76
|
+
const sinY = FP.Mul(two, FP.Add(FP.Mul(q.w, q.y), FP.Mul(q.x, q.z)));
|
|
77
|
+
const cosY = FP.Sub(FP._1, FP.Mul(two, FP.Add(FP.Mul(q.y, q.y), FP.Mul(q.z, q.z))));
|
|
78
|
+
return FP.Atan2(sinY, cosY);
|
|
68
79
|
}
|
|
69
80
|
set fpRotationY(value) {
|
|
70
|
-
|
|
71
|
-
if (idx === -1)
|
|
72
|
-
return;
|
|
73
|
-
this.store.arrays.fpRotationY[idx] = FP.ToRaw(value);
|
|
81
|
+
this.fpRotation = FPQuaternion.FromYaw(value);
|
|
74
82
|
}
|
|
75
83
|
}
|
|
@@ -9,6 +9,7 @@ export interface InterpolatedTransformSample {
|
|
|
9
9
|
x: number;
|
|
10
10
|
y: number;
|
|
11
11
|
z: number;
|
|
12
|
+
w: number;
|
|
12
13
|
};
|
|
13
14
|
}
|
|
14
15
|
export declare class InterpolationSystem extends GameSystem implements IBeforeTick, IAfterTick, IBeforeFrame {
|
|
@@ -23,6 +24,7 @@ export declare class InterpolationSystem extends GameSystem implements IBeforeTi
|
|
|
23
24
|
capture(): void;
|
|
24
25
|
interpolate(alpha: number): void;
|
|
25
26
|
getInterpolatedTransform(entityId: number): InterpolatedTransformSample | undefined;
|
|
26
|
-
private
|
|
27
|
+
private readFpPosition;
|
|
28
|
+
private readFpRotation;
|
|
27
29
|
}
|
|
28
30
|
//# sourceMappingURL=InterpolationSystem.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"InterpolationSystem.d.ts","sourceRoot":"","sources":["../../src/systems/InterpolationSystem.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,UAAU,EACV,KAAK,aAAa,EAClB,KAAK,UAAU,EACf,KAAK,YAAY,EACjB,KAAK,WAAW,EAEhB,KAAK,aAAa,EACnB,MAAM,qBAAqB,CAAC;
|
|
1
|
+
{"version":3,"file":"InterpolationSystem.d.ts","sourceRoot":"","sources":["../../src/systems/InterpolationSystem.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,UAAU,EACV,KAAK,aAAa,EAClB,KAAK,UAAU,EACf,KAAK,YAAY,EACjB,KAAK,WAAW,EAEhB,KAAK,aAAa,EACnB,MAAM,qBAAqB,CAAC;AAc7B,MAAM,WAAW,2BAA2B;IAC1C,QAAQ,EAAE;QAAE,CAAC,EAAE,MAAM,CAAC;QAAC,CAAC,EAAE,MAAM,CAAC;QAAC,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;IAE9C,QAAQ,EAAE;QAAE,CAAC,EAAE,MAAM,CAAC;QAAC,CAAC,EAAE,MAAM,CAAC;QAAC,CAAC,EAAE,MAAM,CAAC;QAAC,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;CAC1D;AAWD,qBAAa,mBACX,SAAQ,UACR,YAAW,WAAW,EAAE,UAAU,EAAE,YAAY;IAEhD,OAAO,CAAC,cAAc,CAA2D;IACjF,OAAO,CAAC,QAAQ,CAAC,mBAAmB,CAAkD;IAEtF,OAAO,CAAC,QAAQ,CAAC,gBAAgB,CAAqB;IAEtC,IAAI,CAAC,OAAO,EAAE,aAAa,GAAG,IAAI;IAK3C,UAAU,CAAC,KAAK,EAAE,MAAM,EAAE,SAAS,EAAE,aAAa,GAAG,IAAI;IAIzD,SAAS,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI;IAI9B,WAAW,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,IAAI;IAI7C,QAAQ,IAAI,IAAI;IAOhB,OAAO,IAAI,IAAI;IAmCf,WAAW,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI;IAkChC,wBAAwB,CAAC,QAAQ,EAAE,MAAM,GAAG,2BAA2B,GAAG,SAAS;IAI1F,OAAO,CAAC,cAAc;IAStB,OAAO,CAAC,cAAc;CASvB"}
|
|
@@ -1,16 +1,7 @@
|
|
|
1
1
|
import { GameSystem, } from '@phalanx-engine/ecs';
|
|
2
|
-
import { FP, FPVector3 } from '@phalanx-engine/math';
|
|
2
|
+
import { FP, FPVector3, FPQuaternion, } from '@phalanx-engine/math';
|
|
3
3
|
import { INTERPOLATION_COMPONENT_TYPE, } from '../components';
|
|
4
4
|
import { TRANSFORM_COMPONENT_TYPE, TransformSoASchema } from '../components';
|
|
5
|
-
function lerpAngle(from, to, t) {
|
|
6
|
-
const clamped = Math.max(0, Math.min(1, t));
|
|
7
|
-
let delta = to - from;
|
|
8
|
-
if (delta > Math.PI)
|
|
9
|
-
delta -= 2 * Math.PI;
|
|
10
|
-
if (delta < -Math.PI)
|
|
11
|
-
delta += 2 * Math.PI;
|
|
12
|
-
return from + delta * clamped;
|
|
13
|
-
}
|
|
14
5
|
function lerpScalar(from, to, t) {
|
|
15
6
|
const clamped = Math.max(0, Math.min(1, t));
|
|
16
7
|
return from + (to - from) * clamped;
|
|
@@ -47,8 +38,8 @@ export class InterpolationSystem extends GameSystem {
|
|
|
47
38
|
const transformIndex = this.transformStore.indexOf(entity.id);
|
|
48
39
|
if (!interpolation || transformIndex === -1)
|
|
49
40
|
continue;
|
|
50
|
-
const fpPosition = this.
|
|
51
|
-
const fpRotation = this.
|
|
41
|
+
const fpPosition = this.readFpPosition(transformIndex);
|
|
42
|
+
const fpRotation = this.readFpRotation(transformIndex);
|
|
52
43
|
if (!this.capturedEntities.has(entity.id)) {
|
|
53
44
|
interpolation.capture(fpPosition, fpRotation);
|
|
54
45
|
interpolation.snapshot();
|
|
@@ -66,6 +57,7 @@ export class InterpolationSystem extends GameSystem {
|
|
|
66
57
|
}
|
|
67
58
|
interpolate(alpha) {
|
|
68
59
|
const clampedAlpha = Math.max(0, Math.min(1, alpha));
|
|
60
|
+
const fpAlpha = FP.FromFloat(clampedAlpha);
|
|
69
61
|
this.interpolatedSamples.clear();
|
|
70
62
|
const entities = this.entityManager.queryEntities(INTERPOLATION_COMPONENT_TYPE, TRANSFORM_COMPONENT_TYPE);
|
|
71
63
|
for (const entity of entities) {
|
|
@@ -74,31 +66,35 @@ export class InterpolationSystem extends GameSystem {
|
|
|
74
66
|
continue;
|
|
75
67
|
const previousPosition = FPVector3.ToFloat(interpolation.previousFpPosition);
|
|
76
68
|
const currentPosition = FPVector3.ToFloat(interpolation.currentFpPosition);
|
|
77
|
-
const
|
|
78
|
-
const currentRotation = FPVector3.ToFloat(interpolation.currentFpRotation);
|
|
69
|
+
const interpolatedRotation = FPQuaternion.Slerp(interpolation.previousFpRotation, interpolation.currentFpRotation, fpAlpha);
|
|
79
70
|
this.interpolatedSamples.set(entity.id, {
|
|
80
71
|
position: {
|
|
81
72
|
x: lerpScalar(previousPosition.x, currentPosition.x, clampedAlpha),
|
|
82
73
|
y: lerpScalar(previousPosition.y, currentPosition.y, clampedAlpha),
|
|
83
74
|
z: lerpScalar(previousPosition.z, currentPosition.z, clampedAlpha),
|
|
84
75
|
},
|
|
85
|
-
rotation:
|
|
86
|
-
x: lerpAngle(previousRotation.x, currentRotation.x, clampedAlpha),
|
|
87
|
-
y: lerpAngle(previousRotation.y, currentRotation.y, clampedAlpha),
|
|
88
|
-
z: lerpAngle(previousRotation.z, currentRotation.z, clampedAlpha),
|
|
89
|
-
},
|
|
76
|
+
rotation: FPQuaternion.ToFloat(interpolatedRotation),
|
|
90
77
|
});
|
|
91
78
|
}
|
|
92
79
|
}
|
|
93
80
|
getInterpolatedTransform(entityId) {
|
|
94
81
|
return this.interpolatedSamples.get(entityId);
|
|
95
82
|
}
|
|
96
|
-
|
|
83
|
+
readFpPosition(index) {
|
|
84
|
+
const arrays = this.transformStore.arrays;
|
|
85
|
+
return {
|
|
86
|
+
x: FP.FromRaw(arrays.fpPositionX[index]),
|
|
87
|
+
y: FP.FromRaw(arrays.fpPositionY[index]),
|
|
88
|
+
z: FP.FromRaw(arrays.fpPositionZ[index]),
|
|
89
|
+
};
|
|
90
|
+
}
|
|
91
|
+
readFpRotation(index) {
|
|
97
92
|
const arrays = this.transformStore.arrays;
|
|
98
93
|
return {
|
|
99
|
-
x: FP.FromRaw(arrays[
|
|
100
|
-
y: FP.FromRaw(arrays[
|
|
101
|
-
z: FP.FromRaw(arrays[
|
|
94
|
+
x: FP.FromRaw(arrays.fpRotationX[index]),
|
|
95
|
+
y: FP.FromRaw(arrays.fpRotationY[index]),
|
|
96
|
+
z: FP.FromRaw(arrays.fpRotationZ[index]),
|
|
97
|
+
w: FP.FromRaw(arrays.fpRotationW[index]),
|
|
102
98
|
};
|
|
103
99
|
}
|
|
104
100
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@phalanx-engine/physics",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.2",
|
|
4
4
|
"description": "Deterministic fixed-point physics engine for Phalanx Engine - spatial hashing, collision detection, and resolution",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -18,8 +18,8 @@
|
|
|
18
18
|
"devDependencies": {
|
|
19
19
|
"typescript": "~5.9.3",
|
|
20
20
|
"vitest": "^1.0.0",
|
|
21
|
-
"@phalanx-engine/ecs": "0.1.
|
|
22
|
-
"@phalanx-engine/math": "0.1.
|
|
21
|
+
"@phalanx-engine/ecs": "0.1.2",
|
|
22
|
+
"@phalanx-engine/math": "0.1.2"
|
|
23
23
|
},
|
|
24
24
|
"keywords": [
|
|
25
25
|
"physics",
|