Add chaos surge mechanic to Stack Blocks Chaos

This commit is contained in:
Daddy32
2025-12-15 23:04:23 +01:00
parent 535018f11d
commit f12fb477cb
3 changed files with 144 additions and 6 deletions

View File

@@ -25,6 +25,9 @@
engine,
width: state.width,
height: state.height,
state,
spawnSystem,
config,
});
};

View File

@@ -1,5 +1,5 @@
(() => {
const { Bodies } = Matter;
const { Bodies, Body } = Matter;
const scenes = (window.PhysilinksSceneDefs =
window.PhysilinksSceneDefs || []);
@@ -7,14 +7,14 @@
id: "stack-blocks-chaos",
name: "Stack Blocks Chaos",
config: {
gravity: 1.85,
gravity: 2.85,
spawnIntervalMs: 750,
autoSpawn: true,
minChain: 3,
palette: ["#fb7185", "#8b5cf6", "#22d3ee", "#fbbf24", "#24fbbf"],
palette: ["#fb7185", "#8b5cf6", "#22d3ee"],
ballRadius: 18,
ballShape: "rect",
spawnColumns: 12,
spawnColumns: 10,
sizeFromColumns: true,
initialRows: 3,
requireClearSpawn: true,
@@ -25,8 +25,8 @@
return { left: 0, right: 0 };
},
winCondition: {
type: "clearCount",
target: 100,
type: "score",
target: 20000,
},
link: {
stiffness: 0.85,
@@ -37,6 +37,72 @@
renderType: "line",
maxLengthMultiplier: 2.5,
},
chaosSurge: {
intervalMs: 19000,
jitterMs: 2500,
pushRows: 1,
columnJitter: 10,
},
onBeforeUpdate: ({
engine,
width,
height,
state,
spawnSystem,
config,
}) => {
if (
!state ||
!spawnSystem ||
state.paused ||
state.gameOver ||
state.levelWon
) {
return;
}
const surgeCfg = config.chaosSurge || {};
const interval = surgeCfg.intervalMs ?? 9000;
const jitter = surgeCfg.jitterMs ?? 0;
const now = engine.timing?.timestamp ?? Date.now();
engine.plugin ??= {};
const chaosState = engine.plugin.stackBlocksChaos || {};
if (chaosState.sceneId !== "stack-blocks-chaos") {
chaosState.sceneId = "stack-blocks-chaos";
chaosState.nextSurgeMs = now + interval + Math.random() * jitter;
}
if (!chaosState.nextSurgeMs) {
chaosState.nextSurgeMs = now + interval + Math.random() * jitter;
}
if (now < chaosState.nextSurgeMs) {
engine.plugin.stackBlocksChaos = chaosState;
return;
}
chaosState.nextSurgeMs = now + interval + Math.random() * jitter;
engine.plugin.stackBlocksChaos = chaosState;
const rowGap = config.ballRadius * 2 * (config.rowGapMultiplier ?? 1);
const pushDistance = Math.min(
rowGap * (surgeCfg.pushRows ?? 1),
height * 0.35,
);
const dampen = 0.6;
state.balls.forEach((ball) => {
Body.translate(ball, { x: 0, y: -pushDistance });
Body.setVelocity(ball, {
x: ball.velocity.x * dampen,
y: Math.min(ball.velocity.y, 0),
});
});
const squareSize = Math.min(width, height);
const playTop = (height - squareSize) / 2;
const baseY = playTop + squareSize - config.ballRadius * 1.2;
spawnSystem.spawnRowAtY({
y: baseY,
jitter: surgeCfg.columnJitter ?? config.ballRadius * 0.4,
markEntered: true,
});
},
},
createBodies: (w, h) => {
const squareSize = Math.min(w, h);

View File

@@ -471,6 +471,74 @@
spawnCount = 0;
};
const spawnRowAtY = ({
y,
columns: columnsOverride,
jitter = 0,
markEntered = false,
} = {}) => {
const scene = getCurrentScene();
const sceneConfig = scene?.config || {};
const columns =
Number.isFinite(columnsOverride) && columnsOverride > 0
? columnsOverride
: sceneConfig.spawnColumns;
if (!Number.isFinite(columns) || columns <= 0) return 0;
const { width, height } = getDimensions();
const insets = getSpawnInsets();
const squareArea = getSquarePlayArea();
const usableWidth = Math.max(
0,
(squareArea ? squareArea.size : width) - insets.left - insets.right,
);
const columnWidth = usableWidth / columns;
const minX =
(squareArea ? squareArea.left : 0) +
insets.left +
config.ballRadius +
2;
const maxX =
(squareArea ? squareArea.left + squareArea.size : width) -
insets.right -
config.ballRadius -
2;
const baseY =
typeof y === "number"
? y
: (squareArea ? squareArea.top + squareArea.size : height) -
config.ballRadius * 1.1;
for (let c = 0; c < columns; c += 1) {
const jitterX = (Math.random() - 0.5) * jitter;
const x =
(squareArea ? squareArea.left : 0) +
insets.left +
columnWidth * (c + 0.5) +
jitterX;
const safeX = Math.max(minX, Math.min(maxX, x));
const color =
config.palette[Math.floor(Math.random() * config.palette.length)];
const blob = createBallBodies(safeX, baseY, color);
blob.bodies.forEach((body) => {
body.plugin = body.plugin || {};
body.plugin.hasEntered = !!markEntered;
if (body.plugin.entryCheckId) {
clearTimeout(body.plugin.entryCheckId);
body.plugin.entryCheckId = null;
}
balls.push(body);
World.add(world, body);
});
if (blob.constraints.length > 0) {
World.add(world, blob.constraints);
}
if (blob.constraints.length > 0 && blob.blobId) {
blobConstraints.set(blob.blobId, blob.constraints);
}
}
spawnCount += columns;
return columns;
};
return {
startSpawner,
stopSpawner,
@@ -482,6 +550,7 @@
cleanupBall,
removeBlob,
resetSpawnState,
spawnRowAtY,
};
};