Add chaos surge mechanic to Stack Blocks Chaos
This commit is contained in:
@@ -25,6 +25,9 @@
|
|||||||
engine,
|
engine,
|
||||||
width: state.width,
|
width: state.width,
|
||||||
height: state.height,
|
height: state.height,
|
||||||
|
state,
|
||||||
|
spawnSystem,
|
||||||
|
config,
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
(() => {
|
(() => {
|
||||||
const { Bodies } = Matter;
|
const { Bodies, Body } = Matter;
|
||||||
const scenes = (window.PhysilinksSceneDefs =
|
const scenes = (window.PhysilinksSceneDefs =
|
||||||
window.PhysilinksSceneDefs || []);
|
window.PhysilinksSceneDefs || []);
|
||||||
|
|
||||||
@@ -7,14 +7,14 @@
|
|||||||
id: "stack-blocks-chaos",
|
id: "stack-blocks-chaos",
|
||||||
name: "Stack Blocks Chaos",
|
name: "Stack Blocks Chaos",
|
||||||
config: {
|
config: {
|
||||||
gravity: 1.85,
|
gravity: 2.85,
|
||||||
spawnIntervalMs: 750,
|
spawnIntervalMs: 750,
|
||||||
autoSpawn: true,
|
autoSpawn: true,
|
||||||
minChain: 3,
|
minChain: 3,
|
||||||
palette: ["#fb7185", "#8b5cf6", "#22d3ee", "#fbbf24", "#24fbbf"],
|
palette: ["#fb7185", "#8b5cf6", "#22d3ee"],
|
||||||
ballRadius: 18,
|
ballRadius: 18,
|
||||||
ballShape: "rect",
|
ballShape: "rect",
|
||||||
spawnColumns: 12,
|
spawnColumns: 10,
|
||||||
sizeFromColumns: true,
|
sizeFromColumns: true,
|
||||||
initialRows: 3,
|
initialRows: 3,
|
||||||
requireClearSpawn: true,
|
requireClearSpawn: true,
|
||||||
@@ -25,8 +25,8 @@
|
|||||||
return { left: 0, right: 0 };
|
return { left: 0, right: 0 };
|
||||||
},
|
},
|
||||||
winCondition: {
|
winCondition: {
|
||||||
type: "clearCount",
|
type: "score",
|
||||||
target: 100,
|
target: 20000,
|
||||||
},
|
},
|
||||||
link: {
|
link: {
|
||||||
stiffness: 0.85,
|
stiffness: 0.85,
|
||||||
@@ -37,6 +37,72 @@
|
|||||||
renderType: "line",
|
renderType: "line",
|
||||||
maxLengthMultiplier: 2.5,
|
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) => {
|
createBodies: (w, h) => {
|
||||||
const squareSize = Math.min(w, h);
|
const squareSize = Math.min(w, h);
|
||||||
|
|||||||
69
src/spawn.js
69
src/spawn.js
@@ -471,6 +471,74 @@
|
|||||||
spawnCount = 0;
|
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 {
|
return {
|
||||||
startSpawner,
|
startSpawner,
|
||||||
stopSpawner,
|
stopSpawner,
|
||||||
@@ -482,6 +550,7 @@
|
|||||||
cleanupBall,
|
cleanupBall,
|
||||||
removeBlob,
|
removeBlob,
|
||||||
resetSpawnState,
|
resetSpawnState,
|
||||||
|
spawnRowAtY,
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user