quickshell: redraw Archie at 2px, fix his paws, add a throwable ball and a bed
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
parent
d53e491812
commit
36360544ee
1 changed files with 346 additions and 125 deletions
|
|
@ -1125,12 +1125,13 @@ in
|
||||||
import QtQuick
|
import QtQuick
|
||||||
|
|
||||||
// Archie — a black and tan dachshund with a red collar, living
|
// Archie — a black and tan dachshund with a red collar, living
|
||||||
// along the bottom of the screen. He trots up and down, stops to
|
// along the bottom of the screen. He trots about, wags, naps in
|
||||||
// wag, and every so often remembers his bowl and goes for a snack.
|
// his bed, visits his bowl, and fetches a ball you can pick up
|
||||||
|
// and fling with the mouse.
|
||||||
//
|
//
|
||||||
// The art is plain text, one character per pixel, so he can be
|
// The art is plain text, one character per pixel, so he can be
|
||||||
// redrawn by editing the picture instead of editing code. He walks
|
// redrawn by editing the picture instead of editing code. He walks
|
||||||
// on all fours and never limps; that was deliberate.
|
// evenly on all fours and never limps; that was deliberate.
|
||||||
Item {
|
Item {
|
||||||
id: archie
|
id: archie
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
|
|
@ -1138,190 +1139,369 @@ in
|
||||||
property bool primary: true
|
property bool primary: true
|
||||||
visible: primary
|
visible: primary
|
||||||
|
|
||||||
// 4px pixels, not the worm's 6: he reads better with more
|
// 2px pixels: plenty of resolution for a proper pointed
|
||||||
// pixels in him, and at 112x48 he takes up a lot less of the
|
// dachshund head, and he still lands smaller on screen than
|
||||||
// screen than the chunkier first pass did.
|
// the chunkier drawing did.
|
||||||
readonly property int cell: 4
|
readonly property int cell: 2
|
||||||
readonly property int cols: 28
|
readonly property int cols: 44
|
||||||
readonly property int rows: 12
|
readonly property int rows: 19
|
||||||
|
|
||||||
// Not themed — he looked how he looked.
|
// Not themed — he looked how he looked.
|
||||||
readonly property var pal: ({
|
readonly property var pal: ({
|
||||||
"K": "#2b2523", // black
|
"K": "#2b2523", // black
|
||||||
"T": "#a86a30", // tan
|
"T": "#a86a30", // tan
|
||||||
"R": "#b3322c", // collar, and his bowl
|
"R": "#b3322c", // collar, and his bowl
|
||||||
"N": "#14100f", // nose
|
"N": "#14100f", // nose and eye
|
||||||
"W": "#efe7dd", // catchlight
|
"B": "#96602f", // kibble
|
||||||
"B": "#96602f" // kibble
|
"G": "#5a667a", // bed
|
||||||
|
"D": "#3a4454", // bed cushion
|
||||||
|
"Y": "#c8d84a", // ball
|
||||||
|
"L": "#e4ee8c" // ball highlight
|
||||||
})
|
})
|
||||||
|
|
||||||
// Trotting: legs out at full stride, tail up.
|
// Trotting: front leg forward, hind leg back, tail up. Paws
|
||||||
|
// point the way he is going — drawn trailing behind the leg
|
||||||
|
// they read as feet on backwards, which is exactly how the
|
||||||
|
// first pass looked.
|
||||||
readonly property var walkA: [
|
readonly property var walkA: [
|
||||||
"....................KKKKK...",
|
"...............................KKKKKKKK.....",
|
||||||
"...................KKTKKKK..",
|
"KK............................KKKKKKKKKK....",
|
||||||
"KK.................KKNTTKKN.",
|
"KKKK..........................KKKKKKKKKKK...",
|
||||||
".KKKKKKKKKKKKKKKKKRKKTTTTTN.",
|
".KKKK.........................KKKKK.KKKKK...",
|
||||||
"..KKKKKKKKKKKKKKKKRKKTTTT...",
|
"..KKKKKKKKKKKKKKKKKKKKKKKKKKRRKKKK..TTKKKKK.",
|
||||||
"..KKKKKKKKKKKKKKKKRKKTT.....",
|
".KKKKKKKKKKKKKKKKKKKKKKKKKKKRRKKKKTTTTTTTTT.",
|
||||||
"...KKKKKKKKKKKKKKTTT........",
|
"..KKKKKKKKKKKKKKKKKKKKKKKKKKRRKKKKTTTTTTTT..",
|
||||||
"....TKKKKKKKKKKKTTT.........",
|
"..KKKKKKKKKKKKKKKKKKKKKKKKKKRRKKKKTTTTT.....",
|
||||||
"....TTKKKKKKKKKTTT..........",
|
"...KKKKKKKKKKKKKKKKKKKKKKKKKTTKKKK..........",
|
||||||
"....TT..........TT..........",
|
"...KKKKKKKKKKKKKKKKKKKKKKKKKTTTKKK..........",
|
||||||
"....TT..........TT..........",
|
"...KKKKKKKKKKKKKKKKKKKKKKKKTTTT.............",
|
||||||
"...TTT.........TTT.........."
|
".....KKKKKKKKKKKKKKKKKKKKKTTTT..............",
|
||||||
|
"....TTKKKKKKKKKKKKKKKKKKKTTTT...............",
|
||||||
|
".....TTTTT..............TTTT................",
|
||||||
|
"......TTTT..............TTT.................",
|
||||||
|
".....TTT................TTT.................",
|
||||||
|
".....TTT................TTT.................",
|
||||||
|
".....TTT................TTT.................",
|
||||||
|
".....TTTTT..............TTTTT..............."
|
||||||
]
|
]
|
||||||
// Legs gathered underneath, tail level.
|
// Legs gathered under him, tail level.
|
||||||
readonly property var walkB: [
|
readonly property var walkB: [
|
||||||
"....................KKKKK...",
|
"...............................KKKKKKKK.....",
|
||||||
"...................KKTKKKK..",
|
"..............................KKKKKKKKKK....",
|
||||||
"...................KKNTTKKN.",
|
"KKKK..........................KKKKKKKKKKK...",
|
||||||
"KKKKKKKKKKKKKKKKKKRKKTTTTTN.",
|
"KKKK..........................KKKKK.KKKKK...",
|
||||||
"..KKKKKKKKKKKKKKKKRKKTTTT...",
|
"..KKKKKKKKKKKKKKKKKKKKKKKKKKRRKKKK..TTKKKKK.",
|
||||||
"..KKKKKKKKKKKKKKKKRKKTT.....",
|
".KKKKKKKKKKKKKKKKKKKKKKKKKKKRRKKKKTTTTTTTTT.",
|
||||||
"...KKKKKKKKKKKKKKTTT........",
|
"..KKKKKKKKKKKKKKKKKKKKKKKKKKRRKKKKTTTTTTTT..",
|
||||||
"....TKKKKKKKKKKKTTT.........",
|
"..KKKKKKKKKKKKKKKKKKKKKKKKKKRRKKKKTTTTT.....",
|
||||||
"....TTKKKKKKKKKTTT..........",
|
"...KKKKKKKKKKKKKKKKKKKKKKKKKTTKKKK..........",
|
||||||
"......TT......TT............",
|
"...KKKKKKKKKKKKKKKKKKKKKKKKKTTTKKK..........",
|
||||||
"......TT......TT............",
|
"...KKKKKKKKKKKKKKKKKKKKKKKKTTTT.............",
|
||||||
".....TTT.....TTT............"
|
".....KKKKKKKKKKKKKKKKKKKKKTTTT..............",
|
||||||
|
"....TTKKKKKKKKKKKKKKKKKKKTTTT...............",
|
||||||
|
"........TTTTT........TTTT...................",
|
||||||
|
".........TTTT........TTT....................",
|
||||||
|
"........TTT..........TTT....................",
|
||||||
|
"........TTT..........TTT....................",
|
||||||
|
"........TTT..........TTT....................",
|
||||||
|
"........TTTTT........TTTTT.................."
|
||||||
]
|
]
|
||||||
// Standing still: walkA's planted legs, walkB's tail. Flipping
|
// Standing: walkA's planted legs, walkB's tail. Flipping
|
||||||
// between this and walkA is the wag.
|
// between this and walkA is the wag.
|
||||||
readonly property var wag: [
|
readonly property var wag: [
|
||||||
"....................KKKKK...",
|
"...............................KKKKKKKK.....",
|
||||||
"...................KKTKKKK..",
|
"..............................KKKKKKKKKK....",
|
||||||
"...................KKNTTKKN.",
|
"KKKK..........................KKKKKKKKKKK...",
|
||||||
"KKKKKKKKKKKKKKKKKKRKKTTTTTN.",
|
"KKKK..........................KKKKK.KKKKK...",
|
||||||
"..KKKKKKKKKKKKKKKKRKKTTTT...",
|
"..KKKKKKKKKKKKKKKKKKKKKKKKKKRRKKKK..TTKKKKK.",
|
||||||
"..KKKKKKKKKKKKKKKKRKKTT.....",
|
".KKKKKKKKKKKKKKKKKKKKKKKKKKKRRKKKKTTTTTTTTT.",
|
||||||
"...KKKKKKKKKKKKKKTTT........",
|
"..KKKKKKKKKKKKKKKKKKKKKKKKKKRRKKKKTTTTTTTT..",
|
||||||
"....TKKKKKKKKKKKTTT.........",
|
"..KKKKKKKKKKKKKKKKKKKKKKKKKKRRKKKKTTTTT.....",
|
||||||
"....TTKKKKKKKKKTTT..........",
|
"...KKKKKKKKKKKKKKKKKKKKKKKKKTTKKKK..........",
|
||||||
"....TT..........TT..........",
|
"...KKKKKKKKKKKKKKKKKKKKKKKKKTTTKKK..........",
|
||||||
"....TT..........TT..........",
|
"...KKKKKKKKKKKKKKKKKKKKKKKKTTTT.............",
|
||||||
"...TTT.........TTT.........."
|
".....KKKKKKKKKKKKKKKKKKKKKTTTT..............",
|
||||||
|
"....TTKKKKKKKKKKKKKKKKKKKTTTT...............",
|
||||||
|
".....TTTTT..............TTTT................",
|
||||||
|
"......TTTT..............TTT.................",
|
||||||
|
".....TTT................TTT.................",
|
||||||
|
".....TTT................TTT.................",
|
||||||
|
".....TTT................TTT.................",
|
||||||
|
".....TTTTT..............TTTTT..............."
|
||||||
]
|
]
|
||||||
// Head down in the bowl.
|
// Head down in the bowl.
|
||||||
readonly property var eat: [
|
readonly property var eat: [
|
||||||
"............................",
|
"............................................",
|
||||||
"............................",
|
"KK..........................................",
|
||||||
"KK..........................",
|
"KKKK........................................",
|
||||||
".KKKKKKKKKKKKKKKKKRKK.......",
|
".KKKK.......................................",
|
||||||
"..KKKKKKKKKKKKKKKKRKKK......",
|
"..KKKKKKKKKKKKKKKKKKKKKKKKKKKKKK............",
|
||||||
"..KKKKKKKKKKKKKKKKRKKKK.....",
|
".KKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKK...........",
|
||||||
"...KKKKKKKKKKKKKKTTKKKKK....",
|
"..KKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKK..........",
|
||||||
"....TKKKKKKKKKKKTTKKTKKK....",
|
"..KKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKK..........",
|
||||||
"....TTKKKKKKKKKTTTKKNTTKN...",
|
"...KKKKKKKKKKKKKKKKKKKKKKKKKTTKKKK..........",
|
||||||
"....TT..........TT.KKTTTTN..",
|
"...KKKKKKKKKKKKKKKKKKKKKKKKKTTTKKKK.........",
|
||||||
"....TT..........TT..KTTN....",
|
"...KKKKKKKKKKKKKKKKKKKKKKKKTTTTKKKKKKKK.....",
|
||||||
"...TTT.........TTT.........."
|
".....KKKKKKKKKKKKKKKKKKKKKTTTTKKKKKKKKKK....",
|
||||||
|
"....TTKKKKKKKKKKKKKKKKKKKTTTT.KKKKK.KKKK....",
|
||||||
|
".....TTTTT..............TTTT..KKKKK.TTTKK...",
|
||||||
|
"......TTTT..............TTT...KKKKTTTTTTTTT.",
|
||||||
|
".....TTT................TTT...KKKKKTTTTTTT..",
|
||||||
|
".....TTT................TTT....KKKKTTTT.....",
|
||||||
|
".....TTT................TTT.................",
|
||||||
|
".....TTTTT..............TTTTT..............."
|
||||||
|
]
|
||||||
|
// Flat out in his bed, muzzle on the cushion.
|
||||||
|
readonly property var sleepArt: [
|
||||||
|
"............................................",
|
||||||
|
"............................................",
|
||||||
|
"............................................",
|
||||||
|
"............................................",
|
||||||
|
"............................................",
|
||||||
|
"............................................",
|
||||||
|
"............................................",
|
||||||
|
"............................................",
|
||||||
|
"............................................",
|
||||||
|
"...............................KKKKKKKK.....",
|
||||||
|
"..............................KKKKKKKKKKK...",
|
||||||
|
"KKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKK.KKKKK...",
|
||||||
|
"..KKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKTTTTTKKK..",
|
||||||
|
"..KKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKTTTTTTTTT.",
|
||||||
|
"...KKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKTTTTTTT...",
|
||||||
|
"...KKKKKKKKKKKKKKKKKKKKKKKKKKTTTT...........",
|
||||||
|
"....KKKKKKKKKKKKKKKKKKKKKKKKTTTT............",
|
||||||
|
".....TTTTTTTTKKKKKKKKKKKKTTTT...............",
|
||||||
|
"......TTTTTT..........TTTTTT................"
|
||||||
]
|
]
|
||||||
readonly property var bowlArt: [
|
readonly property var bowlArt: [
|
||||||
"...BBB..",
|
".....BBBBBB.....",
|
||||||
"..BBBBB.",
|
"...BBBBBBBBBB...",
|
||||||
".RBBBBBR",
|
".BBBBBBBBBBBBBB.",
|
||||||
".RRRRRR.",
|
"RRRRRRRRRRRRRRRR",
|
||||||
"..RRRR.."
|
".RRRRRRRRRRRRRR.",
|
||||||
|
"..RRRRRRRRRRRR..",
|
||||||
|
"...RRRRRRRRRR...",
|
||||||
|
"....RRRRRRRR....",
|
||||||
|
".....RRRRRR....."
|
||||||
|
]
|
||||||
|
readonly property var bedArt: [
|
||||||
|
"GGGGGGG........................................GGGGGGG",
|
||||||
|
"GGGGGGGGG....................................GGGGGGGGG",
|
||||||
|
"GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG",
|
||||||
|
"DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD",
|
||||||
|
"DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD",
|
||||||
|
"GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG",
|
||||||
|
"..GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG.."
|
||||||
|
]
|
||||||
|
readonly property var ballArt: [
|
||||||
|
"..YYY..",
|
||||||
|
".YLYYY.",
|
||||||
|
"YLYYYYY",
|
||||||
|
"YYYYYYY",
|
||||||
|
"YYYYYYY",
|
||||||
|
".YYYYY.",
|
||||||
|
"..YYY.."
|
||||||
]
|
]
|
||||||
|
|
||||||
property var frame: walkA
|
property var frame: walkA
|
||||||
|
|
||||||
// ── Where he lives: the strip along the bottom, the same
|
// ── His patch of floor ──────────────────────────────────
|
||||||
// floor line the worm lands on.
|
|
||||||
readonly property real floorY: archie.height - Theme.frameWidth
|
readonly property real floorY: archie.height - Theme.frameWidth
|
||||||
readonly property real roamL: Theme.barWidth + 12
|
readonly property real roamL: Theme.barWidth + 12
|
||||||
readonly property real roamR: Math.max(roamL,
|
readonly property real roamR: Math.max(roamL,
|
||||||
archie.width - Theme.frameWidth - cols * cell - 12)
|
archie.width - Theme.frameWidth - cols * cell - 12)
|
||||||
// Bowl parked over toward the right, clear of the launcher.
|
readonly property real bowlX: Math.max(roamL, roamR - 120)
|
||||||
readonly property real bowlX: Math.max(roamL, roamR - 150)
|
readonly property real bedX: Math.max(roamL, Math.min(bowlX - 500, roamL + 300))
|
||||||
// Stand so his muzzle lands in it rather than his shoulder:
|
// Stand so his muzzle lands in the bowl, not his shoulder.
|
||||||
// head-down, his nose is about 22 cells along from his tail.
|
readonly property real bowlStandX: bowlX - 32 * cell
|
||||||
readonly property real bowlStandX: bowlX - 18 * cell
|
// Lying down, centred on the cushion.
|
||||||
|
readonly property real bedLieX: bedX + 5 * cell
|
||||||
|
|
||||||
property real px: roamL
|
property real px: 0
|
||||||
property int facing: 1 // 1 = right, -1 = left
|
property int facing: 1 // 1 = right, -1 = left
|
||||||
property string mode: "walk"
|
property string mode: "walk"
|
||||||
property real targetX: 0
|
property real targetX: 0
|
||||||
property bool toBowl: false
|
property string errand: "" // "" | "bowl" | "bed" | "ball"
|
||||||
property int hold: 0
|
property int hold: 0
|
||||||
property int tick: 0
|
// Legs swap on distance covered, not on a tick count, so the
|
||||||
|
// gait stays in step whether he is ambling or running for the
|
||||||
|
// ball. 3 cells is exactly how far the feet move in the art.
|
||||||
|
property real stride: 0
|
||||||
|
property bool stepped: false
|
||||||
|
|
||||||
|
// ── The ball ────────────────────────────────────────────
|
||||||
|
readonly property int ballSize: 7 * cell
|
||||||
|
property real ballX: 0
|
||||||
|
property real ballY: 0
|
||||||
|
property real ballVX: 0
|
||||||
|
property real ballVY: 0
|
||||||
|
property bool ballHeld: false // in your hand
|
||||||
|
property bool ballCarried: false // in his mouth
|
||||||
|
property bool ballThrown: false // he only fetches a fresh throw
|
||||||
|
property real lastBX: 0
|
||||||
|
property real lastBY: 0
|
||||||
|
property int carry: 0
|
||||||
|
|
||||||
|
// Where his mouth is, mirrored with him.
|
||||||
|
readonly property real mouthX: px + (facing > 0 ? 41 : 3) * cell
|
||||||
|
readonly property real mouthY: floorY - 13 * cell
|
||||||
|
|
||||||
|
// Exposed so Bar.qml can punch the ball out of the window's
|
||||||
|
// input mask — without it the whole surface is click-through
|
||||||
|
// here and you could never grab the thing.
|
||||||
|
readonly property real hitX: ballX - 6
|
||||||
|
readonly property real hitY: ballY - 6
|
||||||
|
readonly property real hitW: primary ? ballSize + 12 : 0
|
||||||
|
|
||||||
|
// At rest on the floor after a throw: that is his cue.
|
||||||
|
readonly property bool ballLoose: ballThrown && !ballHeld && !ballCarried
|
||||||
|
&& Math.abs(ballVX) < 0.3 && Math.abs(ballVY) < 0.3
|
||||||
|
&& ballY >= floorY - ballSize - 1
|
||||||
|
|
||||||
|
function ballTick() {
|
||||||
|
if (ballCarried) {
|
||||||
|
ballX = mouthX - ballSize / 2;
|
||||||
|
ballY = mouthY - ballSize / 2;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (ballHeld) {
|
||||||
|
// Velocity comes from how fast you are dragging it, so
|
||||||
|
// letting go mid-swing throws it.
|
||||||
|
ballVX = Math.max(-45, Math.min(45, ballX - lastBX));
|
||||||
|
ballVY = Math.max(-45, Math.min(45, ballY - lastBY));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
ballVY += 0.55;
|
||||||
|
ballX += ballVX;
|
||||||
|
ballY += ballVY;
|
||||||
|
let ground = floorY - ballSize;
|
||||||
|
if (ballY >= ground) {
|
||||||
|
ballY = ground;
|
||||||
|
if (Math.abs(ballVY) > 1.2) ballVY = -ballVY * 0.55;
|
||||||
|
else ballVY = 0;
|
||||||
|
ballVX *= 0.92; // rolling friction
|
||||||
|
if (Math.abs(ballVX) < 0.08) ballVX = 0;
|
||||||
|
}
|
||||||
|
if (ballY < 0) { ballY = 0; ballVY = Math.abs(ballVY) * 0.4; }
|
||||||
|
let bl = Theme.barWidth;
|
||||||
|
let br = archie.width - Theme.frameWidth - ballSize;
|
||||||
|
if (ballX < bl) { ballX = bl; ballVX = -ballVX * 0.6; }
|
||||||
|
if (ballX > br) { ballX = br; ballVX = -ballVX * 0.6; }
|
||||||
|
}
|
||||||
|
|
||||||
|
// ── What he does next ───────────────────────────────────
|
||||||
function wander() {
|
function wander() {
|
||||||
mode = "walk";
|
mode = "walk";
|
||||||
// Not if he is already standing at it — otherwise he can
|
errand = "";
|
||||||
// roll "go to the bowl" while stood in it and eat twice
|
|
||||||
// over without moving.
|
|
||||||
// Near enough to be worth it, but not already stood in it
|
|
||||||
// — otherwise he either marches half a minute across the
|
|
||||||
// screen for a snack, or rolls "go to the bowl" while his
|
|
||||||
// head is in it and eats twice over without moving.
|
|
||||||
let dBowl = Math.abs(px - bowlStandX);
|
let dBowl = Math.abs(px - bowlStandX);
|
||||||
toBowl = Math.random() < 0.3 && dBowl > 80 && dBowl < 900;
|
let dBed = Math.abs(px - bedLieX);
|
||||||
// A short trip from wherever he is, not a random point on
|
// Near enough to be worth it, and not already stood there
|
||||||
// the whole screen: picking uniformly meant single walks
|
// — otherwise he marches half a minute for a snack, or
|
||||||
// most of a minute long across a wide monitor, which reads
|
// rolls "go to the bowl" with his head already in it. No
|
||||||
// as a patrol. Short hops read as pottering about.
|
// errands while he has the ball; he is busy.
|
||||||
|
if (!ballCarried && Math.random() < 0.3 && dBowl > 80 && dBowl < 900) errand = "bowl";
|
||||||
|
else if (!ballCarried && Math.random() < 0.25 && dBed > 80 && dBed < 900) errand = "bed";
|
||||||
|
|
||||||
|
if (errand === "bowl") { targetX = bowlStandX; return; }
|
||||||
|
if (errand === "bed") { targetX = bedLieX; return; }
|
||||||
|
|
||||||
let dir = Math.random() < 0.5 ? -1 : 1;
|
let dir = Math.random() < 0.5 ? -1 : 1;
|
||||||
// Turn away from an end he is already near. Clamping the
|
// Turn away from an end he is already near; clamping the
|
||||||
// target instead just parks him against the wall, picking
|
// target instead just parks him against the wall.
|
||||||
// the same spot over and over.
|
|
||||||
if (dir < 0 && px - roamL < 220) dir = 1;
|
if (dir < 0 && px - roamL < 220) dir = 1;
|
||||||
if (dir > 0 && roamR - px < 220) dir = -1;
|
if (dir > 0 && roamR - px < 220) dir = -1;
|
||||||
targetX = toBowl ? bowlStandX
|
targetX = Math.max(roamL, Math.min(roamR,
|
||||||
: Math.max(roamL, Math.min(roamR,
|
|
||||||
px + dir * (150 + Math.random() * 550)));
|
px + dir * (150 + Math.random() * 550)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function chase() {
|
||||||
|
mode = "walk";
|
||||||
|
errand = "ball";
|
||||||
|
// Line his mouth up with it, approaching from whichever
|
||||||
|
// side he is already on.
|
||||||
|
let bc = ballX + ballSize / 2;
|
||||||
|
targetX = (px + cols * cell / 2 < bc) ? bc - 41 * cell : bc - 3 * cell;
|
||||||
|
targetX = Math.max(roamL - 60, Math.min(roamR + 60, targetX));
|
||||||
|
}
|
||||||
|
|
||||||
function arrive() {
|
function arrive() {
|
||||||
if (toBowl) {
|
if (errand === "ball") {
|
||||||
|
ballCarried = true;
|
||||||
|
ballThrown = false;
|
||||||
|
carry = 400 + Math.random() * 500; // 13-30s of pride
|
||||||
|
mode = "idle";
|
||||||
|
hold = 40;
|
||||||
|
} else if (errand === "bowl") {
|
||||||
mode = "eat";
|
mode = "eat";
|
||||||
hold = 100 + Math.random() * 80;
|
hold = 100 + Math.random() * 80;
|
||||||
facing = 1; // the bowl is off his nose
|
facing = 1;
|
||||||
|
} else if (errand === "bed") {
|
||||||
|
mode = "sleep";
|
||||||
|
hold = 600 + Math.random() * 900;
|
||||||
|
facing = 1;
|
||||||
} else {
|
} else {
|
||||||
mode = "idle";
|
mode = "idle";
|
||||||
hold = 45 + Math.random() * 130;
|
hold = 45 + Math.random() * 130;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Placed on the first real width, not on completion: anchors
|
// Placed on the first real width: anchors have not resolved at
|
||||||
// have not resolved yet at that point, so roamR collapses to
|
// Component.onCompleted, so roamR collapses to roamL and he
|
||||||
// roamL and he spawns pinned to the left edge.
|
// spawns pinned to the left edge.
|
||||||
property bool placed: false
|
property bool placed: false
|
||||||
onWidthChanged: {
|
onWidthChanged: {
|
||||||
if (placed || width <= 0) return;
|
if (placed || width <= 0) return;
|
||||||
placed = true;
|
placed = true;
|
||||||
px = roamL + Math.random() * (roamR - roamL);
|
px = roamL + Math.random() * (roamR - roamL);
|
||||||
|
ballX = Math.min(roamR, px + 300);
|
||||||
|
ballY = floorY - ballSize;
|
||||||
wander();
|
wander();
|
||||||
}
|
}
|
||||||
|
|
||||||
Timer {
|
Timer {
|
||||||
interval: 33; running: archie.primary; repeat: true
|
interval: 33; running: archie.primary; repeat: true
|
||||||
onTriggered: {
|
onTriggered: {
|
||||||
archie.tick++;
|
archie.ballTick();
|
||||||
|
archie.lastBX = archie.ballX;
|
||||||
|
archie.lastBY = archie.ballY;
|
||||||
|
|
||||||
|
// A thrown ball beats whatever else he was doing.
|
||||||
|
if (archie.ballLoose && archie.errand !== "ball") archie.chase();
|
||||||
|
|
||||||
|
if (archie.ballCarried && --archie.carry <= 0) {
|
||||||
|
archie.ballCarried = false;
|
||||||
|
archie.ballVX = 0;
|
||||||
|
archie.ballVY = 0;
|
||||||
|
}
|
||||||
|
|
||||||
if (archie.mode === "walk") {
|
if (archie.mode === "walk") {
|
||||||
// Arrival first: checking after the step makes him
|
// Arrival first: checking after the step makes him
|
||||||
// take a stride backwards when he is already there.
|
// stride backwards when he is already there.
|
||||||
if (Math.abs(archie.targetX - archie.px) < 2) {
|
if (Math.abs(archie.targetX - archie.px) < 2.5) {
|
||||||
archie.arrive();
|
archie.arrive();
|
||||||
} else {
|
} else {
|
||||||
let dir = archie.targetX > archie.px ? 1 : -1;
|
let dir = archie.targetX > archie.px ? 1 : -1;
|
||||||
|
let sp = archie.errand === "ball" ? 3.0 : 1.5;
|
||||||
archie.facing = dir;
|
archie.facing = dir;
|
||||||
archie.px += dir * 1.6;
|
archie.px += dir * sp;
|
||||||
// Swap legs every 5 ticks: at 1.6px a tick
|
archie.stride += sp;
|
||||||
// that is exactly the 8px his feet move in the
|
if (archie.stride >= 3 * archie.cell) {
|
||||||
// art (2 cells), so he does not moonwalk.
|
archie.stride = 0;
|
||||||
archie.frame = archie.tick % 10 < 5 ? archie.walkA : archie.walkB;
|
archie.stepped = !archie.stepped;
|
||||||
|
}
|
||||||
|
archie.frame = archie.stepped ? archie.walkB : archie.walkA;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
archie.frame = archie.mode === "eat" ? archie.eat
|
archie.frame = archie.mode === "eat" ? archie.eat
|
||||||
: (archie.tick % 26 < 13 ? archie.walkA : archie.wag);
|
: archie.mode === "sleep" ? archie.sleepArt
|
||||||
|
: (archie.hold % 26 < 13 ? archie.walkA : archie.wag);
|
||||||
if (--archie.hold <= 0) archie.wander();
|
if (--archie.hold <= 0) archie.wander();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// ── Sprite. One Rectangle per pixel, colour looked up per
|
// ── Sprite: one Rectangle per pixel, colour looked up per
|
||||||
// frame; switching frames just rebinds them.
|
// frame, so switching frames just rebinds them.
|
||||||
component Sprite: Item {
|
component Sprite: Item {
|
||||||
id: sp
|
id: sp
|
||||||
property var art: []
|
property var art: []
|
||||||
|
|
@ -1349,32 +1529,65 @@ in
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Bed first, so he lies in it rather than behind it.
|
||||||
|
Sprite {
|
||||||
|
art: archie.bedArt; w: 54; h: 7
|
||||||
|
x: Math.round(archie.bedX / archie.cell) * archie.cell
|
||||||
|
y: archie.floorY - height
|
||||||
|
}
|
||||||
|
|
||||||
Sprite {
|
Sprite {
|
||||||
art: archie.frame
|
art: archie.frame
|
||||||
w: archie.cols
|
w: archie.cols
|
||||||
h: archie.rows
|
h: archie.rows
|
||||||
// Snap to the pixel grid, same as the worm, or the art
|
// Snap x to the pixel grid or the art shimmers as he
|
||||||
// shimmers as he walks.
|
// walks. y is exact: he never moves vertically, and
|
||||||
|
// rounding sank his paws through the floor.
|
||||||
x: Math.round(archie.px / archie.cell) * archie.cell
|
x: Math.round(archie.px / archie.cell) * archie.cell
|
||||||
// Exact, not grid-snapped: he never moves vertically, so
|
|
||||||
// there is nothing to shimmer, and rounding sank his paws
|
|
||||||
// a couple of pixels through the floor.
|
|
||||||
y: archie.floorY - height
|
y: archie.floorY - height
|
||||||
// Mirror him when he heads back the other way.
|
// Mirror him when he heads back the other way.
|
||||||
transform: Scale { origin.x: archie.cols * archie.cell / 2; xScale: archie.facing }
|
transform: Scale { origin.x: archie.cols * archie.cell / 2; xScale: archie.facing }
|
||||||
}
|
}
|
||||||
|
|
||||||
// Drawn after him, so at the bowl his nose goes behind it.
|
// Bowl after him, so at dinner his nose goes behind it.
|
||||||
Sprite {
|
Sprite {
|
||||||
art: archie.bowlArt
|
art: archie.bowlArt; w: 16; h: 9
|
||||||
w: 8
|
|
||||||
h: 5
|
|
||||||
x: Math.round(archie.bowlX / archie.cell) * archie.cell
|
x: Math.round(archie.bowlX / archie.cell) * archie.cell
|
||||||
// Exact, not grid-snapped: he never moves vertically, so
|
|
||||||
// there is nothing to shimmer, and rounding sank his paws
|
|
||||||
// a couple of pixels through the floor.
|
|
||||||
y: archie.floorY - height
|
y: archie.floorY - height
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Sprite {
|
||||||
|
art: archie.ballArt; w: 7; h: 7
|
||||||
|
x: Math.round(archie.ballX / archie.cell) * archie.cell
|
||||||
|
y: Math.round(archie.ballY / archie.cell) * archie.cell
|
||||||
|
}
|
||||||
|
|
||||||
|
// Grab handle for the ball, a little larger than the ball so
|
||||||
|
// it is catchable while it rolls.
|
||||||
|
MouseArea {
|
||||||
|
x: archie.hitX; y: archie.hitY
|
||||||
|
width: archie.hitW; height: archie.hitW
|
||||||
|
cursorShape: Qt.PointingHandCursor
|
||||||
|
property real grabDX: 0
|
||||||
|
property real grabDY: 0
|
||||||
|
onPressed: (m) => {
|
||||||
|
let p = mapToItem(archie, m.x, m.y);
|
||||||
|
grabDX = p.x - archie.ballX;
|
||||||
|
grabDY = p.y - archie.ballY;
|
||||||
|
archie.ballCarried = false; // you may take it off him
|
||||||
|
archie.ballHeld = true;
|
||||||
|
}
|
||||||
|
onPositionChanged: (m) => {
|
||||||
|
if (!archie.ballHeld) return;
|
||||||
|
let p = mapToItem(archie, m.x, m.y);
|
||||||
|
archie.ballX = p.x - grabDX;
|
||||||
|
archie.ballY = p.y - grabDY;
|
||||||
|
}
|
||||||
|
onReleased: {
|
||||||
|
archie.ballHeld = false;
|
||||||
|
archie.ballThrown = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
'';
|
'';
|
||||||
};
|
};
|
||||||
|
|
@ -1694,6 +1907,14 @@ in
|
||||||
width: launcherPanel.visible ? launcherPanel.width : 0
|
width: launcherPanel.visible ? launcherPanel.width : 0
|
||||||
height: launcherPanel.visible ? launcherPanel.height : 0
|
height: launcherPanel.visible ? launcherPanel.height : 0
|
||||||
}
|
}
|
||||||
|
// Archie's ball. The rest of this surface is click-through,
|
||||||
|
// so without a hole here you could never pick it up.
|
||||||
|
Region {
|
||||||
|
x: archieDog.hitX
|
||||||
|
y: archieDog.hitY
|
||||||
|
width: archieDog.hitW
|
||||||
|
height: archieDog.hitW
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Item {
|
Item {
|
||||||
|
|
@ -7035,7 +7256,7 @@ in
|
||||||
}
|
}
|
||||||
|
|
||||||
// Archie. One dog, primary screen only.
|
// Archie. One dog, primary screen only.
|
||||||
Archie { primary: bar.screen === Quickshell.screens[0] }
|
Archie { id: archieDog; primary: bar.screen === Quickshell.screens[0] }
|
||||||
}
|
}
|
||||||
'';
|
'';
|
||||||
};
|
};
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue