Add Storm Grid Shift scene

This commit is contained in:
Daddy32
2025-12-14 22:13:25 +01:00
parent 95420f1acf
commit e197a02fd0
3 changed files with 121 additions and 0 deletions

View File

@@ -9,6 +9,7 @@
"swirl-arena",
"relax",
"stack-blocks",
"storm-grid",
];
const orderedScenes = desiredOrder
.map((id) => scenes.find((s) => s.id === id))

View File

@@ -0,0 +1,119 @@
(() => {
const { Bodies } = Matter;
const scenes = (window.PhysilinksSceneDefs =
window.PhysilinksSceneDefs || []);
const makeSquareBodies = (w, h, offset = 0, wallThickness = 24) => {
const squareSize = Math.min(w, h) * 0.82;
const left = (w - squareSize) / 2 + offset;
const top = (h - squareSize) / 2 + offset;
const render = {
fillStyle: "#0b1222",
strokeStyle: "#334155",
lineWidth: 2,
};
const floorHeight = Math.max(30, squareSize * 0.06);
return [
Bodies.rectangle(
left - wallThickness / 2,
h / 2,
wallThickness,
h + wallThickness * 2,
{ isStatic: true, render },
),
Bodies.rectangle(
left + squareSize + wallThickness / 2,
h / 2,
wallThickness,
h + wallThickness * 2,
{ isStatic: true, render },
),
Bodies.rectangle(
w / 2,
h + floorHeight / 2,
w + wallThickness * 2,
floorHeight,
{ isStatic: true, restitution: 0.1, render },
),
];
};
scenes.push({
id: "storm-grid",
name: "Storm Grid Shift",
config: {
gravity: 0.9,
spawnIntervalMs: 520,
autoSpawn: true,
minChain: 3,
palette: ["#38bdf8", "#f97316", "#facc15", "#22c55e"],
ballRadius: 18,
ballShape: "rect",
spawnColumns: 10,
sizeFromColumns: true,
initialRows: 3,
rowGapMultiplier: 1,
squarePlayArea: true,
requireClearSpawn: true,
spawnInset: 0,
spawnIntervals: [
{ seconds: 0, gravityX: 0, gravityY: 0.9, label: "Calm start" },
{ seconds: 20, gravityX: 0.2, gravityY: 0.88, label: "Gust: East pull" },
{ seconds: 40, gravityX: -0.25, gravityY: 0.85, label: "Gust: West pull" },
{ seconds: 60, gravityX: 0, gravityY: 0.7, label: "Updraft" },
],
winCondition: { type: "timer", durationSec: 90, onWin: { shoveBalls: true } },
link: {
stiffness: 0.82,
lengthScale: 1.05,
damping: 0.08,
lineWidth: 3,
rope: true,
renderType: "line",
maxLengthMultiplier: 3.3,
},
onBeforeUpdate: ({ engine, width, height }) => {
const state = engine.plugin.stormState || {};
const now = (engine.timing?.timestamp || 0) / 1000;
if (!state.startTime) {
state.startTime = now;
state.nextIdx = 0;
engine.plugin.stormState = state;
}
const elapsed = now - state.startTime;
const steps = engine.world.plugin?.stormSteps || [];
const upcoming = steps[state.nextIdx];
if (upcoming && elapsed >= upcoming.seconds) {
engine.gravity.x = upcoming.gravityX;
engine.gravity.y = upcoming.gravityY;
// Nudge play area offset to keep things lively.
const offset = ((state.nextIdx % 2 === 0 ? 1 : -1) * Math.min(width, height)) / 50;
engine.world.plugin.squareOffset = offset;
state.nextIdx += 1;
if (typeof window?.PhysilinksUI?.create === "function" && window.PhysilinksUI?.instance) {
window.PhysilinksUI.instance.showFloatingMessage(
{ text: upcoming.label || "Gust incoming" },
{ durationMs: 2200 },
);
}
}
},
spawnInsets: ({ width, height, world }) => {
const wallThickness = Math.max(20, Math.min(width, height) * 0.02);
const offset = world?.plugin?.squareOffset || 0;
const squareSize = Math.min(width, height) * 0.82;
const left = (width - squareSize) / 2 + offset;
return { left, right: width - (left + squareSize) };
},
},
createBodies: (w, h) => {
const offset = 0;
const walls = makeSquareBodies(w, h, offset, Math.max(20, Math.min(w, h) * 0.02));
walls.forEach((b) => {
b.plugin = b.plugin || {};
b.plugin.stormWall = true;
});
return walls;
},
});
})();