@phalanx-engine/physics 0.1.1 → 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 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) mesh.position.set(sample.position.x, sample.position.y, sample.position.z);
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
- entity.addComponent(new TransformComponent(entity.id, fpPosition));
180
- entity.addComponent(new InterpolationComponent(fpPosition));
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 position/rotation for rendering, populated after `InterpolationSystem` runs.
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?: FPVector3);
322
+ constructor(entityId: number, initialPosition?: FPVector3, initialRotation?: FPQuaternion);
318
323
 
319
- fpPosition: FPVector3; // get/set — authoritative fixed-point position
320
- fpRotation: FPVector3; // get/set — authoritative fixed-point rotation (radians)
321
- fpRotationY: FixedPoint; // get/set — convenience for Y-axis rotation
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
- `TransformSoASchema` fields: `fpPositionX/Y/Z`, `fpRotationX/Y/Z` (all `i64`).
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?: FPVector3);
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: FPVector3): void; // capture authoritative state after tick
344
+ capture(fpPosition: FPVector3, fpRotation: FPQuaternion): void; // capture authoritative state after tick
337
345
  }
338
346
  ```
339
347
 
@@ -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,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,CAEnC;IAED,IAAW,WAAW,CAAC,KAAK,EAAE,UAAU,EAEvC;CACF"}
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"}
@@ -71,9 +71,13 @@ export class TransformComponent extends SoAComponent {
71
71
  this.fpRotation = FPQuaternion.FromEulerXYZ(value);
72
72
  }
73
73
  get fpRotationY() {
74
- return this.fpRotationEuler.y;
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);
75
79
  }
76
80
  set fpRotationY(value) {
77
- this.fpRotation = FPQuaternion.FromAxisAngle(FPVector3.Up, value);
81
+ this.fpRotation = FPQuaternion.FromYaw(value);
78
82
  }
79
83
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@phalanx-engine/physics",
3
- "version": "0.1.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.1",
22
- "@phalanx-engine/math": "0.1.1"
21
+ "@phalanx-engine/ecs": "0.1.2",
22
+ "@phalanx-engine/math": "0.1.2"
23
23
  },
24
24
  "keywords": [
25
25
  "physics",