Refactor ball body creation

This commit is contained in:
Daddy32
2025-12-29 21:11:26 +01:00
parent 9243ac2df5
commit 653710c8a8

View File

@@ -117,6 +117,154 @@
config.ballRadius = nextRadius; config.ballRadius = nextRadius;
}; };
const createSoftBlob = (x, y, color, commonOpts) => {
const cols = 3;
const rows = 2;
const radius = Math.max(10, config.ballRadius * 0.55);
const soft = Composites.softBody(
x - cols * radius * 1.2,
y - rows * radius * 1.2,
cols,
rows,
0,
0,
true,
radius,
commonOpts,
);
const blobId = `blob-${Date.now()}-${Math.random()
.toString(16)
.slice(2)}`;
soft.bodies.forEach((b) => {
b.plugin = {
color,
hasEntered: false,
entryCheckId: null,
blobId,
};
});
soft.constraints.forEach((c) => {
c.plugin = { blobId, blobConstraint: true };
c.render = c.render || {};
c.render.type = "line";
});
return { bodies: soft.bodies, constraints: soft.constraints, blobId };
};
const createJaggedBall = (x, y, color, commonOpts) => {
const points = [];
const segments = 6;
for (let i = 0; i < segments; i += 1) {
const angle = Math.min((i / segments) * Math.PI * 2, Math.PI * 2);
const variance = 0.6 + Math.random() * 0.5;
const r = config.ballRadius * variance;
points.push({
x: x + Math.cos(angle) * r,
y: y + Math.sin(angle) * r,
});
}
const body = Bodies.fromVertices(x, y, [points], commonOpts, true);
body.plugin = {
color,
hasEntered: false,
entryCheckId: null,
shape: "jagged",
};
return { bodies: [body], constraints: [], blobId: null };
};
const createGiftBall = (x, y, color, commonOpts, scene, debugSpawn) => {
const size = config.ballRadius * 2;
const ribbonSize = Math.max(4, config.ballRadius * 0.35);
const ribbonColor = scene?.config?.giftRibbonColor || "#f8fafc";
if (debugSpawn) {
console.log("Spawn gift", {
sceneId: scene?.id,
x,
y,
color,
size,
});
}
const base = Bodies.rectangle(x, y, size, size, {
...commonOpts,
chamfer: { radius: Math.max(2, config.ballRadius * 0.18) },
});
const ribbonRender = {
fillStyle: ribbonColor,
strokeStyle: "#0b1222",
lineWidth: 2,
};
const verticalRibbon = Bodies.rectangle(x, y, ribbonSize, size * 1.02, {
render: ribbonRender,
});
const horizontalRibbon = Bodies.rectangle(
x,
y,
size * 1.02,
ribbonSize,
{
render: ribbonRender,
},
);
const bow = Bodies.rectangle(
x,
y - size * 0.34,
ribbonSize * 1.4,
ribbonSize * 0.8,
{
render: ribbonRender,
},
);
const body = Body.create({
parts: [base, verticalRibbon, horizontalRibbon, bow],
});
Body.setPosition(body, { x, y });
body.restitution = commonOpts.restitution;
body.friction = commonOpts.friction;
body.frictionAir = commonOpts.frictionAir;
body.frictionStatic = commonOpts.frictionStatic;
body.density = commonOpts.density;
body.render = {
...body.render,
...commonOpts.render,
visible: true,
};
body.plugin = {
color,
hasEntered: false,
entryCheckId: null,
shape: "gift",
};
return { bodies: [body], constraints: [], blobId: null };
};
const createRectBall = (x, y, color, commonOpts) => {
const side = config.ballRadius * 2;
const body = Bodies.rectangle(x, y, side, side, {
...commonOpts,
chamfer: 0,
});
body.plugin = {
color,
hasEntered: false,
entryCheckId: null,
shape: "rect",
};
return { bodies: [body], constraints: [], blobId: null };
};
const createCircleBall = (x, y, color, commonOpts) => {
const body = Bodies.circle(x, y, config.ballRadius, commonOpts);
body.plugin = {
color,
hasEntered: false,
entryCheckId: null,
shape: "circle",
};
return { bodies: [body], constraints: [], blobId: null };
};
const createBallBodies = (x, y, color) => { const createBallBodies = (x, y, color) => {
const scene = getCurrentScene(); const scene = getCurrentScene();
const ballPhysics = scene?.config?.ballPhysics || {}; const ballPhysics = scene?.config?.ballPhysics || {};
@@ -134,146 +282,18 @@
}, },
}; };
if (scene?.config?.blobBalls === "soft") { if (scene?.config?.blobBalls === "soft") {
const cols = 3; return createSoftBlob(x, y, color, commonOpts);
const rows = 2;
const radius = Math.max(10, config.ballRadius * 0.55);
const soft = Composites.softBody(
x - cols * radius * 1.2,
y - rows * radius * 1.2,
cols,
rows,
0,
0,
true,
radius,
commonOpts,
);
const blobId = `blob-${Date.now()}-${Math.random()
.toString(16)
.slice(2)}`;
soft.bodies.forEach((b) => {
b.plugin = {
color,
hasEntered: false,
entryCheckId: null,
blobId,
};
});
soft.constraints.forEach((c) => {
c.plugin = { blobId, blobConstraint: true };
c.render = c.render || {};
c.render.type = "line";
});
return { bodies: soft.bodies, constraints: soft.constraints, blobId };
} }
if (scene?.config?.blobBalls === "jagged") { if (scene?.config?.blobBalls === "jagged") {
const points = []; return createJaggedBall(x, y, color, commonOpts);
const segments = 6;
for (let i = 0; i < segments; i += 1) {
const angle = Math.min((i / segments) * Math.PI * 2, Math.PI * 2);
const variance = 0.6 + Math.random() * 0.5;
const r = config.ballRadius * variance;
points.push({
x: x + Math.cos(angle) * r,
y: y + Math.sin(angle) * r,
});
}
const body = Bodies.fromVertices(x, y, [points], commonOpts, true);
body.plugin = {
color,
hasEntered: false,
entryCheckId: null,
shape: "jagged",
};
return { bodies: [body], constraints: [], blobId: null };
} }
if (scene?.config?.ballShape === "gift") { if (scene?.config?.ballShape === "gift") {
const size = config.ballRadius * 2; return createGiftBall(x, y, color, commonOpts, scene, debugSpawn);
const ribbonSize = Math.max(4, config.ballRadius * 0.35);
const ribbonColor = scene?.config?.giftRibbonColor || "#f8fafc";
if (debugSpawn) {
console.log("Spawn gift", {
sceneId: scene?.id,
x,
y,
color,
size,
});
}
const base = Bodies.rectangle(x, y, size, size, {
...commonOpts,
chamfer: { radius: Math.max(2, config.ballRadius * 0.18) },
});
const ribbonRender = {
fillStyle: ribbonColor,
strokeStyle: "#0b1222",
lineWidth: 2,
};
const verticalRibbon = Bodies.rectangle(x, y, ribbonSize, size * 1.02, {
render: ribbonRender,
});
const horizontalRibbon = Bodies.rectangle(
x,
y,
size * 1.02,
ribbonSize,
{
render: ribbonRender,
},
);
const bow = Bodies.rectangle(
x,
y - size * 0.34,
ribbonSize * 1.4,
ribbonSize * 0.8,
{
render: ribbonRender,
},
);
const body = Body.create({
parts: [base, verticalRibbon, horizontalRibbon, bow],
});
Body.setPosition(body, { x, y });
body.restitution = commonOpts.restitution;
body.friction = commonOpts.friction;
body.frictionAir = commonOpts.frictionAir;
body.frictionStatic = commonOpts.frictionStatic;
body.density = commonOpts.density;
body.render = {
...body.render,
...commonOpts.render,
visible: true,
};
body.plugin = {
color,
hasEntered: false,
entryCheckId: null,
shape: "gift",
};
return { bodies: [body], constraints: [], blobId: null };
} }
if (scene?.config?.ballShape === "rect") { if (scene?.config?.ballShape === "rect") {
const side = config.ballRadius * 2; return createRectBall(x, y, color, commonOpts);
const body = Bodies.rectangle(x, y, side, side, {
...commonOpts,
chamfer: 0,
});
body.plugin = {
color,
hasEntered: false,
entryCheckId: null,
shape: "rect",
};
return { bodies: [body], constraints: [], blobId: null };
} }
const body = Bodies.circle(x, y, config.ballRadius, commonOpts); return createCircleBall(x, y, color, commonOpts);
body.plugin = {
color,
hasEntered: false,
entryCheckId: null,
shape: "circle",
};
return { bodies: [body], constraints: [], blobId: null };
}; };
const spawnBall = () => { const spawnBall = () => {