@gg-web-engine/matter 0.0.72 → 0.0.74

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.
@@ -7,10 +7,11 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
7
7
  step((generator = generator.apply(thisArg, _arguments || [])).next());
8
8
  });
9
9
  };
10
- import { Pnt2, } from '@gg-web-engine/core';
11
- import { Engine, Events } from 'matter-js';
10
+ import { BitMask, Pnt2, } from '@gg-web-engine/core';
11
+ import { Composite, Detector, Engine, Events } from 'matter-js';
12
12
  import { MatterFactory } from '../matter-factory';
13
13
  import { Subject } from 'rxjs';
14
+ import { MatterRigidBodyComponent } from './matter-rigid-body.component';
14
15
  /**
15
16
  * Averages matter-js's collision support points into a single representative contact point for
16
17
  * `CollisionEvent.position`. `collision.supports` is *always* a fixed-length-2 array
@@ -34,6 +35,42 @@ function averageSupports(collision) {
34
35
  }
35
36
  return Pnt2.scalarMult(sum, 1 / supports.length);
36
37
  }
38
+ /**
39
+ * Standard 2D segment-vs-segment intersection (parametric form): `p1->p2` is the ray segment,
40
+ * `p3->p4` one polygon edge. Returns the intersection's fractional position along `p1->p2`
41
+ * (`t`, always in `[0,1]` when a result is returned) and the world-space point itself, or `null`
42
+ * for parallel/non-intersecting/out-of-range segments. Used by `MatterWorldComponent.raycast`
43
+ * (see its own doc for why) instead of matter-js's own `Query.ray`/`Collision.collides`, which
44
+ * only ever reports an approximate SAT contact point, not a true point where the ray segment
45
+ * crosses a candidate's actual boundary.
46
+ */
47
+ function segmentIntersection(p1, p2, p3, p4) {
48
+ const d1 = Pnt2.sub(p2, p1);
49
+ const d2 = Pnt2.sub(p4, p3);
50
+ const denom = d1.x * d2.y - d1.y * d2.x;
51
+ if (Math.abs(denom) < 1e-10) {
52
+ return null; // parallel (or degenerate) - no single intersection point
53
+ }
54
+ const diff = Pnt2.sub(p3, p1);
55
+ const t = (diff.x * d2.y - diff.y * d2.x) / denom;
56
+ const u = (diff.x * d1.y - diff.y * d1.x) / denom;
57
+ if (t < 0 || t > 1 || u < 0 || u > 1) {
58
+ return null;
59
+ }
60
+ return { t, point: Pnt2.add(p1, Pnt2.scalarMult(d1, t)) };
61
+ }
62
+ /**
63
+ * Every polygon (in matter-js's sense) making up `body`'s actual collision boundary, each as a
64
+ * closed loop of world-space vertices - `body` itself for a simple (non-compound) body, or every
65
+ * part but the synthetic index-0 "container" part for a compound one (mirrors `Query.collides`'s
66
+ * own `partsAStart = partsALength === 1 ? 0 : 1` convention). A circle is included via matter-js's
67
+ * own many-sided-polygon approximation (`Bodies.circle` is built on `Bodies.polygon`) - close
68
+ * enough for a raycast headroom check, not a true circle intersection.
69
+ */
70
+ function bodyPolygons(body) {
71
+ const parts = body.parts.length === 1 ? [body] : body.parts.slice(1);
72
+ return parts.map(part => part.vertices);
73
+ }
37
74
  // TODO probably should be configurable in world
38
75
  const MATTER_WORLD_SCALE = 0.0001;
39
76
  export class MatterWorldComponent {
@@ -61,7 +98,9 @@ export class MatterWorldComponent {
61
98
  /** Mirrors the rapier packages' `handleIdEntityMap` pattern: `Body.id` (matter-js's own
62
99
  * globally-unique numeric id, assigned once per body via `Body.nextId` and stable for its whole
63
100
  * lifetime) to component, kept in sync alongside `children` so `findRigidBody` - called once per
64
- * collision pair, per step - is an O(1) lookup instead of an O(n) `Array.find` scan. */
101
+ * collision pair, per step - is an O(1) lookup instead of an O(n) `Array.find` scan. Also used by
102
+ * `MatterCharacterControllerComponent.pushDynamicBodies` to resolve a native body it just bumped
103
+ * into back to its owning component. */
65
104
  this.handleIdEntityMap = new Map();
66
105
  this._gravity = { x: 0, y: 9.82 };
67
106
  this.mainCollisionGroup = 0;
@@ -79,6 +118,18 @@ export class MatterWorldComponent {
79
118
  this.handleCollisionStart = this.handleCollisionStart.bind(this);
80
119
  this.handleCollisionEnd = this.handleCollisionEnd.bind(this);
81
120
  }
121
+ /**
122
+ * `Engine.create` is never given `enableSleeping: true` here, matching matter-js's own default -
123
+ * so a body this world creates never *naturally* falls asleep from prolonged inactivity, no matter
124
+ * how long it rests. `IRigidBodyComponent.sleep()`/`wakeUp()` still work regardless of this flag
125
+ * (`Matter.Sleeping.set` writes a body's `isSleeping` flag directly, and `Engine.update`'s own
126
+ * per-body integration skip checks that flag unconditionally, not gated behind
127
+ * `engine.enableSleeping` - only the *automatic* fall-asleep-from-rest/wake-on-collision behavior
128
+ * is gated behind that flag) - only automatic, inactivity-driven sleeping is unavailable under the
129
+ * current setup. A future change enabling it should re-check
130
+ * `gg-engine-physics-adapter-matter`'s own note on this before assuming every existing
131
+ * position/velocity setter still behaves the same way once bodies can sleep on their own.
132
+ */
82
133
  init() {
83
134
  return __awaiter(this, void 0, void 0, function* () {
84
135
  this.matterEngine_ = Engine.create({
@@ -89,7 +140,11 @@ export class MatterWorldComponent {
89
140
  });
90
141
  }
91
142
  findRigidBody(nativeBody) {
92
- return this.handleIdEntityMap.get(nativeBody.id);
143
+ // a character controller's phantom body is never added to `Composite`/`engine.world` (see its
144
+ // own doc), so it can never actually be `pair.bodyA`/`pair.bodyB` here - this narrows the lookup's
145
+ // type back down since `handleIdEntityMap` itself now also tracks that component class.
146
+ const comp = this.handleIdEntityMap.get(nativeBody.id);
147
+ return comp instanceof MatterRigidBodyComponent ? comp : undefined;
93
148
  }
94
149
  /**
95
150
  * Wires `IRigidBody2dComponent.onCollisionStart` for every non-sensor pair in the world, off
@@ -173,8 +228,79 @@ export class MatterWorldComponent {
173
228
  Engine.update(this.matterEngine, delta, this.lastDelta > 0 ? delta / this.lastDelta : 1);
174
229
  this.lastDelta = delta;
175
230
  }
231
+ /**
232
+ * matter-js has no native raycast query. Built on a true parametric ray-vs-polygon intersection
233
+ * (`segmentIntersection`/`bodyPolygons`), not `Matter.Query.ray` - that helper is only a thin
234
+ * wrapper over `Query.collides` (a full-geometry SAT test of a synthetic, very thin rectangle body
235
+ * against candidates), which reports an approximate overlap contact point, not a true "where does
236
+ * the ray segment first cross this body's boundary" point; verified via this adapter's own
237
+ * regression suite (`MatterWorldComponent.spec.ts`'s `Raycast` block expects a precise hit point at
238
+ * a known box edge) that the SAT-approximated version produces a visibly wrong point.
239
+ *
240
+ * `Query.collides`/`Collision.collides` test raw geometry only and know nothing about
241
+ * `collisionFilter` (the same limitation `MatterCharacterControllerComponent.collectObstacles`'s
242
+ * own doc describes) - candidates are pre-filtered here via `Detector.canCollide` itself, called
243
+ * directly against a synthetic filter built from `options.collisionFilterGroups`/
244
+ * `collisionFilterMask`. Sensor bodies (triggers) are excluded from candidates entirely, mirroring
245
+ * `collectObstacles`'s own exclusion - a trigger never physically blocks anything, so it shouldn't
246
+ * register as a raycast hit either.
247
+ *
248
+ * `hitNormal` is derived from whichever polygon edge the closest intersection landed on (rotated
249
+ * 90°, sign chosen to point back towards `options.from`) - not from a matter-js collision object at
250
+ * all, sidestepping the sign-convention pitfall `handleCollisionStart`'s own doc describes for
251
+ * `pair.collision.normal`.
252
+ */
176
253
  raycast(options) {
177
- throw new Error('Ray casting is not implemented for Matter.js');
254
+ var _a;
255
+ const matterWorld = this.matterWorld;
256
+ const direction = Pnt2.sub(options.to, options.from);
257
+ const rayLength = Pnt2.len(direction);
258
+ if (!matterWorld || rayLength === 0) {
259
+ return { hasHit: false };
260
+ }
261
+ const groupsMask = options.collisionFilterGroups
262
+ ? BitMask.pack(options.collisionFilterGroups, 16)
263
+ : BitMask.full(16);
264
+ const maskMask = options.collisionFilterMask ? BitMask.pack(options.collisionFilterMask, 16) : BitMask.full(16);
265
+ const rayFilter = { category: groupsMask, mask: maskMask, group: 0 };
266
+ const candidates = Composite.allBodies(matterWorld).filter(b => !b.isSensor && Detector.canCollide(rayFilter, b.collisionFilter));
267
+ let closestT = Infinity;
268
+ let closestPoint = null;
269
+ let closestNormal = null;
270
+ let closestBody = null;
271
+ for (const body of candidates) {
272
+ for (const polygon of bodyPolygons(body)) {
273
+ for (let i = 0; i < polygon.length; i++) {
274
+ const a = polygon[i];
275
+ const b = polygon[(i + 1) % polygon.length];
276
+ const hit = segmentIntersection(options.from, options.to, a, b);
277
+ if (!hit || hit.t >= closestT) {
278
+ continue;
279
+ }
280
+ closestT = hit.t;
281
+ closestPoint = hit.point;
282
+ closestBody = body;
283
+ const edge = Pnt2.sub(b, a);
284
+ const normal = Pnt2.norm({ x: -edge.y, y: edge.x });
285
+ closestNormal = Pnt2.dot(normal, Pnt2.sub(options.from, hit.point)) >= 0 ? normal : Pnt2.neg(normal);
286
+ }
287
+ }
288
+ }
289
+ if (!closestBody) {
290
+ return { hasHit: false };
291
+ }
292
+ // A compound body's hit part is not the parent body `handleIdEntityMap` is keyed by (see
293
+ // `MatterFactory`'s compound-shape flattening) - `.parent` (self-referential for a non-compound
294
+ // body) resolves back to it.
295
+ const parentBody = (_a = closestBody.parent) !== null && _a !== void 0 ? _a : closestBody;
296
+ const resolved = this.handleIdEntityMap.get(parentBody.id);
297
+ return {
298
+ hasHit: true,
299
+ hitBody: resolved instanceof MatterRigidBodyComponent ? resolved : undefined,
300
+ hitDistance: closestT * rayLength,
301
+ hitPoint: closestPoint,
302
+ hitNormal: closestNormal,
303
+ };
178
304
  }
179
305
  dispose() {
180
306
  Events.off(this.matterEngine, 'collisionStart', this.handleCollisionStart);
package/dist/index.d.ts CHANGED
@@ -1,3 +1,4 @@
1
+ export * from './components/matter-character-controller.component';
1
2
  export * from './components/matter-rigid-body.component';
2
3
  export * from './components/matter-trigger.component';
3
4
  export * from './components/matter-world.component';
package/dist/index.js CHANGED
@@ -1,3 +1,4 @@
1
+ export * from './components/matter-character-controller.component';
1
2
  export * from './components/matter-rigid-body.component';
2
3
  export * from './components/matter-trigger.component';
3
4
  export * from './components/matter-world.component';
@@ -1,6 +1,7 @@
1
- import { BodyShape2DDescriptor, IPhysicsBody2dComponentFactory, Point2, Shape2DDescriptor } from '@gg-web-engine/core';
1
+ import { BodyShape2DDescriptor, CharacterController2dOptions, IPhysicsBody2dComponentFactory, Point2, Shape2DDescriptor } from '@gg-web-engine/core';
2
2
  import { MatterRigidBodyComponent } from './components/matter-rigid-body.component';
3
3
  import { MatterTriggerComponent } from './components/matter-trigger.component';
4
+ import { MatterCharacterControllerComponent } from './components/matter-character-controller.component';
4
5
  import { MatterWorldComponent } from './components/matter-world.component';
5
6
  import { MatterPhysicsTypeDocRepo } from './types';
6
7
  export declare class MatterFactory implements IPhysicsBody2dComponentFactory<MatterPhysicsTypeDocRepo> {
@@ -14,6 +15,12 @@ export declare class MatterFactory implements IPhysicsBody2dComponentFactory<Mat
14
15
  position?: Point2;
15
16
  rotation?: number;
16
17
  }): MatterTriggerComponent;
18
+ createCharacterController(options: CharacterController2dOptions, transform?: {
19
+ position?: Point2;
20
+ rotation?: number;
21
+ }): MatterCharacterControllerComponent;
22
+ private createShapeParts;
23
+ private createShapeBody;
17
24
  /**
18
25
  * matter-js's own body model only has `isStatic` - no distinct kinematic body type (position-
19
26
  * driven, but still pushes/wakes dynamic bodies it moves into) and no continuous collision
@@ -1,7 +1,17 @@
1
- import { warnOnce, } from '@gg-web-engine/core';
1
+ import { Pnt2, warnOnce, } from '@gg-web-engine/core';
2
2
  import { MatterRigidBodyComponent } from './components/matter-rigid-body.component';
3
3
  import { MatterTriggerComponent } from './components/matter-trigger.component';
4
- import { Bodies, Vector } from 'matter-js';
4
+ import { MatterCharacterControllerComponent } from './components/matter-character-controller.component';
5
+ import { Bodies, Body, Common, Vector } from 'matter-js';
6
+ import * as decomp from 'poly-decomp';
7
+ /**
8
+ * `Bodies.fromVertices` (used for the `POLYGON` shape below) only actually decomposes a concave
9
+ * vertex set into convex parts when a decomposition library is registered via `Common.setDecomp` -
10
+ * without it, matter-js silently falls back to the convex hull of the given vertices, so a concave
11
+ * `POLYGON` would render/collide as if it were convex. Registering `poly-decomp` here, once, at
12
+ * module load makes `Bodies.fromVertices` actually decompose concave outlines everywhere it's used.
13
+ */
14
+ Common.setDecomp(decomp);
5
15
  /**
6
16
  * `kinematic_pos`/`kinematic_vel`/`ccd` have no native matter-js equivalent at all - unlike
7
17
  * `packages/ammo`/`packages/rapier2d`/`packages/rapier3d`, this package can only warn and fall
@@ -19,45 +29,140 @@ export class MatterFactory {
19
29
  this.world = world;
20
30
  }
21
31
  createRigidBody(descriptor, transform) {
22
- var _a, _b;
32
+ var _a, _b, _c;
23
33
  let nativeBody = null;
24
34
  switch (descriptor.shape.shape) {
25
- case 'SQUARE':
35
+ case 'BOX':
26
36
  nativeBody = Bodies.rectangle(0, 0, descriptor.shape.dimensions.x, descriptor.shape.dimensions.y, this.transformOptions(descriptor.body));
27
37
  break;
28
38
  case 'CIRCLE':
29
39
  nativeBody = Bodies.circle(0, 0, descriptor.shape.radius, this.transformOptions(descriptor.body));
30
40
  break;
41
+ case 'CAPSULE':
42
+ nativeBody = Bodies.rectangle(0, 0, descriptor.shape.radius * 2, descriptor.shape.centersDistance + descriptor.shape.radius * 2, {
43
+ chamfer: {
44
+ radius: descriptor.shape.radius,
45
+ },
46
+ });
47
+ break;
48
+ case 'CONVEX_HULL':
49
+ nativeBody = Bodies.fromVertices(0, 0, [Pnt2.hull(descriptor.shape.vertices).map(v => Vector.create(v.x, v.y))], this.transformOptions(descriptor.body));
50
+ break;
51
+ case 'POLYGON':
52
+ nativeBody = Bodies.fromVertices(0, 0, [descriptor.shape.vertices.map(v => Vector.create(v.x, v.y))], this.transformOptions(descriptor.body));
53
+ break;
54
+ case 'COMPOUND':
55
+ nativeBody = this.createShapeBody(descriptor.shape, this.transformOptions(descriptor.body));
56
+ break;
31
57
  }
32
58
  if (!nativeBody) {
33
59
  throw new Error(`Shape "${descriptor.shape}" not implemented for Matter.js`);
34
60
  }
35
- nativeBody.position = Vector.create(((_a = transform === null || transform === void 0 ? void 0 : transform.position) === null || _a === void 0 ? void 0 : _a.x) || 0, ((_b = transform === null || transform === void 0 ? void 0 : transform.position) === null || _b === void 0 ? void 0 : _b.y) || 0);
36
- nativeBody.angle = (transform === null || transform === void 0 ? void 0 : transform.rotation) || 0;
37
- return new MatterRigidBodyComponent(nativeBody, descriptor.shape);
61
+ // Must go through `Body.setPosition`/`Body.setAngle` (not a raw `nativeBody.position = ...`
62
+ // field assignment) - see `gg-engine-physics-adapter-matter`'s own note on this: a body's
63
+ // `vertices`/`bounds` (what every actual collision query reads) are only ever translated to
64
+ // match `.position` at creation time, using whatever position was passed into
65
+ // `Bodies.rectangle`/`Bodies.circle`/`Bodies.fromVertices` itself (always `(0, 0)` here) - a
66
+ // later raw field write changes what `.position` *reports* without moving the real collision
67
+ // geometry at all, permanently desyncing the two until something else (ordinary simulation,
68
+ // which this character-controller-adjacent code path can't rely on) happens to correct it.
69
+ Body.setPosition(nativeBody, Vector.create(((_a = transform === null || transform === void 0 ? void 0 : transform.position) === null || _a === void 0 ? void 0 : _a.x) || 0, ((_b = transform === null || transform === void 0 ? void 0 : transform.position) === null || _b === void 0 ? void 0 : _b.y) || 0));
70
+ Body.setAngle(nativeBody, (transform === null || transform === void 0 ? void 0 : transform.rotation) || 0);
71
+ const bodyType = (_c = descriptor.body.bodyType) !== null && _c !== void 0 ? _c : (descriptor.body.mass ? 'dynamic' : 'static');
72
+ const component = new MatterRigidBodyComponent(nativeBody, descriptor.shape, bodyType, !!descriptor.body.ccd);
73
+ // `transformOptions` (used to build `nativeBody` above) only ever reads
74
+ // `bodyType`/`mass`/`restitution`/`friction` - `ownCollisionGroups`/`interactWithCollisionGroups`
75
+ // must be applied through the component's own setters afterward (same as
76
+ // `MatterCharacterControllerComponent`'s constructor already does for a character), or a
77
+ // configured collision group is silently dropped in favor of the "all groups" default every
78
+ // `MatterRigidBodyComponent` otherwise starts with.
79
+ if (descriptor.body.ownCollisionGroups !== undefined) {
80
+ component.ownCollisionGroups = descriptor.body.ownCollisionGroups;
81
+ }
82
+ if (descriptor.body.interactWithCollisionGroups !== undefined) {
83
+ component.interactWithCollisionGroups = descriptor.body.interactWithCollisionGroups;
84
+ }
85
+ return component;
38
86
  }
39
87
  createTrigger(descriptor, transform) {
40
88
  var _a, _b;
41
89
  let nativeBody = null;
42
90
  switch (descriptor.shape) {
43
- case 'SQUARE':
91
+ case 'BOX':
44
92
  nativeBody = Bodies.rectangle(0, 0, descriptor.dimensions.x, descriptor.dimensions.y, { isSensor: true });
45
93
  break;
46
94
  case 'CIRCLE':
47
95
  nativeBody = Bodies.circle(0, 0, descriptor.radius, { isSensor: true });
48
96
  break;
97
+ case 'CAPSULE':
98
+ nativeBody = Bodies.rectangle(0, 0, descriptor.radius * 2, descriptor.centersDistance + descriptor.radius * 2, {
99
+ isSensor: true,
100
+ chamfer: {
101
+ radius: descriptor.radius,
102
+ },
103
+ });
104
+ break;
105
+ case 'CONVEX_HULL':
106
+ nativeBody = Bodies.fromVertices(0, 0, [Pnt2.hull(descriptor.vertices).map(v => Vector.create(v.x, v.y))], {
107
+ isSensor: true,
108
+ });
109
+ break;
110
+ case 'POLYGON':
111
+ nativeBody = Bodies.fromVertices(0, 0, [descriptor.vertices.map(v => Vector.create(v.x, v.y))], {
112
+ isSensor: true,
113
+ });
114
+ break;
115
+ case 'COMPOUND':
116
+ nativeBody = this.createShapeBody(descriptor, { isSensor: true });
117
+ break;
49
118
  }
50
119
  if (!nativeBody) {
51
120
  throw new Error(`Shape "${descriptor.shape}" not implemented for Matter.js`);
52
121
  }
53
- nativeBody.position.x = ((_a = transform === null || transform === void 0 ? void 0 : transform.position) === null || _a === void 0 ? void 0 : _a.x) || 0;
54
- nativeBody.position.y = ((_b = transform === null || transform === void 0 ? void 0 : transform.position) === null || _b === void 0 ? void 0 : _b.y) || 0;
55
- nativeBody.angle = (transform === null || transform === void 0 ? void 0 : transform.rotation) || 0;
122
+ // See the identical fix (and its doc) in `createRigidBody` above - a trigger's collision
123
+ // geometry needs the same real `Body.setPosition`/`Body.setAngle` treatment, not a raw
124
+ // `.position.x`/`.position.y`/`.angle` field write.
125
+ Body.setPosition(nativeBody, Vector.create(((_a = transform === null || transform === void 0 ? void 0 : transform.position) === null || _a === void 0 ? void 0 : _a.x) || 0, ((_b = transform === null || transform === void 0 ? void 0 : transform.position) === null || _b === void 0 ? void 0 : _b.y) || 0));
126
+ Body.setAngle(nativeBody, (transform === null || transform === void 0 ? void 0 : transform.rotation) || 0);
56
127
  if (!this.world) {
57
128
  throw new Error('MatterFactory: World not set. Make sure the factory is created by MatterWorldComponent.');
58
129
  }
59
130
  return new MatterTriggerComponent(nativeBody, descriptor, this.world);
60
131
  }
132
+ createCharacterController(options, transform) {
133
+ return new MatterCharacterControllerComponent(this.world, options, transform);
134
+ }
135
+ createShapeParts(shape, options) {
136
+ switch (shape.shape) {
137
+ case 'BOX':
138
+ return [Bodies.rectangle(0, 0, shape.dimensions.x, shape.dimensions.y, options)];
139
+ case 'CIRCLE':
140
+ return [Bodies.circle(0, 0, shape.radius, options)];
141
+ case 'CAPSULE':
142
+ return [
143
+ Bodies.rectangle(0, 0, shape.radius * 2, shape.centersDistance + shape.radius * 2, Object.assign(Object.assign({}, options), { chamfer: { radius: shape.radius } })),
144
+ ];
145
+ case 'CONVEX_HULL':
146
+ return [Bodies.fromVertices(0, 0, [Pnt2.hull(shape.vertices).map(v => Vector.create(v.x, v.y))], options)];
147
+ case 'POLYGON':
148
+ return [Bodies.fromVertices(0, 0, [shape.vertices.map(v => Vector.create(v.x, v.y))], options)];
149
+ case 'COMPOUND': {
150
+ const parts = [];
151
+ for (const { position, rotation, shape: childShape } of shape.children) {
152
+ const childParts = this.createShapeParts(childShape, options);
153
+ for (const part of childParts) {
154
+ Body.setPosition(part, Vector.add(Vector.rotate(part.position, rotation || 0), Vector.create((position === null || position === void 0 ? void 0 : position.x) || 0, (position === null || position === void 0 ? void 0 : position.y) || 0)));
155
+ Body.setAngle(part, part.angle + (rotation || 0));
156
+ }
157
+ parts.push(...childParts);
158
+ }
159
+ return parts;
160
+ }
161
+ }
162
+ }
163
+ createShapeBody(shape, options) {
164
+ return Body.create(Object.assign({ parts: this.createShapeParts(shape, options) }, options));
165
+ }
61
166
  /**
62
167
  * matter-js's own body model only has `isStatic` - no distinct kinematic body type (position-
63
168
  * driven, but still pushes/wakes dynamic bodies it moves into) and no continuous collision
package/dist/types.d.ts CHANGED
@@ -1,12 +1,14 @@
1
1
  import { MatterFactory } from './matter-factory';
2
2
  import { MatterRigidBodyComponent } from './components/matter-rigid-body.component';
3
3
  import { MatterTriggerComponent } from './components/matter-trigger.component';
4
+ import { MatterCharacterControllerComponent } from './components/matter-character-controller.component';
4
5
  import { Gg2dWorld, Gg2dWorldSceneTypeDocPPatch, Gg2dWorldTypeDocPPatch } from '@gg-web-engine/core';
5
6
  import { MatterWorldComponent } from './components/matter-world.component';
6
7
  export type MatterPhysicsTypeDocRepo = {
7
8
  factory: MatterFactory;
8
9
  rigidBody: MatterRigidBodyComponent;
9
10
  trigger: MatterTriggerComponent;
11
+ characterController: MatterCharacterControllerComponent;
10
12
  };
11
13
  export type MatterTypeDoc = Gg2dWorldTypeDocPPatch<MatterPhysicsTypeDocRepo>;
12
14
  export type MatterSceneTypeDoc = Gg2dWorldSceneTypeDocPPatch<MatterPhysicsTypeDocRepo, MatterWorldComponent>;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@gg-web-engine/matter",
3
- "version": "0.0.72",
3
+ "version": "0.0.74",
4
4
  "description": "An attempt to create open source game engine for browser",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -27,11 +27,12 @@
27
27
  },
28
28
  "homepage": "https://github.com/AndyGura/gg-web-engine#readme",
29
29
  "dependencies": {
30
+ "poly-decomp": "^0.3.0"
30
31
  },
31
32
  "devDependencies": {
32
- "@types/matter-js": "0.20.2",
33
- "@gg-web-engine/core": "0.0.72",
33
+ "@gg-web-engine/core": "0.0.74",
34
34
  "@types/jest": "^30.0.0",
35
+ "@types/matter-js": "0.20.2",
35
36
  "@types/node": "^26.4.0",
36
37
  "jest": "^30.5.0",
37
38
  "jest-environment-jsdom": "^30.5.0",
@@ -42,7 +43,7 @@
42
43
  "typescript": "~6.0.3"
43
44
  },
44
45
  "peerDependencies": {
45
- "@gg-web-engine/core": "0.0.72",
46
+ "@gg-web-engine/core": "0.0.74",
46
47
  "matter-js": "0.20.0",
47
48
  "rxjs": "7.8.2"
48
49
  },