quickshell: worm rides the frame rail, falling cards knock him off it
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
parent
535fe56b76
commit
3eb1d242fa
1 changed files with 93 additions and 13 deletions
|
|
@ -848,29 +848,106 @@ in
|
|||
readonly property int segments: 10
|
||||
readonly property int lag: 3 // ticks of trail per segment
|
||||
|
||||
// ── The rail ────────────────────────────────────────────
|
||||
// The worm rides the chrome cutout: the exact rounded rect
|
||||
// the frame shader carves out of the shell, so he crawls the
|
||||
// real screen edge, corners and all. Keep these in step with
|
||||
// the ShaderEffect's `cutout` in Bar.qml.
|
||||
readonly property real railL: Theme.barWidth
|
||||
readonly property real railT: Theme.frameWidth
|
||||
readonly property real railR: weird.width - Theme.frameWidth
|
||||
readonly property real railB: weird.height - Theme.frameWidth
|
||||
readonly property real rad: Math.min(Theme.radius, (railR - railL) / 2, (railB - railT) / 2)
|
||||
readonly property real runX: railR - railL - 2 * rad // straight top/bottom run
|
||||
readonly property real runY: railB - railT - 2 * rad // straight left/right run
|
||||
readonly property real arc: Math.PI * rad / 2
|
||||
readonly property real perim: 2 * (runX + runY) + 4 * arc
|
||||
|
||||
// Point at distance d clockwise along that outline, starting
|
||||
// where the top-left corner lets go of the top edge: run,
|
||||
// quarter arc, run, quarter arc, … Each leg hands its end
|
||||
// point to the next, so the path closes exactly.
|
||||
function railPoint(d) {
|
||||
d = ((d % perim) + perim) % perim;
|
||||
let r = rad;
|
||||
if (d < runX) return Qt.point(railL + r + d, railT);
|
||||
d -= runX;
|
||||
if (d < arc) { let a = -Math.PI / 2 + d / r; return Qt.point(railR - r + Math.cos(a) * r, railT + r + Math.sin(a) * r); }
|
||||
d -= arc;
|
||||
if (d < runY) return Qt.point(railR, railT + r + d);
|
||||
d -= runY;
|
||||
if (d < arc) { let a = d / r; return Qt.point(railR - r + Math.cos(a) * r, railB - r + Math.sin(a) * r); }
|
||||
d -= arc;
|
||||
if (d < runX) return Qt.point(railR - r - d, railB);
|
||||
d -= runX;
|
||||
if (d < arc) { let a = Math.PI / 2 + d / r; return Qt.point(railL + r + Math.cos(a) * r, railB - r + Math.sin(a) * r); }
|
||||
d -= arc;
|
||||
if (d < runY) return Qt.point(railL, railB - r - d);
|
||||
d -= runY;
|
||||
let a = Math.PI + d / r;
|
||||
return Qt.point(railL + r + Math.cos(a) * r, railT + r + Math.sin(a) * r);
|
||||
}
|
||||
|
||||
// Where a landing at x sits on the bottom run — he always
|
||||
// comes down onto the floor, so that is the only leg that
|
||||
// ever needs solving backwards.
|
||||
function railAtBottom(x) {
|
||||
return runX + arc + runY + arc
|
||||
+ Math.max(0, Math.min(runX, railR - rad - x));
|
||||
}
|
||||
|
||||
// ── Worm ────────────────────────────────────────────────
|
||||
QtObject {
|
||||
id: worm
|
||||
property real hx: weird.width / 2
|
||||
property real hy: weird.height / 2
|
||||
property real dir: Math.random() * 2 * Math.PI
|
||||
property real d: Math.random() * 4000 // distance along the rail
|
||||
property real hx: 0
|
||||
property real hy: 0
|
||||
property bool loose: false // knocked off, ballistic
|
||||
property real vx: 0
|
||||
property real vy: 0
|
||||
property var trail: []
|
||||
}
|
||||
|
||||
// A card in flight punts him off the rail. Head only — a
|
||||
// per-segment hit test buys nothing you can see.
|
||||
function checkHit() {
|
||||
for (let c of pile) {
|
||||
if (!c.inFlight) continue; // a landed card is scenery
|
||||
if (worm.hx < c.x - 6 || worm.hx > c.x + c.width + 6) continue;
|
||||
if (worm.hy < c.y - 6 || worm.hy > c.y + c.height + 6) continue;
|
||||
worm.loose = true;
|
||||
worm.vx = (worm.hx < c.x + c.width / 2 ? -1 : 1) * (2 + Math.random() * 2);
|
||||
worm.vy = -3; // popped up first, then gravity
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
Timer {
|
||||
interval: 33; running: true; repeat: true
|
||||
onTriggered: {
|
||||
worm.dir += (Math.random() - 0.5) * 0.45;
|
||||
let m = weird.cell * 3;
|
||||
let nx = worm.hx + Math.cos(worm.dir) * 2.4;
|
||||
let ny = worm.hy + Math.sin(worm.dir) * 2.4;
|
||||
// Reflect the heading at the edges. Clamping alone
|
||||
// leaves it grinding along the border forever.
|
||||
if (nx < m || nx > weird.width - m) { worm.dir = Math.PI - worm.dir; nx = worm.hx; }
|
||||
if (ny < m || ny > weird.height - m) { worm.dir = -worm.dir; ny = worm.hy; }
|
||||
worm.hx = nx; worm.hy = ny;
|
||||
if (worm.loose) {
|
||||
worm.vy += 0.6; // gravity, px/tick²
|
||||
worm.hx += worm.vx;
|
||||
worm.hy += worm.vy;
|
||||
// The rail doubles as the walls — he cannot leave
|
||||
// the screen he was knocked off.
|
||||
if (worm.hx < weird.railL) { worm.hx = weird.railL; worm.vx = -worm.vx * 0.5; }
|
||||
if (worm.hx > weird.railR) { worm.hx = weird.railR; worm.vx = -worm.vx * 0.5; }
|
||||
if (worm.hy >= weird.railB) {
|
||||
worm.hy = weird.railB;
|
||||
// Still moving: bounce. Spent: he is back on
|
||||
// the floor, which is just the bottom run.
|
||||
if (worm.vy > 3) { worm.vy = -worm.vy * 0.45; worm.vx *= 0.7; }
|
||||
else { worm.loose = false; worm.d = weird.railAtBottom(worm.hx); }
|
||||
}
|
||||
} else {
|
||||
worm.d += 2.6;
|
||||
let p = weird.railPoint(worm.d);
|
||||
worm.hx = p.x; worm.hy = p.y;
|
||||
weird.checkHit();
|
||||
}
|
||||
let t = worm.trail;
|
||||
t.unshift(Qt.point(nx, ny));
|
||||
t.unshift(Qt.point(worm.hx, worm.hy));
|
||||
if (t.length > weird.segments * weird.lag) t.pop();
|
||||
// slice(), not `t`: a var property assigned the array
|
||||
// it already holds emits no change signal, so the
|
||||
|
|
@ -943,6 +1020,9 @@ in
|
|||
textureSize: Qt.size(width / 3, height / 3)
|
||||
smooth: false
|
||||
transformOrigin: Item.Center
|
||||
// Only a card still in the air can knock the worm off
|
||||
// his rail; one sitting in the pile is scenery.
|
||||
readonly property bool inFlight: fall.running
|
||||
|
||||
function drop() {
|
||||
fallX.to = Math.max(Theme.barWidth, Math.min(weird.width - width, x + (Math.random() - 0.5) * 240));
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue