Add chaos surge mechanic to Stack Blocks Chaos
This commit is contained in:
@@ -25,6 +25,9 @@
|
||||
engine,
|
||||
width: state.width,
|
||||
height: state.height,
|
||||
state,
|
||||
spawnSystem,
|
||||
config,
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
69
src/spawn.js
69
src/spawn.js
@@ -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,
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user