@react-shimeji/core 0.3.3 → 0.3.4
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 +54 -4
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +54 -4
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -1647,6 +1647,9 @@ function environmentRectangle(bounds) {
|
|
|
1647
1647
|
}
|
|
1648
1648
|
var PLATFORM_NEARBY_DISTANCE = 400;
|
|
1649
1649
|
var PLATFORM_EDGE_TOLERANCE = 2;
|
|
1650
|
+
var MASCOT_HITBOX_MAX_WIDTH = 32;
|
|
1651
|
+
var MASCOT_HITBOX_MAX_HEIGHT = 64;
|
|
1652
|
+
var MASCOT_COLLISION_LOOKAHEAD = 4;
|
|
1650
1653
|
var IE_BEHAVIOR_NAME_PATTERN = /wall|climb|crawl|壁|登|よじ/i;
|
|
1651
1654
|
function isIEBehavior(behavior) {
|
|
1652
1655
|
return behavior.conditions.some((condition) => /activeIE/i.test(condition)) || behavior.name.includes("IE") || behavior.name.includes("\uFF29\uFF25") || IE_BEHAVIOR_NAME_PATTERN.test(behavior.name) || behavior.actionName !== void 0 && (behavior.actionName.includes("IE") || behavior.actionName.includes("\uFF29\uFF25") || IE_BEHAVIOR_NAME_PATTERN.test(behavior.actionName));
|
|
@@ -1713,7 +1716,7 @@ var Mascot = class {
|
|
|
1713
1716
|
random;
|
|
1714
1717
|
forceInitialFall;
|
|
1715
1718
|
/** Advances behavior, animation, physics, and rendering by one clock tick. */
|
|
1716
|
-
tick(deltaMs, bounds, platforms = []) {
|
|
1719
|
+
tick(deltaMs, bounds, platforms = [], siblings = []) {
|
|
1717
1720
|
if (this.destroyed) return;
|
|
1718
1721
|
this.platforms = platforms;
|
|
1719
1722
|
try {
|
|
@@ -1721,7 +1724,7 @@ var Mascot = class {
|
|
|
1721
1724
|
this.accumulatedMs += Math.max(0, deltaMs);
|
|
1722
1725
|
while (this.accumulatedMs >= this.frameDuration && !this.destroyed) {
|
|
1723
1726
|
this.accumulatedMs -= this.frameDuration;
|
|
1724
|
-
this.legacyTick(bounds, platforms);
|
|
1727
|
+
this.legacyTick(bounds, platforms, siblings);
|
|
1725
1728
|
}
|
|
1726
1729
|
} catch (error) {
|
|
1727
1730
|
this.callbacks.error(error instanceof Error ? error : new Error(String(error)));
|
|
@@ -1734,6 +1737,24 @@ var Mascot = class {
|
|
|
1734
1737
|
snapshot() {
|
|
1735
1738
|
return { ...this.state };
|
|
1736
1739
|
}
|
|
1740
|
+
/** Returns the mascot's compact, feet-aligned behavioral collision box. */
|
|
1741
|
+
collisionBox() {
|
|
1742
|
+
const sprite = this.spec.sprites[this.state.sprite];
|
|
1743
|
+
const spriteWidth = typeof sprite === "object" && sprite.width !== void 0 ? sprite.width : 128;
|
|
1744
|
+
const spriteHeight = typeof sprite === "object" && sprite.height !== void 0 ? sprite.height : 128;
|
|
1745
|
+
const width = Math.min(spriteWidth, MASCOT_HITBOX_MAX_WIDTH);
|
|
1746
|
+
const height = Math.min(spriteHeight, MASCOT_HITBOX_MAX_HEIGHT);
|
|
1747
|
+
const anchorX = this.state.lookRight ? spriteWidth - this.state.anchorX : this.state.anchorX;
|
|
1748
|
+
const visualLeft = this.state.x - anchorX;
|
|
1749
|
+
const visualTop = this.state.y - this.state.anchorY;
|
|
1750
|
+
return {
|
|
1751
|
+
id: this.id,
|
|
1752
|
+
x: visualLeft + (spriteWidth - width) / 2,
|
|
1753
|
+
y: visualTop + spriteHeight - height,
|
|
1754
|
+
width,
|
|
1755
|
+
height
|
|
1756
|
+
};
|
|
1757
|
+
}
|
|
1737
1758
|
/** Removes listeners, DOM nodes, and object URLs owned by this mascot. */
|
|
1738
1759
|
destroy() {
|
|
1739
1760
|
if (this.destroyed) return;
|
|
@@ -1762,11 +1783,13 @@ var Mascot = class {
|
|
|
1762
1783
|
if (!this.startBehavior(this.createEnvironment(bounds, platforms), bounds, platforms)) return;
|
|
1763
1784
|
}
|
|
1764
1785
|
}
|
|
1765
|
-
legacyTick(bounds, platforms) {
|
|
1786
|
+
legacyTick(bounds, platforms, siblings) {
|
|
1766
1787
|
this.ensureBehavior(bounds, platforms, false);
|
|
1767
1788
|
if (!this.currentBehavior) return;
|
|
1789
|
+
const previous = { x: this.state.x, y: this.state.y };
|
|
1768
1790
|
const result = this.actions.step(this.createEnvironment(bounds, platforms), bounds, platforms);
|
|
1769
1791
|
if (this.destroyed) return;
|
|
1792
|
+
this.avoidSiblingCollision(previous, bounds, platforms, siblings);
|
|
1770
1793
|
if (result === "lost-ground") {
|
|
1771
1794
|
this.state.dragging = false;
|
|
1772
1795
|
this.actions.cancel();
|
|
@@ -1784,6 +1807,31 @@ var Mascot = class {
|
|
|
1784
1807
|
if (this.currentBehavior) this.startBehavior(this.createEnvironment(bounds, platforms), bounds, platforms);
|
|
1785
1808
|
}
|
|
1786
1809
|
}
|
|
1810
|
+
avoidSiblingCollision(previous, bounds, platforms, siblings) {
|
|
1811
|
+
const dx = this.state.x - previous.x;
|
|
1812
|
+
if (this.state.dragging || dx === 0 || this.state.y !== previous.y) return;
|
|
1813
|
+
const onHorizontalSurface = isOnFloor(previous, bounds, platforms) || isOnTop(previous, bounds) || platforms.some((platform) => isOnBottom(previous, platform));
|
|
1814
|
+
if (!onHorizontalSurface) return;
|
|
1815
|
+
const currentBox = this.collisionBox();
|
|
1816
|
+
const offsetX = currentBox.x - this.state.x;
|
|
1817
|
+
const previousBox = { ...currentBox, x: previous.x + offsetX };
|
|
1818
|
+
const movingRight = dx > 0;
|
|
1819
|
+
const sweptLeft = Math.min(previousBox.x, currentBox.x) - (movingRight ? 0 : MASCOT_COLLISION_LOOKAHEAD);
|
|
1820
|
+
const sweptRight = Math.max(previousBox.x + previousBox.width, currentBox.x + currentBox.width) + (movingRight ? MASCOT_COLLISION_LOOKAHEAD : 0);
|
|
1821
|
+
const previousCenterX = previousBox.x + previousBox.width / 2;
|
|
1822
|
+
const collision = siblings.some((sibling) => {
|
|
1823
|
+
if (sibling.id === this.id) return false;
|
|
1824
|
+
const siblingCenterX = sibling.x + sibling.width / 2;
|
|
1825
|
+
const isAhead = movingRight ? siblingCenterX >= previousCenterX : siblingCenterX <= previousCenterX;
|
|
1826
|
+
const overlapsVertically = currentBox.y < sibling.y + sibling.height && sibling.y < currentBox.y + currentBox.height;
|
|
1827
|
+
const crossesHorizontally = sweptLeft <= sibling.x + sibling.width && sibling.x <= sweptRight;
|
|
1828
|
+
return isAhead && overlapsVertically && crossesHorizontally;
|
|
1829
|
+
});
|
|
1830
|
+
if (!collision) return;
|
|
1831
|
+
this.state.x = previous.x;
|
|
1832
|
+
this.state.vx = 0;
|
|
1833
|
+
this.state.lookRight = !this.state.lookRight;
|
|
1834
|
+
}
|
|
1787
1835
|
isOutsideVisibleBounds(bounds) {
|
|
1788
1836
|
const sprite = this.spec.sprites[this.state.sprite];
|
|
1789
1837
|
const width = typeof sprite === "object" && "width" in sprite && sprite.width !== void 0 ? sprite.width : 128;
|
|
@@ -2205,7 +2253,9 @@ var ShimejiEngine = class {
|
|
|
2205
2253
|
this.lastFrameTime = timestamp;
|
|
2206
2254
|
const delta = Math.max(0, Math.min(rawDelta, this.options.maxDeltaTime));
|
|
2207
2255
|
const { bounds, platforms } = this.readFrameGeometry();
|
|
2208
|
-
|
|
2256
|
+
const mascots = [...this.mascots.values()];
|
|
2257
|
+
const collisionBoxes = mascots.map((mascot) => mascot.collisionBox());
|
|
2258
|
+
for (const mascot of mascots) mascot.tick(delta, bounds, platforms, collisionBoxes);
|
|
2209
2259
|
this.emitState();
|
|
2210
2260
|
this.animationFrame = this.container.ownerDocument.defaultView?.requestAnimationFrame(this.onAnimationFrame);
|
|
2211
2261
|
};
|