@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.cjs CHANGED
@@ -701,21 +701,25 @@ var BehaviorController = class {
701
701
  };
702
702
 
703
703
  // src/physics.ts
704
- var BORDER_TOLERANCE = 0.999999;
704
+ var BORDER_TOLERANCE = 1 - Number.EPSILON / 2;
705
+ function isWithinSpan(value, minimum, maximum, tolerance) {
706
+ const distance = value < minimum ? minimum - value : value > maximum ? value - maximum : 0;
707
+ return distance <= tolerance;
708
+ }
705
709
  function clamp(value, minimum, maximum) {
706
710
  return Math.min(Math.max(value, minimum), maximum);
707
711
  }
708
712
  function isOnTop(point, rectangle, tolerance = BORDER_TOLERANCE) {
709
- return point.x >= rectangle.x - tolerance && point.x <= rectangle.x + rectangle.width + tolerance && Math.abs(point.y - rectangle.y) <= tolerance;
713
+ return isWithinSpan(point.x, rectangle.x, rectangle.x + rectangle.width, tolerance) && Math.abs(point.y - rectangle.y) <= tolerance;
710
714
  }
711
715
  function isOnBottom(point, rectangle, tolerance = BORDER_TOLERANCE) {
712
- return point.x >= rectangle.x - tolerance && point.x <= rectangle.x + rectangle.width + tolerance && Math.abs(point.y - rectangle.y - rectangle.height) <= tolerance;
716
+ return isWithinSpan(point.x, rectangle.x, rectangle.x + rectangle.width, tolerance) && Math.abs(point.y - rectangle.y - rectangle.height) <= tolerance;
713
717
  }
714
718
  function isOnLeft(point, rectangle, tolerance = BORDER_TOLERANCE) {
715
- return point.y >= rectangle.y - tolerance && point.y <= rectangle.y + rectangle.height + tolerance && Math.abs(point.x - rectangle.x) <= tolerance;
719
+ return isWithinSpan(point.y, rectangle.y, rectangle.y + rectangle.height, tolerance) && Math.abs(point.x - rectangle.x) <= tolerance;
716
720
  }
717
721
  function isOnRight(point, rectangle, tolerance = BORDER_TOLERANCE) {
718
- return point.y >= rectangle.y - tolerance && point.y <= rectangle.y + rectangle.height + tolerance && Math.abs(point.x - rectangle.x - rectangle.width) <= tolerance;
722
+ return isWithinSpan(point.y, rectangle.y, rectangle.y + rectangle.height, tolerance) && Math.abs(point.x - rectangle.x - rectangle.width) <= tolerance;
719
723
  }
720
724
  function isOnBorder(state, bounds, border, platform) {
721
725
  if (!border) return true;
@@ -1663,6 +1667,7 @@ var Mascot = class {
1663
1667
  this.domHandle = dom.createMascot(spec, id, options.mascotClassName || void 0);
1664
1668
  this.frameDuration = options.frameDuration;
1665
1669
  this.random = options.random ?? Math.random;
1670
+ this.forceInitialFall = spawnOptions.behaviorName === void 0;
1666
1671
  this.behavior = new BehaviorController(spec, options.random);
1667
1672
  this.actions = new ActionExecutor(spec, this.state, options, {
1668
1673
  spawn: (position, characterId) => this.callbacks.spawn(characterId ?? this.spec.id, position),
@@ -1692,6 +1697,7 @@ var Mascot = class {
1692
1697
  accumulatedMs = 0;
1693
1698
  frameDuration;
1694
1699
  random;
1700
+ forceInitialFall;
1695
1701
  /** Advances behavior, animation, physics, and rendering by one clock tick. */
1696
1702
  tick(deltaMs, bounds, platforms = []) {
1697
1703
  if (this.destroyed) return;
@@ -1731,7 +1737,7 @@ var Mascot = class {
1731
1737
  for (let guard = 0; guard < 32 && !this.destroyed; guard += 1) {
1732
1738
  const environment = this.createEnvironment(bounds, platforms);
1733
1739
  if (!this.currentBehavior) {
1734
- this.currentBehavior = initial ? this.behavior.selectInitial(environment, this.state.behaviorName) : this.selectNextBehavior(environment, bounds);
1740
+ this.currentBehavior = initial ? this.forceInitialFall ? this.findFallBehavior() ?? this.behavior.selectInitial(environment) : this.behavior.selectInitial(environment, this.state.behaviorName) : this.selectNextBehavior(environment, bounds);
1735
1741
  initial = false;
1736
1742
  if (!this.currentBehavior) this.currentBehavior = this.findFallBehavior();
1737
1743
  if (!this.currentBehavior || !this.startBehavior(environment, bounds, platforms)) return;
@@ -2067,9 +2073,13 @@ var ShimejiEngine = class {
2067
2073
  if (!spec) throw new Error(`Character '${characterId}' is not registered`);
2068
2074
  const { bounds, platforms } = this.readFrameGeometry();
2069
2075
  const random = this.options.random ?? Math.random;
2076
+ const randomX = Math.trunc(bounds.x + random() * bounds.width);
2077
+ const spawnInset = Math.min(2, bounds.width / 2);
2070
2078
  const spawnOptions = {
2071
2079
  ...position,
2072
- x: position.x ?? Math.trunc(bounds.x + random() * bounds.width),
2080
+ // Fall treats the wall in the facing direction as ground. Keep implicit
2081
+ // spawns clear of both side-wall tolerances so even random() === 0 falls.
2082
+ x: position.x ?? Math.min(Math.max(randomX, bounds.x + spawnInset), bounds.x + bounds.width - spawnInset),
2073
2083
  y: position.y ?? bounds.y + 2
2074
2084
  };
2075
2085
  const id = `shimeji-${this.nextMascotId++}`;