refactor(gootower): draw strands as pinched goo shapes instead of lines
Replace simple line-based strand rendering with filled polygon shapes that are thick at the ends and pinched thin in the middle, with curved edges and perpendicular sag for a drooping arc effect. Strands now connect smoothly to balls with tangent-aligned edges.
This commit is contained in:
parent
b6e7d932cd
commit
59a5d0606e
|
|
@ -654,7 +654,8 @@ export default class GooTowerGame extends Phaser.Scene {
|
||||||
|
|
||||||
this.drawGears(g);
|
this.drawGears(g);
|
||||||
|
|
||||||
// Strands first, under the balls.
|
// Strands first, under the balls — drawn as pinched goo shapes (thick
|
||||||
|
// at the ends, thin in the middle with curved edges).
|
||||||
for (const s of st.strands) {
|
for (const s of st.strands) {
|
||||||
if (s.broken) continue;
|
if (s.broken) continue;
|
||||||
const a = st.balls[s.a];
|
const a = st.balls[s.a];
|
||||||
|
|
@ -662,9 +663,60 @@ export default class GooTowerGame extends Phaser.Scene {
|
||||||
if (!a || !b || a.dead || b.dead) continue;
|
if (!a || !b || a.dead || b.dead) continue;
|
||||||
const stress = strandStress(s);
|
const stress = strandStress(s);
|
||||||
const color = lerpColor(STRAND, STRAND_HOT, stress);
|
const color = lerpColor(STRAND, STRAND_HOT, stress);
|
||||||
const width = 7 - 3 * stress; // strands thin as they are pulled taut
|
|
||||||
g.lineStyle(width, color, 1);
|
const dx = b.x - a.x;
|
||||||
g.lineBetween(a.x, a.y, b.x, b.y);
|
const dy = b.y - a.y;
|
||||||
|
const len = Math.hypot(dx, dy);
|
||||||
|
if (len < 1) continue;
|
||||||
|
|
||||||
|
// Unit direction along the strand and perpendicular to it.
|
||||||
|
const ux = dx / len, uy = dy / len;
|
||||||
|
const nx = -uy, ny = ux;
|
||||||
|
|
||||||
|
const baseW = 7 - 3 * stress;
|
||||||
|
const endW = baseW;
|
||||||
|
const midW = Math.max(1, baseW * 0.2);
|
||||||
|
// Perpendicular sag of the centerline at the midpoint — gives the strand
|
||||||
|
// a gentle drooping arc.
|
||||||
|
const sagAmt = baseW * 0.5;
|
||||||
|
|
||||||
|
// Width profile: endW at both endpoints, pinched to midW at the center.
|
||||||
|
// Zero derivative at t=0 and t=1 so the strand meets each ball tangentially.
|
||||||
|
// w(t) = midW + (endW - midW) * (1 - 2·t·(1-t))
|
||||||
|
// Sag profile: zero at endpoints, sagAmt at center.
|
||||||
|
// s(t) = 4·sagAmt·t·(1-t)
|
||||||
|
// Both are quadratics with zero derivative at the endpoints, giving
|
||||||
|
// perfectly smooth (tangent-aligned) connections into the balls.
|
||||||
|
// The second derivative of the edge offset is negative everywhere,
|
||||||
|
// so the edges curve inward — a concave "pinched" look.
|
||||||
|
|
||||||
|
const samples = Math.max(8, Math.min(20, Math.round(len / 15)));
|
||||||
|
const verts = [];
|
||||||
|
|
||||||
|
for (let i = 0; i <= samples; i++) {
|
||||||
|
const t = i / samples;
|
||||||
|
const tp = t * (1 - t); // peaks at 0.25 when t = 0.5
|
||||||
|
const w = midW + (endW - midW) * (1 - 2 * tp);
|
||||||
|
const sg = 4 * sagAmt * tp;
|
||||||
|
// Center point (straight line + perpendicular sag)
|
||||||
|
const cx = a.x + t * dx + nx * sg;
|
||||||
|
const cy = a.y + t * dy + ny * sg;
|
||||||
|
// Upper edge
|
||||||
|
verts.push({ x: cx + nx * (w / 2), y: cy + ny * (w / 2) });
|
||||||
|
}
|
||||||
|
// Bottom edge, walking back from end → start.
|
||||||
|
for (let i = samples; i >= 0; i--) {
|
||||||
|
const t = i / samples;
|
||||||
|
const tp = t * (1 - t);
|
||||||
|
const w = midW + (endW - midW) * (1 - 2 * tp);
|
||||||
|
const sg = 4 * sagAmt * tp;
|
||||||
|
const cx = a.x + t * dx + nx * sg;
|
||||||
|
const cy = a.y + t * dy + ny * sg;
|
||||||
|
verts.push({ x: cx - nx * (w / 2), y: cy - ny * (w / 2) });
|
||||||
|
}
|
||||||
|
|
||||||
|
g.fillStyle(color, 1);
|
||||||
|
g.fillPoints(verts, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Balls.
|
// Balls.
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue