quickshell: panels launch the worm instead of turning him around

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
rope 2026-08-04 11:27:04 +01:00
parent bdb3ab0c75
commit 9b43f5f669

View file

@ -935,16 +935,9 @@ in
property bool loose: false // shoved off, ballistic
property real vx: 0
property real vy: 0
property real spin: 0 // rad/tick while airborne
}
// Turn around: the two ends swap roles, so the face leads in
// the new direction instead of the worm moonwalking.
function reverse() {
let f = worm.frontD;
worm.frontD = worm.backD;
worm.backD = f;
worm.step = -worm.step;
}
// Every segment's position, rebuilt each tick. One array
// instead of per-segment bindings: the gait and the ballistic
@ -1005,11 +998,17 @@ in
}
}
if (worm.loose) {
// Flying, he keeps whatever shape he was
// caught in and simply travels a curled-up
// worm mid-air, not a swimming one.
let dx = hx - body[0].x, dy = hy - body[0].y;
body = body.map(p => Qt.point(p.x + dx, p.y + dy));
// Airborne he keeps the shape he was caught
// in and tumbles about his own head: map()
// reads the old array throughout, so body[0]
// stays the pivot and the head lands exactly
// on the new position.
let c = Math.cos(worm.spin), s = Math.sin(worm.spin);
let px = body[0].x, py = body[0].y;
body = body.map(p => {
let ox = p.x - px, oy = p.y - py;
return Qt.point(hx + ox * c - oy * s, hy + ox * s + oy * c);
});
} else {
body = railBody();
}
@ -1071,46 +1070,47 @@ in
// direction off of.
property var pushers: []
property var prevRects: []
readonly property real shoveSpeed: 18
readonly property real shoveSpeed: 26
// Ticks before a panel may launch him again. Without it he can
// land back inside the same rect with his head over the edge
// and get booted forever.
property int shoveCool: 0
function launch(p) {
worm.loose = true;
worm.vx = p.push.x * shoveSpeed;
worm.vy = p.push.y * shoveSpeed - 8; // -8: sent up, not slid along
worm.spin = (0.04 + Math.random() * 0.05) * (p.push.x >= 0 ? 1 : -1);
shoveCool = 45;
}
function inRect(p, r) {
return Math.abs(p.x - r.x) <= r.z + 6 && Math.abs(p.y - r.y) <= r.w + 6;
}
function checkShove() {
let head = body[0], tail = body[segments - 1];
if (shoveCool > 0) { shoveCool--; return; }
let tail = body[segments - 1];
for (let i = 0; i < pushers.length; i++) {
let r = pushers[i].rect, q = prevRects[i];
if (!r || r.z < 0.5) continue;
// Any part of him in the way is enough to be swept;
// only the head decides a turn-around.
// Any part of him in the way is enough to be caught.
let touched = false;
for (let s = 0; s < body.length && !touched; s++)
touched = inRect(body[s], r);
if (!touched) continue;
// Either it was not there a tick ago the pop-out,
// and the usual case given how fast the morph is or
// an edge has swept outward over him since. Both mean
// the panel arrived where he was standing.
let appeared = !q || q.z < 0.5;
let grew = !appeared && (
(r.x + r.z) - (q.x + q.z) > 1 || (q.x - q.z) - (r.x - r.z) > 1
|| (r.y + r.w) - (q.y + q.w) > 1 || (q.y - q.w) - (r.y - r.w) > 1);
if (appeared || grew) {
worm.loose = true;
worm.vx = pushers[i].push.x * shoveSpeed;
worm.vy = pushers[i].push.y * shoveSpeed - 3; // -3: a little air
return;
}
// Sitting still, it is simply solid: he walks into the
// panel and turns around rather than crawling through
// it, which is what made an open dropdown feel like it
// was not there at all. Only turn him when he is
// ENTERING head in, tail still out. Whole body
// inside (he landed there) means walking on is the way
// out, and reversing on that would just buzz him in
// place against both edges.
if (inRect(head, r) && !inRect(tail, r)) reverse();
// A panel popping out on top of him and him crawling
// into one already open both end the same way now:
// launched. Only the first is the moment you asked
// for, but a dropdown sits open for minutes while he
// crawls at well under a pixel a tick, so contact is
// the event you actually see and having that merely
// turn him round is what read as never being knocked.
//
// The exception is his whole body being inside, which
// means he landed in there: walking out is the way
// out, and kicking him again would only pin him.
if (!inRect(tail, r)) launch(pushers[i]);
return;
}
}