@react-shimeji/core 0.3.0 → 0.3.2
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 +45 -11
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +45 -11
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
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 =
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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;
|
|
@@ -1633,6 +1637,7 @@ function environmentRectangle(bounds) {
|
|
|
1633
1637
|
};
|
|
1634
1638
|
}
|
|
1635
1639
|
var PLATFORM_NEARBY_DISTANCE = 400;
|
|
1640
|
+
var PLATFORM_EDGE_TOLERANCE = 2;
|
|
1636
1641
|
function distanceToRectangle(point, rectangle) {
|
|
1637
1642
|
const dx = Math.max(rectangle.x - point.x, 0, point.x - rectangle.x - rectangle.width);
|
|
1638
1643
|
const dy = Math.max(rectangle.y - point.y, 0, point.y - rectangle.y - rectangle.height);
|
|
@@ -1663,6 +1668,7 @@ var Mascot = class {
|
|
|
1663
1668
|
this.domHandle = dom.createMascot(spec, id, options.mascotClassName || void 0);
|
|
1664
1669
|
this.frameDuration = options.frameDuration;
|
|
1665
1670
|
this.random = options.random ?? Math.random;
|
|
1671
|
+
this.forceInitialFall = spawnOptions.behaviorName === void 0;
|
|
1666
1672
|
this.behavior = new BehaviorController(spec, options.random);
|
|
1667
1673
|
this.actions = new ActionExecutor(spec, this.state, options, {
|
|
1668
1674
|
spawn: (position, characterId) => this.callbacks.spawn(characterId ?? this.spec.id, position),
|
|
@@ -1692,6 +1698,7 @@ var Mascot = class {
|
|
|
1692
1698
|
accumulatedMs = 0;
|
|
1693
1699
|
frameDuration;
|
|
1694
1700
|
random;
|
|
1701
|
+
forceInitialFall;
|
|
1695
1702
|
/** Advances behavior, animation, physics, and rendering by one clock tick. */
|
|
1696
1703
|
tick(deltaMs, bounds, platforms = []) {
|
|
1697
1704
|
if (this.destroyed) return;
|
|
@@ -1731,7 +1738,7 @@ var Mascot = class {
|
|
|
1731
1738
|
for (let guard = 0; guard < 32 && !this.destroyed; guard += 1) {
|
|
1732
1739
|
const environment = this.createEnvironment(bounds, platforms);
|
|
1733
1740
|
if (!this.currentBehavior) {
|
|
1734
|
-
this.currentBehavior = initial ? this.behavior.selectInitial(environment, this.state.behaviorName) : this.selectNextBehavior(environment, bounds);
|
|
1741
|
+
this.currentBehavior = initial ? this.forceInitialFall ? this.findFallBehavior() ?? this.behavior.selectInitial(environment) : this.behavior.selectInitial(environment, this.state.behaviorName) : this.selectNextBehavior(environment, bounds);
|
|
1735
1742
|
initial = false;
|
|
1736
1743
|
if (!this.currentBehavior) this.currentBehavior = this.findFallBehavior();
|
|
1737
1744
|
if (!this.currentBehavior || !this.startBehavior(environment, bounds, platforms)) return;
|
|
@@ -1750,7 +1757,7 @@ var Mascot = class {
|
|
|
1750
1757
|
if (result === "lost-ground") {
|
|
1751
1758
|
this.state.dragging = false;
|
|
1752
1759
|
this.actions.cancel();
|
|
1753
|
-
this.currentBehavior = this.
|
|
1760
|
+
this.currentBehavior = this.selectEdgeBehavior(bounds, platforms);
|
|
1754
1761
|
if (this.currentBehavior) this.startBehavior(this.createEnvironment(bounds, platforms), bounds, platforms);
|
|
1755
1762
|
} else if (result === "complete") {
|
|
1756
1763
|
this.currentBehavior = this.selectNextBehavior(this.createEnvironment(bounds, platforms), bounds);
|
|
@@ -1776,14 +1783,37 @@ var Mascot = class {
|
|
|
1776
1783
|
findFallBehavior() {
|
|
1777
1784
|
return this.behavior.force("Fall") ?? this.behavior.force("\u843D\u4E0B\u3059\u308B");
|
|
1778
1785
|
}
|
|
1779
|
-
selectNextBehavior(environment, bounds) {
|
|
1786
|
+
selectNextBehavior(environment, bounds, relocateOnFallback = true) {
|
|
1780
1787
|
const selected = this.behavior.selectNext(environment);
|
|
1781
|
-
if (this.behavior.usedFallback()) {
|
|
1788
|
+
if (relocateOnFallback && this.behavior.usedFallback()) {
|
|
1782
1789
|
this.state.x = Math.trunc(bounds.x + this.random() * bounds.width);
|
|
1783
1790
|
this.state.y = bounds.y - 256;
|
|
1784
1791
|
}
|
|
1785
1792
|
return selected;
|
|
1786
1793
|
}
|
|
1794
|
+
selectEdgeBehavior(bounds, platforms) {
|
|
1795
|
+
const original = { x: this.state.x, y: this.state.y };
|
|
1796
|
+
const platform = platforms.find((candidate) => candidate.element === this.activePlatformElement);
|
|
1797
|
+
if (platform) {
|
|
1798
|
+
const left = platform.x;
|
|
1799
|
+
const right = platform.x + platform.width;
|
|
1800
|
+
const top = platform.y;
|
|
1801
|
+
const bottom = platform.y + platform.height;
|
|
1802
|
+
if (Math.abs(this.state.y - top) <= PLATFORM_EDGE_TOLERANCE || Math.abs(this.state.y - bottom) <= PLATFORM_EDGE_TOLERANCE) {
|
|
1803
|
+
if (this.state.x < left) this.state.x = left;
|
|
1804
|
+
else if (this.state.x > right) this.state.x = right;
|
|
1805
|
+
} else if (Math.abs(this.state.x - left) <= PLATFORM_EDGE_TOLERANCE || Math.abs(this.state.x - right) <= PLATFORM_EDGE_TOLERANCE) {
|
|
1806
|
+
if (this.state.y < top) this.state.y = top;
|
|
1807
|
+
else if (this.state.y > bottom) this.state.y = bottom;
|
|
1808
|
+
}
|
|
1809
|
+
}
|
|
1810
|
+
const selected = this.selectNextBehavior(this.createEnvironment(bounds, platforms), bounds, false);
|
|
1811
|
+
if (this.behavior.usedFallback() || selected?.name === "Fall" || selected?.name === "\u843D\u4E0B\u3059\u308B") {
|
|
1812
|
+
this.state.x = original.x;
|
|
1813
|
+
this.state.y = original.y;
|
|
1814
|
+
}
|
|
1815
|
+
return selected ?? this.findFallBehavior();
|
|
1816
|
+
}
|
|
1787
1817
|
createEnvironment(bounds, platforms = this.platforms) {
|
|
1788
1818
|
const workArea = environmentRectangle(bounds);
|
|
1789
1819
|
const inactive = environmentRectangle({ x: -100, y: -100, width: 0, height: 0 });
|
|
@@ -1814,7 +1844,7 @@ var Mascot = class {
|
|
|
1814
1844
|
}
|
|
1815
1845
|
const anchor = this.state;
|
|
1816
1846
|
const current = platforms.find((platform) => platform.element === this.activePlatformElement);
|
|
1817
|
-
if (current && (isOnTop(anchor, current,
|
|
1847
|
+
if (current && (isOnTop(anchor, current, PLATFORM_EDGE_TOLERANCE) || isOnBottom(anchor, current, PLATFORM_EDGE_TOLERANCE) || isOnLeft(anchor, current, PLATFORM_EDGE_TOLERANCE) || isOnRight(anchor, current, PLATFORM_EDGE_TOLERANCE))) return current;
|
|
1818
1848
|
if (this.state.vy >= 0) {
|
|
1819
1849
|
const landingPlatform = platforms.filter((platform) => anchor.x >= platform.x && anchor.x <= platform.x + platform.width && platform.y >= anchor.y - 1).sort((left, right) => left.y - right.y)[0];
|
|
1820
1850
|
if (landingPlatform) {
|
|
@@ -2067,9 +2097,13 @@ var ShimejiEngine = class {
|
|
|
2067
2097
|
if (!spec) throw new Error(`Character '${characterId}' is not registered`);
|
|
2068
2098
|
const { bounds, platforms } = this.readFrameGeometry();
|
|
2069
2099
|
const random = this.options.random ?? Math.random;
|
|
2100
|
+
const randomX = Math.trunc(bounds.x + random() * bounds.width);
|
|
2101
|
+
const spawnInset = Math.min(2, bounds.width / 2);
|
|
2070
2102
|
const spawnOptions = {
|
|
2071
2103
|
...position,
|
|
2072
|
-
|
|
2104
|
+
// Fall treats the wall in the facing direction as ground. Keep implicit
|
|
2105
|
+
// spawns clear of both side-wall tolerances so even random() === 0 falls.
|
|
2106
|
+
x: position.x ?? Math.min(Math.max(randomX, bounds.x + spawnInset), bounds.x + bounds.width - spawnInset),
|
|
2073
2107
|
y: position.y ?? bounds.y + 2
|
|
2074
2108
|
};
|
|
2075
2109
|
const id = `shimeji-${this.nextMascotId++}`;
|