@react-shimeji/core 0.3.0 → 0.3.1

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/dist/index.js CHANGED
@@ -654,21 +654,25 @@ var BehaviorController = class {
654
654
  };
655
655
 
656
656
  // src/physics.ts
657
- var BORDER_TOLERANCE = 0.999999;
657
+ var BORDER_TOLERANCE = 1 - Number.EPSILON / 2;
658
+ function isWithinSpan(value, minimum, maximum, tolerance) {
659
+ const distance = value < minimum ? minimum - value : value > maximum ? value - maximum : 0;
660
+ return distance <= tolerance;
661
+ }
658
662
  function clamp(value, minimum, maximum) {
659
663
  return Math.min(Math.max(value, minimum), maximum);
660
664
  }
661
665
  function isOnTop(point, rectangle, tolerance = BORDER_TOLERANCE) {
662
- return point.x >= rectangle.x - tolerance && point.x <= rectangle.x + rectangle.width + tolerance && Math.abs(point.y - rectangle.y) <= tolerance;
666
+ return isWithinSpan(point.x, rectangle.x, rectangle.x + rectangle.width, tolerance) && Math.abs(point.y - rectangle.y) <= tolerance;
663
667
  }
664
668
  function isOnBottom(point, rectangle, tolerance = BORDER_TOLERANCE) {
665
- return point.x >= rectangle.x - tolerance && point.x <= rectangle.x + rectangle.width + tolerance && Math.abs(point.y - rectangle.y - rectangle.height) <= tolerance;
669
+ return isWithinSpan(point.x, rectangle.x, rectangle.x + rectangle.width, tolerance) && Math.abs(point.y - rectangle.y - rectangle.height) <= tolerance;
666
670
  }
667
671
  function isOnLeft(point, rectangle, tolerance = BORDER_TOLERANCE) {
668
- return point.y >= rectangle.y - tolerance && point.y <= rectangle.y + rectangle.height + tolerance && Math.abs(point.x - rectangle.x) <= tolerance;
672
+ return isWithinSpan(point.y, rectangle.y, rectangle.y + rectangle.height, tolerance) && Math.abs(point.x - rectangle.x) <= tolerance;
669
673
  }
670
674
  function isOnRight(point, rectangle, tolerance = BORDER_TOLERANCE) {
671
- return point.y >= rectangle.y - tolerance && point.y <= rectangle.y + rectangle.height + tolerance && Math.abs(point.x - rectangle.x - rectangle.width) <= tolerance;
675
+ return isWithinSpan(point.y, rectangle.y, rectangle.y + rectangle.height, tolerance) && Math.abs(point.x - rectangle.x - rectangle.width) <= tolerance;
672
676
  }
673
677
  function isOnBorder(state, bounds, border, platform) {
674
678
  if (!border) return true;
@@ -1616,6 +1620,7 @@ var Mascot = class {
1616
1620
  this.domHandle = dom.createMascot(spec, id, options.mascotClassName || void 0);
1617
1621
  this.frameDuration = options.frameDuration;
1618
1622
  this.random = options.random ?? Math.random;
1623
+ this.forceInitialFall = spawnOptions.behaviorName === void 0;
1619
1624
  this.behavior = new BehaviorController(spec, options.random);
1620
1625
  this.actions = new ActionExecutor(spec, this.state, options, {
1621
1626
  spawn: (position, characterId) => this.callbacks.spawn(characterId ?? this.spec.id, position),
@@ -1645,6 +1650,7 @@ var Mascot = class {
1645
1650
  accumulatedMs = 0;
1646
1651
  frameDuration;
1647
1652
  random;
1653
+ forceInitialFall;
1648
1654
  /** Advances behavior, animation, physics, and rendering by one clock tick. */
1649
1655
  tick(deltaMs, bounds, platforms = []) {
1650
1656
  if (this.destroyed) return;
@@ -1684,7 +1690,7 @@ var Mascot = class {
1684
1690
  for (let guard = 0; guard < 32 && !this.destroyed; guard += 1) {
1685
1691
  const environment = this.createEnvironment(bounds, platforms);
1686
1692
  if (!this.currentBehavior) {
1687
- this.currentBehavior = initial ? this.behavior.selectInitial(environment, this.state.behaviorName) : this.selectNextBehavior(environment, bounds);
1693
+ this.currentBehavior = initial ? this.forceInitialFall ? this.findFallBehavior() ?? this.behavior.selectInitial(environment) : this.behavior.selectInitial(environment, this.state.behaviorName) : this.selectNextBehavior(environment, bounds);
1688
1694
  initial = false;
1689
1695
  if (!this.currentBehavior) this.currentBehavior = this.findFallBehavior();
1690
1696
  if (!this.currentBehavior || !this.startBehavior(environment, bounds, platforms)) return;
@@ -2020,9 +2026,13 @@ var ShimejiEngine = class {
2020
2026
  if (!spec) throw new Error(`Character '${characterId}' is not registered`);
2021
2027
  const { bounds, platforms } = this.readFrameGeometry();
2022
2028
  const random = this.options.random ?? Math.random;
2029
+ const randomX = Math.trunc(bounds.x + random() * bounds.width);
2030
+ const spawnInset = Math.min(2, bounds.width / 2);
2023
2031
  const spawnOptions = {
2024
2032
  ...position,
2025
- x: position.x ?? Math.trunc(bounds.x + random() * bounds.width),
2033
+ // Fall treats the wall in the facing direction as ground. Keep implicit
2034
+ // spawns clear of both side-wall tolerances so even random() === 0 falls.
2035
+ x: position.x ?? Math.min(Math.max(randomX, bounds.x + spawnInset), bounds.x + bounds.width - spawnInset),
2026
2036
  y: position.y ?? bounds.y + 2
2027
2037
  };
2028
2038
  const id = `shimeji-${this.nextMascotId++}`;