excalibur 0.32.0-alpha.19 → 0.32.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.
@@ -1,4 +1,4 @@
1
- /*! excalibur - 0.32.0-alpha.19+57bc004 - 2025-12-22
1
+ /*! excalibur - 0.32.0 - 2025-12-23
2
2
  https://github.com/excaliburjs/Excalibur
3
3
  Copyright (c) 2025 Excalibur.js <https://github.com/excaliburjs/Excalibur/graphs/contributors>
4
4
  Licensed BSD-2-Clause
@@ -512,18 +512,13 @@ Licensed BSD-2-Clause
512
512
  return Math.abs(val1 - val2) < tolerance;
513
513
  }
514
514
  function canonicalizeAngle(angle) {
515
- let tmpAngle = angle;
516
- if (angle >= TwoPI) {
517
- while (tmpAngle >= TwoPI) {
518
- tmpAngle -= TwoPI;
519
- }
520
- }
521
- if (angle < 0) {
522
- while (tmpAngle < 0) {
523
- tmpAngle += TwoPI;
524
- }
525
- }
526
- return tmpAngle;
515
+ const TWO_PI = 2 * Math.PI;
516
+ return (angle % TWO_PI + TWO_PI) % TWO_PI;
517
+ }
518
+ function angleDifference(angle1, angle2) {
519
+ const TWO_PI = 2 * Math.PI;
520
+ const diff = Math.abs(angle1 - angle2);
521
+ return Math.min(diff, TWO_PI - diff);
527
522
  }
528
523
  function toDegrees(radians) {
529
524
  return 180 / Math.PI * radians;
@@ -5927,18 +5922,32 @@ mask: ${(this.mask >>> 0).toString(2).padStart(32, "0")}
5927
5922
  * @param elapsed time in milliseconds
5928
5923
  */
5929
5924
  updateSystems(type, scene, elapsed) {
5925
+ var _a, _b, _c;
5930
5926
  const systems = this.systems.filter((s) => s.systemType === type);
5931
- for (const s of systems) {
5932
- if (s.preupdate) {
5933
- s.preupdate(scene, elapsed);
5927
+ const stats = (_c = (_b = (_a = scene == null ? void 0 : scene.engine) == null ? void 0 : _a.stats) == null ? void 0 : _b.currFrame) != null ? _c : { systemDuration: {} };
5928
+ let startTime;
5929
+ let endTime;
5930
+ const systemsLength = systems.length;
5931
+ for (let i = 0; i < systemsLength; i++) {
5932
+ if (systems[i].preupdate) {
5933
+ startTime = performance.now();
5934
+ systems[i].preupdate(scene, elapsed);
5935
+ endTime = performance.now();
5936
+ stats.systemDuration[`${type}:${systems[i].constructor.name}.preupdate`] = endTime - startTime;
5934
5937
  }
5935
5938
  }
5936
- for (const s of systems) {
5937
- s.update(elapsed);
5939
+ for (let i = 0; i < systemsLength; i++) {
5940
+ startTime = performance.now();
5941
+ systems[i].update(elapsed);
5942
+ endTime = performance.now();
5943
+ stats.systemDuration[`${type}:${systems[i].constructor.name}.update`] = endTime - startTime;
5938
5944
  }
5939
- for (const s of systems) {
5940
- if (s.postupdate) {
5941
- s.postupdate(scene, elapsed);
5945
+ for (let i = 0; i < systemsLength; i++) {
5946
+ if (systems[i].postupdate) {
5947
+ startTime = performance.now();
5948
+ systems[i].postupdate(scene, elapsed);
5949
+ endTime = performance.now();
5950
+ stats.systemDuration[`${type}:${systems[i].constructor.name}.postupdate`] = endTime - startTime;
5942
5951
  }
5943
5952
  }
5944
5953
  }
@@ -7196,10 +7205,11 @@ Check your bundler settings to make sure this is not the case! Excalibur has ESM
7196
7205
  surfaceEpsilon: 0.1
7197
7206
  },
7198
7207
  bodies: {
7199
- canSleepByDefault: false,
7208
+ canSleepByDefault: true,
7200
7209
  sleepEpsilon: 0.07,
7201
7210
  wakeThreshold: 0.07 * 3,
7202
- sleepBias: 0.9,
7211
+ sleepBias: 0.5,
7212
+ sleepTimeThreshold: 1e3,
7203
7213
  defaultMass: 10
7204
7214
  },
7205
7215
  spatialPartition: SpatialPartitionStrategy.SparseHashGrid,
@@ -7839,23 +7849,6 @@ Check your bundler settings to make sure this is not the case! Excalibur has ESM
7839
7849
  this.bodyB = this.colliderB.owner.get(BodyComponent);
7840
7850
  }
7841
7851
  }
7842
- /**
7843
- * Match contact awake state, except if body's are Fixed
7844
- */
7845
- matchAwake() {
7846
- const bodyA = this.bodyA;
7847
- const bodyB = this.bodyB;
7848
- if (bodyA && bodyB) {
7849
- if (bodyA.isSleeping !== bodyB.isSleeping) {
7850
- if (bodyA.isSleeping && bodyA.collisionType !== CollisionType.Fixed && bodyB.sleepMotion >= bodyA.wakeThreshold) {
7851
- bodyA.isSleeping = false;
7852
- }
7853
- if (bodyB.isSleeping && bodyB.collisionType !== CollisionType.Fixed && bodyA.sleepMotion >= bodyB.wakeThreshold) {
7854
- bodyB.isSleeping = false;
7855
- }
7856
- }
7857
- }
7858
- }
7859
7852
  isCanceled() {
7860
7853
  return this._canceled;
7861
7854
  }
@@ -12083,7 +12076,7 @@ Read more here: https://developer.mozilla.org/en-US/docs/Web/API/WebGL_API/WebGL
12083
12076
  const optionalBody = ancestor == null ? void 0 : ancestor.get(BodyComponent);
12084
12077
  if (transform) {
12085
12078
  let tx = transform.get();
12086
- if (optionalBody) {
12079
+ if (optionalBody && !optionalBody.isSleeping) {
12087
12080
  if (this._engine.fixedUpdateTimestep && optionalBody.__oldTransformCaptured && optionalBody.enableFixedUpdateInterpolate) {
12088
12081
  const blend = this._engine.currentFrameLagMs / this._engine.fixedUpdateTimestep;
12089
12082
  tx = blendTransform(optionalBody.oldTransform, transform.get(), blend, this._targetInterpolationTransform);
@@ -20750,11 +20743,14 @@ If you want to do custom drawing, use Actor.graphics, or any onPreDraw or onPost
20750
20743
  this.dependencies = [TransformComponent, MotionComponent];
20751
20744
  this.id = createId("body", _BodyComponent2._ID++);
20752
20745
  this.events = new EventEmitter();
20746
+ this.island = null;
20753
20747
  this.oldTransform = new Transform();
20754
20748
  this.__oldTransformCaptured = false;
20755
20749
  this.enableFixedUpdateInterpolate = true;
20750
+ this.sleepTime = 0;
20756
20751
  this.collisionType = CollisionType.PreventCollision;
20757
20752
  this.group = CollisionGroup.All;
20753
+ this.canSleep = this.collisionType === CollisionType.Active;
20758
20754
  this._sleeping = false;
20759
20755
  this.bounciness = 0.2;
20760
20756
  this.friction = 0.99;
@@ -20797,6 +20793,12 @@ If you want to do custom drawing, use Actor.graphics, or any onPreDraw or onPost
20797
20793
  this.sleepMotion = this._bodyConfig.sleepEpsilon * 5;
20798
20794
  this.wakeThreshold = this._bodyConfig.wakeThreshold;
20799
20795
  }
20796
+ get canFallAsleep() {
20797
+ return this.canSleep && this.collisionType === CollisionType.Active && this.sleepMotion < this._bodyConfig.sleepEpsilon;
20798
+ }
20799
+ get canWakeUp() {
20800
+ return this.collisionType === CollisionType.Active && this.sleepMotion > this.wakeThreshold;
20801
+ }
20800
20802
  /**
20801
20803
  * Called by excalibur to update defaults
20802
20804
  * @param config
@@ -20829,7 +20831,7 @@ If you want to do custom drawing, use Actor.graphics, or any onPreDraw or onPost
20829
20831
  * Whether this body is sleeping or not
20830
20832
  */
20831
20833
  get isSleeping() {
20832
- return this._sleeping;
20834
+ return this.canSleep && this._sleeping;
20833
20835
  }
20834
20836
  /**
20835
20837
  * Set the sleep state of the body
@@ -20839,30 +20841,51 @@ If you want to do custom drawing, use Actor.graphics, or any onPreDraw or onPost
20839
20841
  setSleeping(sleeping) {
20840
20842
  this.isSleeping = sleeping;
20841
20843
  }
20842
- set isSleeping(sleeping) {
20843
- this._sleeping = sleeping;
20844
- if (!sleeping) {
20845
- this.sleepMotion = this._bodyConfig.sleepEpsilon * 5;
20846
- } else {
20844
+ wake() {
20845
+ var _a;
20846
+ if (this._sleeping && this.collisionType === CollisionType.Active) {
20847
+ this._sleeping = false;
20848
+ (_a = this.owner) == null ? void 0 : _a.removeTag("ex.is_sleeping");
20849
+ this.sleepMotion = this._bodyConfig.sleepEpsilon * 2;
20850
+ this.sleepTime = 0;
20851
+ }
20852
+ }
20853
+ sleep() {
20854
+ var _a;
20855
+ if (!this._sleeping && this.canSleep) {
20856
+ this._sleeping = true;
20857
+ (_a = this.owner) == null ? void 0 : _a.addTag("ex.is_sleeping");
20847
20858
  this.vel = Vector.Zero;
20848
20859
  this.acc = Vector.Zero;
20849
20860
  this.angularVelocity = 0;
20850
20861
  this.sleepMotion = 0;
20851
20862
  }
20852
20863
  }
20864
+ set isSleeping(sleeping) {
20865
+ if (sleeping) {
20866
+ this.sleep();
20867
+ } else {
20868
+ this.wake();
20869
+ }
20870
+ }
20853
20871
  /**
20854
20872
  * Update body's {@apilink BodyComponent.sleepMotion} for the purpose of sleeping
20855
20873
  */
20856
- updateMotion() {
20857
- if (this._sleeping) {
20858
- this.isSleeping = true;
20874
+ updateMotion(duration) {
20875
+ if (this.collisionType !== CollisionType.Active) {
20876
+ return;
20859
20877
  }
20860
- const currentMotion = this.vel.magnitude * this.vel.magnitude + Math.abs(this.angularVelocity * this.angularVelocity);
20861
- const bias = this._bodyConfig.sleepBias;
20862
- this.sleepMotion = bias * this.sleepMotion + (1 - bias) * currentMotion;
20878
+ const effectiveVel = this.pos.sub(this.oldPos);
20879
+ const effectiveAngularVel = angleDifference(canonicalizeAngle(this.rotation), canonicalizeAngle(this.oldRotation));
20880
+ const vel = effectiveVel.magnitude;
20881
+ const omega = effectiveAngularVel;
20882
+ const currentMotion = vel * vel + omega * omega;
20883
+ const bias = Math.pow(this._bodyConfig.sleepBias, duration / 1e3);
20884
+ const previousMotion = this.sleepMotion;
20885
+ this.sleepMotion = bias * previousMotion + (1 - bias) * currentMotion;
20863
20886
  this.sleepMotion = clamp(this.sleepMotion, 0, 10 * this._bodyConfig.sleepEpsilon);
20864
- if (this.canSleep && this.sleepMotion < this._bodyConfig.sleepEpsilon) {
20865
- this.isSleeping = true;
20887
+ if (this.canFallAsleep) {
20888
+ this.sleepTime += duration;
20866
20889
  }
20867
20890
  }
20868
20891
  /**
@@ -22091,7 +22114,6 @@ If you want to do custom drawing, use Actor.graphics, or any onPreDraw or onPost
22091
22114
  "beforecollisionresolve",
22092
22115
  new CollisionPreSolveEvent(contact.colliderB, contact.colliderA, exports2.Side.getOpposite(side), contact.mtv.negate(), contact)
22093
22116
  );
22094
- contact.matchAwake();
22095
22117
  }
22096
22118
  const finishedContactIds = Array.from(this.idToContactConstraint.keys());
22097
22119
  for (let i = 0; i < contacts.length; i++) {
@@ -22106,7 +22128,7 @@ If you want to do custom drawing, use Actor.graphics, or any onPreDraw or onPost
22106
22128
  const colliderA = contact.colliderA;
22107
22129
  const bodyB = contact.bodyB;
22108
22130
  const colliderB = contact.colliderB;
22109
- if (bodyA && bodyB) {
22131
+ if (bodyA && bodyB && (!bodyA.isSleeping || !bodyB.isSleeping)) {
22110
22132
  for (let j = 0; j < contact.points.length; j++) {
22111
22133
  const point2 = contact.points[j];
22112
22134
  const normal = contact.normal;
@@ -22165,8 +22187,6 @@ If you want to do custom drawing, use Actor.graphics, or any onPreDraw or onPost
22165
22187
  if (bodyA.collisionType === CollisionType.Passive || bodyB.collisionType === CollisionType.Passive) {
22166
22188
  continue;
22167
22189
  }
22168
- bodyA.updateMotion();
22169
- bodyB.updateMotion();
22170
22190
  }
22171
22191
  const side = exports2.Side.fromDirection(contact.mtv);
22172
22192
  contact.colliderA.events.emit(
@@ -22202,6 +22222,9 @@ If you want to do custom drawing, use Actor.graphics, or any onPreDraw or onPost
22202
22222
  const contact = contacts[i];
22203
22223
  const bodyA = contact.bodyA;
22204
22224
  const bodyB = contact.bodyB;
22225
+ if (bodyA.isSleeping && bodyB.isSleeping) {
22226
+ continue;
22227
+ }
22205
22228
  if (bodyA && bodyB) {
22206
22229
  const contactPoints = (_a = this.idToContactConstraint.get(contact.id)) != null ? _a : [];
22207
22230
  for (const point2 of contactPoints) {
@@ -22230,6 +22253,9 @@ If you want to do custom drawing, use Actor.graphics, or any onPreDraw or onPost
22230
22253
  const contact = contacts[i2];
22231
22254
  const bodyA = contact.bodyA;
22232
22255
  const bodyB = contact.bodyB;
22256
+ if (bodyA.isSleeping && bodyB.isSleeping) {
22257
+ continue;
22258
+ }
22233
22259
  if (bodyA && bodyB) {
22234
22260
  if (bodyA.collisionType === CollisionType.Passive || bodyB.collisionType === CollisionType.Passive) {
22235
22261
  continue;
@@ -22281,6 +22307,9 @@ If you want to do custom drawing, use Actor.graphics, or any onPreDraw or onPost
22281
22307
  const contact = contacts[i2];
22282
22308
  const bodyA = contact.bodyA;
22283
22309
  const bodyB = contact.bodyB;
22310
+ if (bodyA.isSleeping && bodyB.isSleeping) {
22311
+ continue;
22312
+ }
22284
22313
  if (bodyA && bodyB) {
22285
22314
  if (bodyA.collisionType === CollisionType.Passive || bodyB.collisionType === CollisionType.Passive) {
22286
22315
  continue;
@@ -22322,17 +22351,20 @@ If you want to do custom drawing, use Actor.graphics, or any onPreDraw or onPost
22322
22351
  this.physics = physics;
22323
22352
  this.systemType = SystemType.Update;
22324
22353
  this._physicsConfigDirty = false;
22325
- this.query = this.world.query({
22354
+ this.query = this._createPhysicsQuery(world, physics);
22355
+ physics.$configUpdate.subscribe(() => {
22356
+ this._physicsConfigDirty = true;
22357
+ });
22358
+ }
22359
+ _createPhysicsQuery(world, physics) {
22360
+ return world.query({
22326
22361
  components: {
22327
22362
  all: [TransformComponent, MotionComponent]
22328
22363
  },
22329
22364
  tags: {
22330
- not: this.physics.config.integration.onScreenOnly ? ["ex.offscreen"] : []
22365
+ not: physics.config.integration.onScreenOnly ? ["ex.offscreen", "ex.is_sleeping"] : ["ex.is_sleeping"]
22331
22366
  }
22332
22367
  });
22333
- physics.$configUpdate.subscribe(() => {
22334
- this._physicsConfigDirty = true;
22335
- });
22336
22368
  }
22337
22369
  update(elapsed) {
22338
22370
  let transform;
@@ -22364,14 +22396,7 @@ If you want to do custom drawing, use Actor.graphics, or any onPreDraw or onPost
22364
22396
  }
22365
22397
  if (this._physicsConfigDirty) {
22366
22398
  this._physicsConfigDirty = false;
22367
- this.query = this.world.query({
22368
- components: {
22369
- all: [TransformComponent, MotionComponent]
22370
- },
22371
- tags: {
22372
- not: this.physics.config.integration.onScreenOnly ? ["ex.offscreen"] : []
22373
- }
22374
- });
22399
+ this.query = this._createPhysicsQuery(this.world, this.physics);
22375
22400
  }
22376
22401
  }
22377
22402
  captureOldTransformWithChildren(entity) {
@@ -22383,6 +22408,105 @@ If you want to do custom drawing, use Actor.graphics, or any onPreDraw or onPost
22383
22408
  }
22384
22409
  }
22385
22410
  MotionSystem.priority = SystemPriority.Higher;
22411
+ class Island {
22412
+ constructor(config) {
22413
+ this.config = config;
22414
+ this.bodies = [];
22415
+ this.contacts = [];
22416
+ this.isSleeping = false;
22417
+ }
22418
+ wake() {
22419
+ this.isSleeping = false;
22420
+ for (const body of this.bodies) {
22421
+ body.wake();
22422
+ }
22423
+ }
22424
+ sleep() {
22425
+ this.isSleeping = true;
22426
+ for (const body of this.bodies) {
22427
+ body.sleep();
22428
+ }
22429
+ }
22430
+ updateSleepState(elapsed) {
22431
+ let islandHasMotion = false;
22432
+ let allBodiesCanSleep = true;
22433
+ for (const body of this.bodies) {
22434
+ body.updateMotion(elapsed);
22435
+ if (!body.canFallAsleep) {
22436
+ allBodiesCanSleep && (allBodiesCanSleep = false);
22437
+ }
22438
+ if (body.canWakeUp) {
22439
+ islandHasMotion || (islandHasMotion = true);
22440
+ }
22441
+ }
22442
+ if (islandHasMotion) {
22443
+ this.wake();
22444
+ } else if (allBodiesCanSleep) {
22445
+ let minSleepTime = Infinity;
22446
+ for (const body of this.bodies) {
22447
+ minSleepTime = Math.min(minSleepTime, body.sleepTime);
22448
+ }
22449
+ if (minSleepTime > this.config.sleepTimeThreshold) {
22450
+ this.sleep();
22451
+ }
22452
+ }
22453
+ }
22454
+ }
22455
+ function buildContactIslands(config, bodies, contacts) {
22456
+ const parent = /* @__PURE__ */ new Map();
22457
+ function find(body) {
22458
+ if (!parent.has(body)) {
22459
+ parent.set(body, body);
22460
+ }
22461
+ if (parent.get(body) !== body) {
22462
+ parent.set(body, find(parent.get(body)));
22463
+ }
22464
+ return parent.get(body);
22465
+ }
22466
+ function union(bodyA, bodyB) {
22467
+ const rootA = find(bodyA);
22468
+ const rootB = find(bodyB);
22469
+ if (rootA !== rootB) {
22470
+ parent.set(rootA, rootB);
22471
+ }
22472
+ }
22473
+ const bodyToContacts = /* @__PURE__ */ new Map();
22474
+ for (const contact of contacts) {
22475
+ if (contact.bodyA.collisionType === CollisionType.Active && contact.bodyB.collisionType === CollisionType.Active) {
22476
+ union(contact.bodyA, contact.bodyB);
22477
+ }
22478
+ if (!bodyToContacts.has(contact.bodyA)) {
22479
+ bodyToContacts.set(contact.bodyA, []);
22480
+ }
22481
+ if (!bodyToContacts.has(contact.bodyB)) {
22482
+ bodyToContacts.set(contact.bodyB, []);
22483
+ }
22484
+ if (contact.bodyA.collisionType === CollisionType.Active) {
22485
+ bodyToContacts.get(contact.bodyA).push(contact);
22486
+ }
22487
+ if (contact.bodyB.collisionType === CollisionType.Active) {
22488
+ bodyToContacts.get(contact.bodyB).push(contact);
22489
+ }
22490
+ }
22491
+ const islandMap = /* @__PURE__ */ new Map();
22492
+ for (const body of bodies) {
22493
+ if (body.collisionType !== CollisionType.Active) {
22494
+ continue;
22495
+ }
22496
+ const root = find(body);
22497
+ if (!islandMap.has(root)) {
22498
+ islandMap.set(root, []);
22499
+ }
22500
+ islandMap.get(root).push(body);
22501
+ }
22502
+ return Array.from(islandMap.values()).map((bodies2) => {
22503
+ const island = new Island(config);
22504
+ island.bodies = bodies2;
22505
+ bodies2.forEach((b) => b.island = island);
22506
+ island.contacts = Array.from(new Set(bodies2.flatMap((b) => bodyToContacts.get(b))));
22507
+ return island;
22508
+ });
22509
+ }
22386
22510
  class CollisionSystem extends System {
22387
22511
  constructor(world, _physics) {
22388
22512
  super();
@@ -22391,6 +22515,7 @@ If you want to do custom drawing, use Actor.graphics, or any onPreDraw or onPost
22391
22515
  this._configDirty = false;
22392
22516
  this._lastFrameContacts = /* @__PURE__ */ new Map();
22393
22517
  this._currentFrameContacts = /* @__PURE__ */ new Map();
22518
+ this._bodies = [];
22394
22519
  this._arcadeSolver = new ArcadeSolver(_physics.config.arcade);
22395
22520
  this._realisticSolver = new RealisticSolver(_physics.config.realistic);
22396
22521
  this._physics.$configUpdate.subscribe(() => this._configDirty = true);
@@ -22414,6 +22539,17 @@ If you want to do custom drawing, use Actor.graphics, or any onPreDraw or onPost
22414
22539
  }
22415
22540
  });
22416
22541
  this._motionSystem = world.get(MotionSystem);
22542
+ this.bodyQuery = world.query([BodyComponent]);
22543
+ this.bodyQuery.entityAdded$.subscribe((e) => {
22544
+ this._bodies.push(e.get(BodyComponent));
22545
+ });
22546
+ this.bodyQuery.entityRemoved$.subscribe((e) => {
22547
+ const body = e.get(BodyComponent);
22548
+ const indexOf = this._bodies.indexOf(body);
22549
+ if (indexOf > -1) {
22550
+ this._bodies.splice(indexOf, 1);
22551
+ }
22552
+ });
22417
22553
  }
22418
22554
  get _processor() {
22419
22555
  return this._physics.collisionProcessor;
@@ -22459,7 +22595,13 @@ If you want to do custom drawing, use Actor.graphics, or any onPreDraw or onPost
22459
22595
  }
22460
22596
  if (pairs.length) {
22461
22597
  contacts = this._processor.narrowphase(pairs, (_d = (_c = (_b = this._engine) == null ? void 0 : _b.debug) == null ? void 0 : _c.stats) == null ? void 0 : _d.currFrame);
22462
- contacts = solver.solve(contacts);
22598
+ if (this._physics.config.solver === SolverStrategy.Realistic) {
22599
+ const islands = buildContactIslands(this._physics.config.bodies, this._bodies, contacts);
22600
+ for (const island of islands) {
22601
+ island.updateSleepState(elapsed / substep);
22602
+ }
22603
+ }
22604
+ contacts = solver.solve(contacts, elapsed / substep);
22463
22605
  for (const contact of contacts) {
22464
22606
  if (contact.isCanceled()) {
22465
22607
  continue;
@@ -22515,6 +22657,8 @@ If you want to do custom drawing, use Actor.graphics, or any onPreDraw or onPost
22515
22657
  if (!this._currentFrameContacts.has(id)) {
22516
22658
  const colliderA = c.colliderA;
22517
22659
  const colliderB = c.colliderB;
22660
+ c.bodyA.isSleeping = false;
22661
+ c.bodyB.isSleeping = false;
22518
22662
  const side = exports2.Side.fromDirection(c.mtv);
22519
22663
  const opposite = exports2.Side.getOpposite(side);
22520
22664
  colliderA.events.emit("collisionend", new CollisionEndEvent(colliderA, colliderB, side, c));
@@ -27154,7 +27298,7 @@ If you want to do custom drawing, use Actor.graphics, or any onPreDraw or onPost
27154
27298
  cursor = cursor.add(lineHeight);
27155
27299
  }
27156
27300
  if (bodySettings.showAll || bodySettings.showMotion) {
27157
- this._graphicsContext.debug.drawText(`motion(${body.sleepMotion})`, cursor);
27301
+ this._graphicsContext.debug.drawText(`motion(${body.sleepMotion.toFixed(3)})`, cursor);
27158
27302
  cursor = cursor.add(lineHeight);
27159
27303
  }
27160
27304
  if (bodySettings.showAll || bodySettings.showSleeping) {
@@ -29461,6 +29605,7 @@ If you want to do custom drawing, use Actor.graphics, or any onPreDraw or onPost
29461
29605
  drawnImages: 0,
29462
29606
  rendererSwaps: 0
29463
29607
  };
29608
+ this.systemDuration = {};
29464
29609
  }
29465
29610
  /**
29466
29611
  * Zero out values or clone other IFrameStat stats. Allows instance reuse.
@@ -29476,6 +29621,9 @@ If you want to do custom drawing, use Actor.graphics, or any onPreDraw or onPost
29476
29621
  this.actors.ui = otherStats.actors.ui;
29477
29622
  this.duration.update = otherStats.duration.update;
29478
29623
  this.duration.draw = otherStats.duration.draw;
29624
+ for (const key in otherStats.systemDuration) {
29625
+ this.systemDuration[key] = otherStats.systemDuration[key];
29626
+ }
29479
29627
  this._physicsStats.reset(otherStats.physics);
29480
29628
  this.graphics.drawCalls = otherStats.graphics.drawCalls;
29481
29629
  this.graphics.drawnImages = otherStats.graphics.drawnImages;
@@ -29486,6 +29634,9 @@ If you want to do custom drawing, use Actor.graphics, or any onPreDraw or onPost
29486
29634
  this.duration.update = this.duration.draw = 0;
29487
29635
  this._physicsStats.reset();
29488
29636
  this.graphics.drawnImages = this.graphics.drawCalls = this.graphics.rendererSwaps = 0;
29637
+ for (const key in this.systemDuration) {
29638
+ this.systemDuration[key] = 0;
29639
+ }
29489
29640
  }
29490
29641
  }
29491
29642
  /**
@@ -33631,7 +33782,7 @@ Read more about this issue at https://excaliburjs.com/docs/performance`
33631
33782
  this._count += count;
33632
33783
  }
33633
33784
  }
33634
- const EX_VERSION = "0.32.0-alpha.19+57bc004";
33785
+ const EX_VERSION = "0.32.0";
33635
33786
  polyfill();
33636
33787
  exports2.ActionCompleteEvent = ActionCompleteEvent;
33637
33788
  exports2.ActionContext = ActionContext;
@@ -33952,6 +34103,7 @@ Read more about this issue at https://excaliburjs.com/docs/performance`
33952
34103
  exports2.WheelDeltaMode = WheelDeltaMode;
33953
34104
  exports2.WheelEvent = WheelEvent;
33954
34105
  exports2.World = World;
34106
+ exports2.angleDifference = angleDifference;
33955
34107
  exports2.approximatelyEqual = approximatelyEqual;
33956
34108
  exports2.assert = assert;
33957
34109
  exports2.canonicalizeAngle = canonicalizeAngle;