@phalanx-engine/physics 0.1.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.
Files changed (65) hide show
  1. package/README.md +437 -0
  2. package/dist/PhysicsWorld.d.ts +35 -0
  3. package/dist/PhysicsWorld.d.ts.map +1 -0
  4. package/dist/PhysicsWorld.js +112 -0
  5. package/dist/PhysicsWorldConfig.d.ts +21 -0
  6. package/dist/PhysicsWorldConfig.d.ts.map +1 -0
  7. package/dist/PhysicsWorldConfig.js +1 -0
  8. package/dist/collision/CollisionManifold.d.ts +9 -0
  9. package/dist/collision/CollisionManifold.d.ts.map +1 -0
  10. package/dist/collision/CollisionManifold.js +1 -0
  11. package/dist/collision/NarrowPhase.d.ts +8 -0
  12. package/dist/collision/NarrowPhase.d.ts.map +1 -0
  13. package/dist/collision/NarrowPhase.js +112 -0
  14. package/dist/collision/SpatialHashGrid.d.ts +19 -0
  15. package/dist/collision/SpatialHashGrid.d.ts.map +1 -0
  16. package/dist/collision/SpatialHashGrid.js +125 -0
  17. package/dist/collision/index.d.ts +4 -0
  18. package/dist/collision/index.d.ts.map +1 -0
  19. package/dist/collision/index.js +2 -0
  20. package/dist/components/InterpolationComponent.d.ts +15 -0
  21. package/dist/components/InterpolationComponent.d.ts.map +1 -0
  22. package/dist/components/InterpolationComponent.js +32 -0
  23. package/dist/components/PhysicsBodyComponent.d.ts +53 -0
  24. package/dist/components/PhysicsBodyComponent.d.ts.map +1 -0
  25. package/dist/components/PhysicsBodyComponent.js +157 -0
  26. package/dist/components/TransformComponent.d.ts +32 -0
  27. package/dist/components/TransformComponent.d.ts.map +1 -0
  28. package/dist/components/TransformComponent.js +75 -0
  29. package/dist/components/index.d.ts +4 -0
  30. package/dist/components/index.d.ts.map +1 -0
  31. package/dist/components/index.js +3 -0
  32. package/dist/events.d.ts +7 -0
  33. package/dist/events.d.ts.map +1 -0
  34. package/dist/events.js +6 -0
  35. package/dist/index.d.ts +17 -0
  36. package/dist/index.d.ts.map +1 -0
  37. package/dist/index.js +8 -0
  38. package/dist/systems/CollisionSystem.d.ts +20 -0
  39. package/dist/systems/CollisionSystem.d.ts.map +1 -0
  40. package/dist/systems/CollisionSystem.js +150 -0
  41. package/dist/systems/InterpolationSystem.d.ts +28 -0
  42. package/dist/systems/InterpolationSystem.d.ts.map +1 -0
  43. package/dist/systems/InterpolationSystem.js +104 -0
  44. package/dist/systems/PhysicsSystem.d.ts +41 -0
  45. package/dist/systems/PhysicsSystem.d.ts.map +1 -0
  46. package/dist/systems/PhysicsSystem.js +316 -0
  47. package/dist/systems/index.d.ts +5 -0
  48. package/dist/systems/index.d.ts.map +1 -0
  49. package/dist/systems/index.js +3 -0
  50. package/dist/tick/AutonomousPhysicsTickProvider.d.ts +18 -0
  51. package/dist/tick/AutonomousPhysicsTickProvider.d.ts.map +1 -0
  52. package/dist/tick/AutonomousPhysicsTickProvider.js +39 -0
  53. package/dist/tick/ExternalPhysicsTickProvider.d.ts +8 -0
  54. package/dist/tick/ExternalPhysicsTickProvider.d.ts.map +1 -0
  55. package/dist/tick/ExternalPhysicsTickProvider.js +6 -0
  56. package/dist/tick/IPhysicsTickProvider.d.ts +5 -0
  57. package/dist/tick/IPhysicsTickProvider.d.ts.map +1 -0
  58. package/dist/tick/IPhysicsTickProvider.js +1 -0
  59. package/dist/tick/index.d.ts +5 -0
  60. package/dist/tick/index.d.ts.map +1 -0
  61. package/dist/tick/index.js +2 -0
  62. package/dist/types.d.ts +37 -0
  63. package/dist/types.d.ts.map +1 -0
  64. package/dist/types.js +1 -0
  65. package/package.json +55 -0
@@ -0,0 +1,112 @@
1
+ import { FP } from '@phalanx-engine/math';
2
+ const EPSILON = FP.FromFloat(0.0001);
3
+ export class NarrowPhase {
4
+ static circleVsCircle(posAX, posAZ, radiusA, posBX, posBZ, radiusB, entityA, entityB) {
5
+ const dx = FP.Sub(posBX, posAX);
6
+ const dz = FP.Sub(posBZ, posAZ);
7
+ const distSq = FP.Add(FP.Mul(dx, dx), FP.Mul(dz, dz));
8
+ const minDist = FP.Add(radiusA, radiusB);
9
+ const minDistSq = FP.Mul(minDist, minDist);
10
+ if (FP.Gte(distSq, minDistSq)) {
11
+ return null;
12
+ }
13
+ if (FP.Lte(distSq, FP.Mul(EPSILON, EPSILON))) {
14
+ return {
15
+ entityA,
16
+ entityB,
17
+ normalX: FP._1,
18
+ normalZ: FP._0,
19
+ penetration: minDist,
20
+ };
21
+ }
22
+ const dist = FP.Sqrt(distSq);
23
+ const penetration = FP.Sub(minDist, dist);
24
+ const normalX = FP.Div(dx, dist);
25
+ const normalZ = FP.Div(dz, dist);
26
+ return { entityA, entityB, normalX, normalZ, penetration };
27
+ }
28
+ static circleVsAABB(circlePosX, circlePosZ, circleRadius, aabbMinX, aabbMinZ, aabbMaxX, aabbMaxZ, entityCircle, entityAABB) {
29
+ const closestX = FP.Clamp(circlePosX, aabbMinX, aabbMaxX);
30
+ const closestZ = FP.Clamp(circlePosZ, aabbMinZ, aabbMaxZ);
31
+ const dx = FP.Sub(circlePosX, closestX);
32
+ const dz = FP.Sub(circlePosZ, closestZ);
33
+ const distSq = FP.Add(FP.Mul(dx, dx), FP.Mul(dz, dz));
34
+ const radiusSq = FP.Mul(circleRadius, circleRadius);
35
+ if (FP.Gte(distSq, radiusSq)) {
36
+ return null;
37
+ }
38
+ if (FP.Lte(distSq, FP.Mul(EPSILON, EPSILON))) {
39
+ const halfW = FP.Mul(FP.Sub(aabbMaxX, aabbMinX), FP.FromFloat(0.5));
40
+ const halfH = FP.Mul(FP.Sub(aabbMaxZ, aabbMinZ), FP.FromFloat(0.5));
41
+ const centerX = FP.Add(aabbMinX, halfW);
42
+ const centerZ = FP.Add(aabbMinZ, halfH);
43
+ const ox = FP.Sub(circlePosX, centerX);
44
+ const oz = FP.Sub(circlePosZ, centerZ);
45
+ const overlapX = FP.Sub(FP.Add(halfW, circleRadius), FP.Abs(ox));
46
+ const overlapZ = FP.Sub(FP.Add(halfH, circleRadius), FP.Abs(oz));
47
+ if (FP.Lt(overlapX, overlapZ)) {
48
+ const sign = FP.Gte(ox, FP._0) ? FP._1 : FP.Neg(FP._1);
49
+ return {
50
+ entityA: entityCircle,
51
+ entityB: entityAABB,
52
+ normalX: sign,
53
+ normalZ: FP._0,
54
+ penetration: overlapX,
55
+ };
56
+ }
57
+ else {
58
+ const sign = FP.Gte(oz, FP._0) ? FP._1 : FP.Neg(FP._1);
59
+ return {
60
+ entityA: entityCircle,
61
+ entityB: entityAABB,
62
+ normalX: FP._0,
63
+ normalZ: sign,
64
+ penetration: overlapZ,
65
+ };
66
+ }
67
+ }
68
+ const dist = FP.Sqrt(distSq);
69
+ const penetration = FP.Sub(circleRadius, dist);
70
+ const normalX = FP.Div(dx, dist);
71
+ const normalZ = FP.Div(dz, dist);
72
+ return {
73
+ entityA: entityCircle,
74
+ entityB: entityAABB,
75
+ normalX,
76
+ normalZ,
77
+ penetration,
78
+ };
79
+ }
80
+ static aabbVsAABB(aMinX, aMinZ, aMaxX, aMaxZ, bMinX, bMinZ, bMaxX, bMaxZ, entityA, entityB) {
81
+ const overlapX1 = FP.Sub(aMaxX, bMinX);
82
+ const overlapX2 = FP.Sub(bMaxX, aMinX);
83
+ const overlapZ1 = FP.Sub(aMaxZ, bMinZ);
84
+ const overlapZ2 = FP.Sub(bMaxZ, aMinZ);
85
+ if (FP.Lte(overlapX1, FP._0) || FP.Lte(overlapX2, FP._0) ||
86
+ FP.Lte(overlapZ1, FP._0) || FP.Lte(overlapZ2, FP._0)) {
87
+ return null;
88
+ }
89
+ const minOverlapX = FP.Min(overlapX1, overlapX2);
90
+ const minOverlapZ = FP.Min(overlapZ1, overlapZ2);
91
+ if (FP.Lt(minOverlapX, minOverlapZ)) {
92
+ const sign = FP.Lt(overlapX1, overlapX2) ? FP._1 : FP.Neg(FP._1);
93
+ return {
94
+ entityA,
95
+ entityB,
96
+ normalX: sign,
97
+ normalZ: FP._0,
98
+ penetration: minOverlapX,
99
+ };
100
+ }
101
+ else {
102
+ const sign = FP.Lt(overlapZ1, overlapZ2) ? FP._1 : FP.Neg(FP._1);
103
+ return {
104
+ entityA,
105
+ entityB,
106
+ normalX: FP._0,
107
+ normalZ: sign,
108
+ penetration: minOverlapZ,
109
+ };
110
+ }
111
+ }
112
+ }
@@ -0,0 +1,19 @@
1
+ import { type FixedPoint } from '@phalanx-engine/math';
2
+ export declare class SpatialHashGrid {
3
+ private readonly cellSize;
4
+ private readonly cells;
5
+ private readonly entityCells;
6
+ private readonly entityPosX;
7
+ private readonly entityPosZ;
8
+ private readonly _pairsResult;
9
+ private readonly _radiusResult;
10
+ constructor(cellSize: FixedPoint);
11
+ insert(entityId: number, posX: FixedPoint, posZ: FixedPoint, radius: FixedPoint): void;
12
+ remove(entityId: number): void;
13
+ update(entityId: number, posX: FixedPoint, posZ: FixedPoint, radius: FixedPoint): void;
14
+ queryPairs(): [number, number][];
15
+ queryRadius(posX: FixedPoint, posZ: FixedPoint, radius: FixedPoint): number[];
16
+ clear(): void;
17
+ private getCoveredCells;
18
+ }
19
+ //# sourceMappingURL=SpatialHashGrid.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"SpatialHashGrid.d.ts","sourceRoot":"","sources":["../../src/collision/SpatialHashGrid.ts"],"names":[],"mappings":"AAAA,OAAO,EAAM,KAAK,UAAU,EAAE,MAAM,sBAAsB,CAAC;AAW3D,qBAAa,eAAe;IAC1B,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAa;IACtC,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAoC;IAG1D,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAoC;IAMhE,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAsC;IACjE,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAsC;IAGjE,OAAO,CAAC,QAAQ,CAAC,YAAY,CAA0B;IAGvD,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAgB;gBAElC,QAAQ,EAAE,UAAU;IAOzB,MAAM,CAAC,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,UAAU,EAAE,IAAI,EAAE,UAAU,EAAE,MAAM,EAAE,UAAU,GAAG,IAAI;IAoBtF,MAAM,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI;IA0B9B,MAAM,CAAC,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,UAAU,EAAE,IAAI,EAAE,UAAU,EAAE,MAAM,EAAE,UAAU,GAAG,IAAI;IActF,UAAU,IAAI,CAAC,MAAM,EAAE,MAAM,CAAC,EAAE;IAuChC,WAAW,CAAC,IAAI,EAAE,UAAU,EAAE,IAAI,EAAE,UAAU,EAAE,MAAM,EAAE,UAAU,GAAG,MAAM,EAAE;IAiC7E,KAAK,IAAI,IAAI;IAUpB,OAAO,CAAC,eAAe;CAmBxB"}
@@ -0,0 +1,125 @@
1
+ import { FP } from '@phalanx-engine/math';
2
+ export class SpatialHashGrid {
3
+ cellSize;
4
+ cells = new Map();
5
+ entityCells = new Map();
6
+ entityPosX = new Map();
7
+ entityPosZ = new Map();
8
+ _pairsResult = [];
9
+ _radiusResult = [];
10
+ constructor(cellSize) {
11
+ this.cellSize = cellSize;
12
+ }
13
+ insert(entityId, posX, posZ, radius) {
14
+ const cellKeys = this.getCoveredCells(posX, posZ, radius);
15
+ this.entityCells.set(entityId, cellKeys);
16
+ this.entityPosX.set(entityId, posX);
17
+ this.entityPosZ.set(entityId, posZ);
18
+ for (const key of cellKeys) {
19
+ let cell = this.cells.get(key);
20
+ if (!cell) {
21
+ cell = [];
22
+ this.cells.set(key, cell);
23
+ }
24
+ cell.push(entityId);
25
+ }
26
+ }
27
+ remove(entityId) {
28
+ const cellKeys = this.entityCells.get(entityId);
29
+ if (!cellKeys)
30
+ return;
31
+ for (const key of cellKeys) {
32
+ const cell = this.cells.get(key);
33
+ if (cell) {
34
+ const idx = cell.indexOf(entityId);
35
+ if (idx !== -1) {
36
+ cell[idx] = cell[cell.length - 1];
37
+ cell.pop();
38
+ }
39
+ if (cell.length === 0) {
40
+ this.cells.delete(key);
41
+ }
42
+ }
43
+ }
44
+ this.entityCells.delete(entityId);
45
+ this.entityPosX.delete(entityId);
46
+ this.entityPosZ.delete(entityId);
47
+ }
48
+ update(entityId, posX, posZ, radius) {
49
+ this.remove(entityId);
50
+ this.insert(entityId, posX, posZ, radius);
51
+ }
52
+ queryPairs() {
53
+ this._pairsResult.length = 0;
54
+ const seen = new Set();
55
+ for (const cell of this.cells.values()) {
56
+ const len = cell.length;
57
+ for (let i = 0; i < len; i++) {
58
+ for (let j = i + 1; j < len; j++) {
59
+ const a = cell[i];
60
+ const b = cell[j];
61
+ const lo = a < b ? a : b;
62
+ const hi = a < b ? b : a;
63
+ const key = `${lo},${hi}`;
64
+ if (!seen.has(key)) {
65
+ seen.add(key);
66
+ this._pairsResult.push([lo, hi]);
67
+ }
68
+ }
69
+ }
70
+ }
71
+ this._pairsResult.sort((a, b) => a[0] - b[0] || a[1] - b[1]);
72
+ return this._pairsResult;
73
+ }
74
+ queryRadius(posX, posZ, radius) {
75
+ this._radiusResult.length = 0;
76
+ const seen = new Set();
77
+ const radiusSq = FP.Mul(radius, radius);
78
+ const cellKeys = this.getCoveredCells(posX, posZ, radius);
79
+ for (const key of cellKeys) {
80
+ const cell = this.cells.get(key);
81
+ if (!cell)
82
+ continue;
83
+ for (const id of cell) {
84
+ if (seen.has(id))
85
+ continue;
86
+ seen.add(id);
87
+ const px = this.entityPosX.get(id);
88
+ const pz = this.entityPosZ.get(id);
89
+ if (px === undefined || pz === undefined)
90
+ continue;
91
+ const dx = FP.Sub(px, posX);
92
+ const dz = FP.Sub(pz, posZ);
93
+ const distanceSq = FP.Add(FP.Mul(dx, dx), FP.Mul(dz, dz));
94
+ if (FP.Lte(distanceSq, radiusSq)) {
95
+ this._radiusResult.push(id);
96
+ }
97
+ }
98
+ }
99
+ this._radiusResult.sort((a, b) => a - b);
100
+ return this._radiusResult;
101
+ }
102
+ clear() {
103
+ this.cells.clear();
104
+ this.entityCells.clear();
105
+ this.entityPosX.clear();
106
+ this.entityPosZ.clear();
107
+ }
108
+ getCoveredCells(posX, posZ, radius) {
109
+ const minX = FP.Sub(posX, radius);
110
+ const maxX = FP.Add(posX, radius);
111
+ const minZ = FP.Sub(posZ, radius);
112
+ const maxZ = FP.Add(posZ, radius);
113
+ const cellMinX = FP.ToFloat(FP.Floor(FP.Div(minX, this.cellSize)));
114
+ const cellMaxX = FP.ToFloat(FP.Floor(FP.Div(maxX, this.cellSize)));
115
+ const cellMinZ = FP.ToFloat(FP.Floor(FP.Div(minZ, this.cellSize)));
116
+ const cellMaxZ = FP.ToFloat(FP.Floor(FP.Div(maxZ, this.cellSize)));
117
+ const keys = [];
118
+ for (let cx = cellMinX; cx <= cellMaxX; cx++) {
119
+ for (let cz = cellMinZ; cz <= cellMaxZ; cz++) {
120
+ keys.push(`${cx},${cz}`);
121
+ }
122
+ }
123
+ return keys;
124
+ }
125
+ }
@@ -0,0 +1,4 @@
1
+ export type { CollisionManifold } from './CollisionManifold';
2
+ export { SpatialHashGrid } from './SpatialHashGrid';
3
+ export { NarrowPhase } from './NarrowPhase';
4
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/collision/index.ts"],"names":[],"mappings":"AAAA,YAAY,EAAE,iBAAiB,EAAE,MAAM,qBAAqB,CAAC;AAC7D,OAAO,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AACpD,OAAO,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC"}
@@ -0,0 +1,2 @@
1
+ export { SpatialHashGrid } from './SpatialHashGrid';
2
+ export { NarrowPhase } from './NarrowPhase';
@@ -0,0 +1,15 @@
1
+ import type { IComponent } from '@phalanx-engine/ecs';
2
+ import type { FPVector3 as FPVector3Type } from '@phalanx-engine/math';
3
+ export declare const INTERPOLATION_COMPONENT_TYPE: symbol;
4
+ export declare class InterpolationComponent implements IComponent {
5
+ readonly type: symbol;
6
+ readonly previousFpPosition: FPVector3Type;
7
+ readonly currentFpPosition: FPVector3Type;
8
+ readonly previousFpRotation: FPVector3Type;
9
+ readonly currentFpRotation: FPVector3Type;
10
+ constructor(initialPosition?: FPVector3Type, initialRotation?: FPVector3Type);
11
+ snapshot(): void;
12
+ capture(fpPosition: FPVector3Type, fpRotation: FPVector3Type): void;
13
+ private copyFpVector3;
14
+ }
15
+ //# sourceMappingURL=InterpolationComponent.d.ts.map
@@ -0,0 +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,EAAE,SAAS,IAAI,aAAa,EAAE,MAAM,sBAAsB,CAAC;AAMvE,eAAO,MAAM,4BAA4B,EAAE,MAAgC,CAAC;AAS5E,qBAAa,sBAAuB,YAAW,UAAU;IACvD,SAAgB,IAAI,SAAgC;IAEpD,SAAgB,kBAAkB,EAAE,aAAa,CAAoC;IACrF,SAAgB,iBAAiB,EAAE,aAAa,CAAoC;IACpF,SAAgB,kBAAkB,EAAE,aAAa,CAAoC;IACrF,SAAgB,iBAAiB,EAAE,aAAa,CAAoC;gBAExE,eAAe,CAAC,EAAE,aAAa,EAAE,eAAe,CAAC,EAAE,aAAa;IAYrE,QAAQ,IAAI,IAAI;IAMhB,OAAO,CAAC,UAAU,EAAE,aAAa,EAAE,UAAU,EAAE,aAAa,GAAG,IAAI;IAK1E,OAAO,CAAC,aAAa;CAKtB"}
@@ -0,0 +1,32 @@
1
+ import { FP } from '@phalanx-engine/math';
2
+ export const INTERPOLATION_COMPONENT_TYPE = Symbol('Interpolation');
3
+ export class InterpolationComponent {
4
+ type = INTERPOLATION_COMPONENT_TYPE;
5
+ previousFpPosition = { x: FP._0, y: FP._0, z: FP._0 };
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 };
9
+ constructor(initialPosition, initialRotation) {
10
+ if (initialPosition) {
11
+ this.copyFpVector3(this.previousFpPosition, initialPosition);
12
+ this.copyFpVector3(this.currentFpPosition, initialPosition);
13
+ }
14
+ if (initialRotation) {
15
+ this.copyFpVector3(this.previousFpRotation, initialRotation);
16
+ this.copyFpVector3(this.currentFpRotation, initialRotation);
17
+ }
18
+ }
19
+ snapshot() {
20
+ this.copyFpVector3(this.previousFpPosition, this.currentFpPosition);
21
+ this.copyFpVector3(this.previousFpRotation, this.currentFpRotation);
22
+ }
23
+ capture(fpPosition, fpRotation) {
24
+ this.copyFpVector3(this.currentFpPosition, fpPosition);
25
+ this.copyFpVector3(this.currentFpRotation, fpRotation);
26
+ }
27
+ copyFpVector3(target, source) {
28
+ target.x = source.x;
29
+ target.y = source.y;
30
+ target.z = source.z;
31
+ }
32
+ }
@@ -0,0 +1,53 @@
1
+ import { SoAComponent } from '@phalanx-engine/ecs';
2
+ import { type FixedPoint, type FPVector3 as FPVector3Type } from '@phalanx-engine/math';
3
+ import type { PhysicsBodyConfig } from '../types';
4
+ export declare const PhysicsSoASchema: import("@phalanx-engine/ecs").SoASchema<{
5
+ velocityX: "i64";
6
+ velocityY: "i64";
7
+ velocityZ: "i64";
8
+ radius: "i64";
9
+ mass: "i64";
10
+ restitution: "i64";
11
+ friction: "i64";
12
+ isStatic: "u8";
13
+ ignorePhysics: "u8";
14
+ lastX: "f64";
15
+ lastZ: "f64";
16
+ }>;
17
+ export declare const PHYSICS_BODY_COMPONENT_TYPE: symbol;
18
+ export declare class PhysicsBodyComponent extends SoAComponent<typeof PhysicsSoASchema.definition> {
19
+ readonly type: symbol;
20
+ static readonly soaSchema: import("@phalanx-engine/ecs").SoASchema<{
21
+ velocityX: "i64";
22
+ velocityY: "i64";
23
+ velocityZ: "i64";
24
+ radius: "i64";
25
+ mass: "i64";
26
+ restitution: "i64";
27
+ friction: "i64";
28
+ isStatic: "u8";
29
+ ignorePhysics: "u8";
30
+ lastX: "f64";
31
+ lastZ: "f64";
32
+ }>;
33
+ private readonly _velocity;
34
+ constructor(entityId: number, config: PhysicsBodyConfig);
35
+ get velocity(): FPVector3Type;
36
+ set velocity(value: FPVector3Type);
37
+ setVelocity(x: FixedPoint, y: FixedPoint, z: FixedPoint): void;
38
+ addVelocity(velocity: FPVector3Type): void;
39
+ stopVelocity(): void;
40
+ get radius(): FixedPoint;
41
+ get radiusFloat(): number;
42
+ get mass(): FixedPoint;
43
+ get restitution(): FixedPoint;
44
+ get friction(): FixedPoint;
45
+ get isStatic(): boolean;
46
+ get ignorePhysics(): boolean;
47
+ set ignorePhysics(value: boolean);
48
+ get lastX(): number;
49
+ set lastX(value: number);
50
+ get lastZ(): number;
51
+ set lastZ(value: number);
52
+ }
53
+ //# sourceMappingURL=PhysicsBodyComponent.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"PhysicsBodyComponent.d.ts","sourceRoot":"","sources":["../../src/components/PhysicsBodyComponent.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAmB,MAAM,qBAAqB,CAAC;AACpE,OAAO,EAAM,KAAK,UAAU,EAAE,KAAK,SAAS,IAAI,aAAa,EAAE,MAAM,sBAAsB,CAAC;AAC5F,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,UAAU,CAAC;AAQlD,eAAO,MAAM,gBAAgB;;;;;;;;;;;;EAYZ,CAAC;AAMlB,eAAO,MAAM,2BAA2B,EAAE,MAA8B,CAAC;AAgBzE,qBAAa,oBAAqB,SAAQ,YAAY,CAAC,OAAO,gBAAgB,CAAC,UAAU,CAAC;IACxF,SAAgB,IAAI,SAA+B;IACnD,MAAM,CAAC,QAAQ,CAAC,SAAS;;;;;;;;;;;;OAAoB;IAG7C,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAmD;gBAEjE,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,iBAAiB;IA0BvD,IAAW,QAAQ,IAAI,aAAa,CAOnC;IAED,IAAW,QAAQ,CAAC,KAAK,EAAE,aAAa,EAMvC;IAGM,WAAW,CAAC,CAAC,EAAE,UAAU,EAAE,CAAC,EAAE,UAAU,EAAE,CAAC,EAAE,UAAU,GAAG,IAAI;IAS9D,WAAW,CAAC,QAAQ,EAAE,aAAa,GAAG,IAAI;IAY1C,YAAY,IAAI,IAAI;IAW3B,IAAW,MAAM,IAAI,UAAU,CAI9B;IAED,IAAW,WAAW,IAAI,MAAM,CAI/B;IAID,IAAW,IAAI,IAAI,UAAU,CAI5B;IAID,IAAW,WAAW,IAAI,UAAU,CAInC;IAID,IAAW,QAAQ,IAAI,UAAU,CAIhC;IAID,IAAW,QAAQ,IAAI,OAAO,CAI7B;IAID,IAAW,aAAa,IAAI,OAAO,CAIlC;IAED,IAAW,aAAa,CAAC,KAAK,EAAE,OAAO,EAItC;IAID,IAAW,KAAK,IAAI,MAAM,CAIzB;IAED,IAAW,KAAK,CAAC,KAAK,EAAE,MAAM,EAI7B;IAED,IAAW,KAAK,IAAI,MAAM,CAIzB;IAED,IAAW,KAAK,CAAC,KAAK,EAAE,MAAM,EAI7B;CACF"}
@@ -0,0 +1,157 @@
1
+ import { SoAComponent, defineSoASchema } from '@phalanx-engine/ecs';
2
+ import { FP } from '@phalanx-engine/math';
3
+ export const PhysicsSoASchema = defineSoASchema({
4
+ velocityX: 'i64',
5
+ velocityY: 'i64',
6
+ velocityZ: 'i64',
7
+ radius: 'i64',
8
+ mass: 'i64',
9
+ restitution: 'i64',
10
+ friction: 'i64',
11
+ isStatic: 'u8',
12
+ ignorePhysics: 'u8',
13
+ lastX: 'f64',
14
+ lastZ: 'f64',
15
+ }, 'PhysicsBody');
16
+ export const PHYSICS_BODY_COMPONENT_TYPE = Symbol('PhysicsBody');
17
+ export class PhysicsBodyComponent extends SoAComponent {
18
+ type = PHYSICS_BODY_COMPONENT_TYPE;
19
+ static soaSchema = PhysicsSoASchema;
20
+ _velocity = { x: FP._0, y: FP._0, z: FP._0 };
21
+ constructor(entityId, config) {
22
+ const mass = config.mass ?? FP._1;
23
+ const restitution = config.restitution ?? FP.FromFloat(0.5);
24
+ const friction = config.friction ?? FP._0;
25
+ const isStatic = config.isStatic ?? false;
26
+ super(PhysicsSoASchema, entityId, {
27
+ velocityX: FP.ToRaw(FP._0),
28
+ velocityY: FP.ToRaw(FP._0),
29
+ velocityZ: FP.ToRaw(FP._0),
30
+ radius: FP.ToRaw(config.radius),
31
+ mass: FP.ToRaw(mass),
32
+ restitution: FP.ToRaw(restitution),
33
+ friction: FP.ToRaw(friction),
34
+ isStatic: isStatic ? 1 : 0,
35
+ ignorePhysics: 0,
36
+ lastX: 0,
37
+ lastZ: 0,
38
+ });
39
+ }
40
+ get velocity() {
41
+ const idx = this.getIndex();
42
+ if (idx === -1)
43
+ return this._velocity;
44
+ this._velocity.x = FP.FromRaw(this.store.arrays.velocityX[idx]);
45
+ this._velocity.y = FP.FromRaw(this.store.arrays.velocityY[idx]);
46
+ this._velocity.z = FP.FromRaw(this.store.arrays.velocityZ[idx]);
47
+ return this._velocity;
48
+ }
49
+ set velocity(value) {
50
+ const idx = this.getIndex();
51
+ if (idx === -1)
52
+ return;
53
+ this.store.arrays.velocityX[idx] = FP.ToRaw(value.x);
54
+ this.store.arrays.velocityY[idx] = FP.ToRaw(value.y);
55
+ this.store.arrays.velocityZ[idx] = FP.ToRaw(value.z);
56
+ }
57
+ setVelocity(x, y, z) {
58
+ const idx = this.getIndex();
59
+ if (idx === -1)
60
+ return;
61
+ this.store.arrays.velocityX[idx] = FP.ToRaw(x);
62
+ this.store.arrays.velocityY[idx] = FP.ToRaw(y);
63
+ this.store.arrays.velocityZ[idx] = FP.ToRaw(z);
64
+ }
65
+ addVelocity(velocity) {
66
+ const idx = this.getIndex();
67
+ if (idx === -1)
68
+ return;
69
+ const currentX = FP.FromRaw(this.store.arrays.velocityX[idx]);
70
+ const currentY = FP.FromRaw(this.store.arrays.velocityY[idx]);
71
+ const currentZ = FP.FromRaw(this.store.arrays.velocityZ[idx]);
72
+ this.store.arrays.velocityX[idx] = FP.ToRaw(FP.Add(currentX, velocity.x));
73
+ this.store.arrays.velocityY[idx] = FP.ToRaw(FP.Add(currentY, velocity.y));
74
+ this.store.arrays.velocityZ[idx] = FP.ToRaw(FP.Add(currentZ, velocity.z));
75
+ }
76
+ stopVelocity() {
77
+ const idx = this.getIndex();
78
+ if (idx === -1)
79
+ return;
80
+ const zero = FP.ToRaw(FP._0);
81
+ this.store.arrays.velocityX[idx] = zero;
82
+ this.store.arrays.velocityY[idx] = zero;
83
+ this.store.arrays.velocityZ[idx] = zero;
84
+ }
85
+ get radius() {
86
+ const idx = this.getIndex();
87
+ if (idx === -1)
88
+ return FP._1;
89
+ return FP.FromRaw(this.store.arrays.radius[idx]);
90
+ }
91
+ get radiusFloat() {
92
+ const idx = this.getIndex();
93
+ if (idx === -1)
94
+ return 1;
95
+ return FP.ToFloat(FP.FromRaw(this.store.arrays.radius[idx]));
96
+ }
97
+ get mass() {
98
+ const idx = this.getIndex();
99
+ if (idx === -1)
100
+ return FP._1;
101
+ return FP.FromRaw(this.store.arrays.mass[idx]);
102
+ }
103
+ get restitution() {
104
+ const idx = this.getIndex();
105
+ if (idx === -1)
106
+ return FP.FromFloat(0.5);
107
+ return FP.FromRaw(this.store.arrays.restitution[idx]);
108
+ }
109
+ get friction() {
110
+ const idx = this.getIndex();
111
+ if (idx === -1)
112
+ return FP.FromFloat(0.3);
113
+ return FP.FromRaw(this.store.arrays.friction[idx]);
114
+ }
115
+ get isStatic() {
116
+ const idx = this.getIndex();
117
+ if (idx === -1)
118
+ return false;
119
+ return this.store.arrays.isStatic[idx] === 1;
120
+ }
121
+ get ignorePhysics() {
122
+ const idx = this.getIndex();
123
+ if (idx === -1)
124
+ return false;
125
+ return this.store.arrays.ignorePhysics[idx] === 1;
126
+ }
127
+ set ignorePhysics(value) {
128
+ const idx = this.getIndex();
129
+ if (idx === -1)
130
+ return;
131
+ this.store.arrays.ignorePhysics[idx] = value ? 1 : 0;
132
+ }
133
+ get lastX() {
134
+ const idx = this.getIndex();
135
+ if (idx === -1)
136
+ return 0;
137
+ return this.store.arrays.lastX[idx];
138
+ }
139
+ set lastX(value) {
140
+ const idx = this.getIndex();
141
+ if (idx === -1)
142
+ return;
143
+ this.store.arrays.lastX[idx] = value;
144
+ }
145
+ get lastZ() {
146
+ const idx = this.getIndex();
147
+ if (idx === -1)
148
+ return 0;
149
+ return this.store.arrays.lastZ[idx];
150
+ }
151
+ set lastZ(value) {
152
+ const idx = this.getIndex();
153
+ if (idx === -1)
154
+ return;
155
+ this.store.arrays.lastZ[idx] = value;
156
+ }
157
+ }
@@ -0,0 +1,32 @@
1
+ import { SoAComponent } from '@phalanx-engine/ecs';
2
+ import { type FixedPoint, type FPVector3 as FPVector3Type } from '@phalanx-engine/math';
3
+ export declare const TransformSoASchema: import("@phalanx-engine/ecs").SoASchema<{
4
+ fpPositionX: "i64";
5
+ fpPositionY: "i64";
6
+ fpPositionZ: "i64";
7
+ fpRotationX: "i64";
8
+ fpRotationY: "i64";
9
+ fpRotationZ: "i64";
10
+ }>;
11
+ export declare const TRANSFORM_COMPONENT_TYPE: symbol;
12
+ export declare class TransformComponent extends SoAComponent<typeof TransformSoASchema.definition> {
13
+ readonly type: symbol;
14
+ static readonly soaSchema: import("@phalanx-engine/ecs").SoASchema<{
15
+ fpPositionX: "i64";
16
+ fpPositionY: "i64";
17
+ fpPositionZ: "i64";
18
+ fpRotationX: "i64";
19
+ fpRotationY: "i64";
20
+ fpRotationZ: "i64";
21
+ }>;
22
+ private readonly _fpPosition;
23
+ private readonly _fpRotation;
24
+ constructor(entityId: number, initialPosition?: FPVector3Type, initialRotation?: FPVector3Type);
25
+ get fpPosition(): FPVector3Type;
26
+ set fpPosition(value: FPVector3Type);
27
+ get fpRotation(): FPVector3Type;
28
+ set fpRotation(value: FPVector3Type);
29
+ get fpRotationY(): FixedPoint;
30
+ set fpRotationY(value: FixedPoint);
31
+ }
32
+ //# sourceMappingURL=TransformComponent.d.ts.map
@@ -0,0 +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,EAAiB,KAAK,UAAU,EAAE,KAAK,SAAS,IAAI,aAAa,EAAE,MAAM,sBAAsB,CAAC;AAQvG,eAAO,MAAM,kBAAkB;;;;;;;EAU9B,CAAC;AAMF,eAAO,MAAM,wBAAwB,EAAE,MAA4B,CAAC;AAapE,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,CAAmD;gBAG7E,QAAQ,EAAE,MAAM,EAChB,eAAe,CAAC,EAAE,aAAa,EAC/B,eAAe,CAAC,EAAE,aAAa;IAejC,IAAW,UAAU,IAAI,aAAa,CASrC;IAED,IAAW,UAAU,CAAC,KAAK,EAAE,aAAa,EAQzC;IAED,IAAW,UAAU,IAAI,aAAa,CAQrC;IAED,IAAW,UAAU,CAAC,KAAK,EAAE,aAAa,EAOzC;IAED,IAAW,WAAW,IAAI,UAAU,CAInC;IAED,IAAW,WAAW,CAAC,KAAK,EAAE,UAAU,EAIvC;CACF"}
@@ -0,0 +1,75 @@
1
+ import { SoAComponent, defineSoASchema } from '@phalanx-engine/ecs';
2
+ import { FP, FPVector3 } from '@phalanx-engine/math';
3
+ export const TransformSoASchema = defineSoASchema({
4
+ fpPositionX: 'i64',
5
+ fpPositionY: 'i64',
6
+ fpPositionZ: 'i64',
7
+ fpRotationX: 'i64',
8
+ fpRotationY: 'i64',
9
+ fpRotationZ: 'i64',
10
+ }, 'Transform');
11
+ export const TRANSFORM_COMPONENT_TYPE = Symbol('Transform');
12
+ export class TransformComponent extends SoAComponent {
13
+ type = TRANSFORM_COMPONENT_TYPE;
14
+ static soaSchema = TransformSoASchema;
15
+ _fpPosition = { x: FP._0, y: FP._0, z: FP._0 };
16
+ _fpRotation = { x: FP._0, y: FP._0, z: FP._0 };
17
+ constructor(entityId, initialPosition, initialRotation) {
18
+ const position = initialPosition ?? FPVector3.Zero;
19
+ const rotation = initialRotation ?? FPVector3.Zero;
20
+ super(TransformSoASchema, entityId, {
21
+ fpPositionX: FP.ToRaw(position.x),
22
+ fpPositionY: FP.ToRaw(position.y),
23
+ fpPositionZ: FP.ToRaw(position.z),
24
+ fpRotationX: FP.ToRaw(rotation.x),
25
+ fpRotationY: FP.ToRaw(rotation.y),
26
+ fpRotationZ: FP.ToRaw(rotation.z),
27
+ });
28
+ }
29
+ get fpPosition() {
30
+ const idx = this.getIndex();
31
+ if (idx === -1)
32
+ return this._fpPosition;
33
+ this._fpPosition.x = FP.FromRaw(this.store.arrays.fpPositionX[idx]);
34
+ this._fpPosition.y = FP.FromRaw(this.store.arrays.fpPositionY[idx]);
35
+ this._fpPosition.z = FP.FromRaw(this.store.arrays.fpPositionZ[idx]);
36
+ return this._fpPosition;
37
+ }
38
+ set fpPosition(value) {
39
+ const idx = this.getIndex();
40
+ if (idx === -1)
41
+ return;
42
+ this.store.arrays.fpPositionX[idx] = FP.ToRaw(value.x);
43
+ this.store.arrays.fpPositionY[idx] = FP.ToRaw(value.y);
44
+ this.store.arrays.fpPositionZ[idx] = FP.ToRaw(value.z);
45
+ }
46
+ get fpRotation() {
47
+ const idx = this.getIndex();
48
+ if (idx === -1)
49
+ return this._fpRotation;
50
+ this._fpRotation.x = FP.FromRaw(this.store.arrays.fpRotationX[idx]);
51
+ this._fpRotation.y = FP.FromRaw(this.store.arrays.fpRotationY[idx]);
52
+ this._fpRotation.z = FP.FromRaw(this.store.arrays.fpRotationZ[idx]);
53
+ return this._fpRotation;
54
+ }
55
+ set fpRotation(value) {
56
+ const idx = this.getIndex();
57
+ if (idx === -1)
58
+ return;
59
+ this.store.arrays.fpRotationX[idx] = FP.ToRaw(value.x);
60
+ this.store.arrays.fpRotationY[idx] = FP.ToRaw(value.y);
61
+ this.store.arrays.fpRotationZ[idx] = FP.ToRaw(value.z);
62
+ }
63
+ get fpRotationY() {
64
+ const idx = this.getIndex();
65
+ if (idx === -1)
66
+ return FP._0;
67
+ return FP.FromRaw(this.store.arrays.fpRotationY[idx]);
68
+ }
69
+ set fpRotationY(value) {
70
+ const idx = this.getIndex();
71
+ if (idx === -1)
72
+ return;
73
+ this.store.arrays.fpRotationY[idx] = FP.ToRaw(value);
74
+ }
75
+ }
@@ -0,0 +1,4 @@
1
+ export { PhysicsBodyComponent, PhysicsSoASchema, PHYSICS_BODY_COMPONENT_TYPE } from './PhysicsBodyComponent';
2
+ export { TransformComponent, TransformSoASchema, TRANSFORM_COMPONENT_TYPE } from './TransformComponent';
3
+ export { InterpolationComponent, INTERPOLATION_COMPONENT_TYPE, } from './InterpolationComponent';
4
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/components/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,oBAAoB,EAAE,gBAAgB,EAAE,2BAA2B,EAAE,MAAM,wBAAwB,CAAC;AAC7G,OAAO,EAAE,kBAAkB,EAAE,kBAAkB,EAAE,wBAAwB,EAAE,MAAM,sBAAsB,CAAC;AACxG,OAAO,EACL,sBAAsB,EACtB,4BAA4B,GAC7B,MAAM,0BAA0B,CAAC"}
@@ -0,0 +1,3 @@
1
+ export { PhysicsBodyComponent, PhysicsSoASchema, PHYSICS_BODY_COMPONENT_TYPE } from './PhysicsBodyComponent';
2
+ export { TransformComponent, TransformSoASchema, TRANSFORM_COMPONENT_TYPE } from './TransformComponent';
3
+ export { InterpolationComponent, INTERPOLATION_COMPONENT_TYPE, } from './InterpolationComponent';