Add stack blocks scene with column spawning
This commit is contained in:
@@ -102,6 +102,7 @@
|
|||||||
<script src="./src/scenes/scene-lavalamp.js"></script>
|
<script src="./src/scenes/scene-lavalamp.js"></script>
|
||||||
<script src="./src/scenes/scene-relax.js"></script>
|
<script src="./src/scenes/scene-relax.js"></script>
|
||||||
<script src="./src/scenes/scene-swirl-arena.js"></script>
|
<script src="./src/scenes/scene-swirl-arena.js"></script>
|
||||||
|
<script src="./src/scenes/scene-stack-blocks.js"></script>
|
||||||
<script src="./src/scenes/index.js"></script>
|
<script src="./src/scenes/index.js"></script>
|
||||||
<script src="./src/ui.js"></script>
|
<script src="./src/ui.js"></script>
|
||||||
<script src="./src/main.js"></script>
|
<script src="./src/main.js"></script>
|
||||||
|
|||||||
75
src/main.js
75
src/main.js
@@ -52,6 +52,7 @@
|
|||||||
minChain: 3,
|
minChain: 3,
|
||||||
palette: ["#ff595e", "#ffca3a", "#8ac926", "#1982c4", "#6a4c93"],
|
palette: ["#ff595e", "#ffca3a", "#8ac926", "#1982c4", "#6a4c93"],
|
||||||
ballRadius: 18,
|
ballRadius: 18,
|
||||||
|
ballShape: "circle",
|
||||||
link: {
|
link: {
|
||||||
stiffness: 0.85,
|
stiffness: 0.85,
|
||||||
lengthScale: 1.05, // max stretch factor; slack below this
|
lengthScale: 1.05, // max stretch factor; slack below this
|
||||||
@@ -320,12 +321,18 @@
|
|||||||
(Math.random() - 0.5) * Math.max(spawnJitter, config.ballRadius),
|
(Math.random() - 0.5) * Math.max(spawnJitter, config.ballRadius),
|
||||||
}
|
}
|
||||||
: null;
|
: null;
|
||||||
const x =
|
const columnCount = currentScene?.config?.spawnColumns;
|
||||||
|
let x =
|
||||||
centerSpawn?.x ??
|
centerSpawn?.x ??
|
||||||
Math.max(
|
Math.max(
|
||||||
config.ballRadius + 10,
|
config.ballRadius + 10,
|
||||||
Math.min(width - config.ballRadius - 10, Math.random() * width),
|
Math.min(width - config.ballRadius - 10, Math.random() * width),
|
||||||
);
|
);
|
||||||
|
if (Number.isFinite(columnCount) && columnCount > 0) {
|
||||||
|
const columnWidth = width / columnCount;
|
||||||
|
const colIndex = Math.floor(Math.random() * columnCount);
|
||||||
|
x = columnWidth * (colIndex + 0.5);
|
||||||
|
}
|
||||||
const spawnFromBottom = currentScene?.config?.spawnFrom === "bottom";
|
const spawnFromBottom = currentScene?.config?.spawnFrom === "bottom";
|
||||||
const y =
|
const y =
|
||||||
centerSpawn?.y ??
|
centerSpawn?.y ??
|
||||||
@@ -342,21 +349,30 @@
|
|||||||
Math.floor(Math.random() * (batchMax - batchMin + 1)) + batchMin,
|
Math.floor(Math.random() * (batchMax - batchMin + 1)) + batchMin,
|
||||||
);
|
);
|
||||||
for (let i = 0; i < batchCount; i += 1) {
|
for (let i = 0; i < batchCount; i += 1) {
|
||||||
const blob = createBallBodies(
|
const targetX = Math.min(
|
||||||
Math.min(
|
|
||||||
Math.max(
|
Math.max(
|
||||||
config.ballRadius + 10,
|
config.ballRadius + 10,
|
||||||
x + (i - batchCount / 2) * config.ballRadius * 1.5,
|
x + (i - batchCount / 2) * config.ballRadius * 1.5,
|
||||||
),
|
),
|
||||||
width - config.ballRadius - 10,
|
width - config.ballRadius - 10,
|
||||||
),
|
);
|
||||||
|
const targetY =
|
||||||
y +
|
y +
|
||||||
i *
|
i *
|
||||||
(spawnFromBottom
|
(spawnFromBottom
|
||||||
? -config.ballRadius * 0.5
|
? -config.ballRadius * 0.5
|
||||||
: config.ballRadius * 0.5),
|
: config.ballRadius * 0.5);
|
||||||
color,
|
const halfSize = config.ballRadius * 1.05;
|
||||||
);
|
const region = {
|
||||||
|
min: { x: targetX - halfSize, y: targetY - halfSize },
|
||||||
|
max: { x: targetX + halfSize, y: targetY + halfSize },
|
||||||
|
};
|
||||||
|
const hits = Query.region(balls, region);
|
||||||
|
if (hits && hits.length > 0) {
|
||||||
|
triggerGameOver();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const blob = createBallBodies(targetX, targetY, color);
|
||||||
if (blob.constraints.length > 0 && blob.blobId) {
|
if (blob.constraints.length > 0 && blob.blobId) {
|
||||||
blobConstraints.set(blob.blobId, blob.constraints);
|
blobConstraints.set(blob.blobId, blob.constraints);
|
||||||
}
|
}
|
||||||
@@ -402,6 +418,39 @@
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const spawnInitialColumns = () => {
|
||||||
|
const rows = currentScene?.config?.initialRows;
|
||||||
|
const columns = currentScene?.config?.spawnColumns;
|
||||||
|
if (!Number.isFinite(rows) || rows <= 0) return false;
|
||||||
|
if (!Number.isFinite(columns) || columns <= 0) return false;
|
||||||
|
const columnWidth = width / columns;
|
||||||
|
const side = config.ballRadius * 2;
|
||||||
|
const rowGap = side * 1.05;
|
||||||
|
for (let r = 0; r < rows; r += 1) {
|
||||||
|
const y = config.ballRadius * 1.5 + r * rowGap;
|
||||||
|
for (let c = 0; c < columns; c += 1) {
|
||||||
|
const x = columnWidth * (c + 0.5);
|
||||||
|
const color =
|
||||||
|
config.palette[Math.floor(Math.random() * config.palette.length)];
|
||||||
|
const blob = createBallBodies(x, y, color);
|
||||||
|
blob.bodies.forEach((body) => {
|
||||||
|
body.plugin = body.plugin || {};
|
||||||
|
body.plugin.hasEntered = true;
|
||||||
|
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 += rows * columns;
|
||||||
|
return true;
|
||||||
|
};
|
||||||
|
|
||||||
const cleanupBall = (ball) => {
|
const cleanupBall = (ball) => {
|
||||||
if (ball.plugin && ball.plugin.entryCheckId) {
|
if (ball.plugin && ball.plugin.entryCheckId) {
|
||||||
clearTimeout(ball.plugin.entryCheckId);
|
clearTimeout(ball.plugin.entryCheckId);
|
||||||
@@ -517,7 +566,10 @@
|
|||||||
if (isGridScene()) {
|
if (isGridScene()) {
|
||||||
spawnGridBalls();
|
spawnGridBalls();
|
||||||
} else {
|
} else {
|
||||||
|
const spawnedGrid = spawnInitialColumns();
|
||||||
|
if (!spawnedGrid) {
|
||||||
spawnInitialBurst();
|
spawnInitialBurst();
|
||||||
|
}
|
||||||
startSpawner();
|
startSpawner();
|
||||||
}
|
}
|
||||||
showGoalIntro();
|
showGoalIntro();
|
||||||
@@ -1000,6 +1052,15 @@
|
|||||||
body.plugin = { color, hasEntered: false, entryCheckId: null };
|
body.plugin = { color, hasEntered: false, entryCheckId: null };
|
||||||
return { bodies: [body], constraints: [], blobId: null };
|
return { bodies: [body], constraints: [], blobId: null };
|
||||||
}
|
}
|
||||||
|
if (currentScene?.config?.ballShape === "rect") {
|
||||||
|
const side = config.ballRadius * 2;
|
||||||
|
const body = Bodies.rectangle(x, y, side, side, {
|
||||||
|
...commonOpts,
|
||||||
|
chamfer: 4,
|
||||||
|
});
|
||||||
|
body.plugin = { color, hasEntered: false, entryCheckId: null };
|
||||||
|
return { bodies: [body], constraints: [], blobId: null };
|
||||||
|
}
|
||||||
const body = Bodies.circle(x, y, config.ballRadius, commonOpts);
|
const body = Bodies.circle(x, y, config.ballRadius, commonOpts);
|
||||||
body.plugin = { color, hasEntered: false, entryCheckId: null };
|
body.plugin = { color, hasEntered: false, entryCheckId: null };
|
||||||
return { bodies: [body], constraints: [], blobId: null };
|
return { bodies: [body], constraints: [], blobId: null };
|
||||||
|
|||||||
@@ -8,6 +8,7 @@
|
|||||||
"scene-lava",
|
"scene-lava",
|
||||||
"swirl-arena",
|
"swirl-arena",
|
||||||
"relax",
|
"relax",
|
||||||
|
"stack-blocks",
|
||||||
];
|
];
|
||||||
const orderedScenes = desiredOrder
|
const orderedScenes = desiredOrder
|
||||||
.map((id) => scenes.find((s) => s.id === id))
|
.map((id) => scenes.find((s) => s.id === id))
|
||||||
|
|||||||
Reference in New Issue
Block a user