diff --git a/qml/CatDefs.qml b/qml/CatDefs.qml index 9e0ab97..5f49d17 100644 --- a/qml/CatDefs.qml +++ b/qml/CatDefs.qml @@ -7,6 +7,9 @@ QtObject { // holds the whiskers, the tail and the glyphs that float above the head. readonly property real aspect: 106 / 120 + // Chip.qml draws in a 52 x 58 box, large enough to hold the tumbling curl. + readonly property real chipAspect: 58 / 52 + readonly property var moodNames: ["walking", "running", "sitting", "grooming", "stretching", "sleeping", "loving", "alert", "chasing", "batting", "drinking"] diff --git a/qml/Chip.qml b/qml/Chip.qml index f02a001..bbb57e4 100644 --- a/qml/Chip.qml +++ b/qml/Chip.qml @@ -3,27 +3,41 @@ import QtQuick import QtQuick.Shapes // A curled steel chip, the kind that comes off a milling cutter. -// Design space is 60 x 44 units. +// +// The box is 52 x 58 and the curl tumbles about (26, 33). Sizing rules, all in +// design units, all measured off the actual Bezier curve rather than its +// control points: +// * farthest point of the curl from the pivot is 24.2 including the stroke, +// so the box has to give 24.2 in every direction or spinning clips it +// * at rest the curl reaches 15.1 below the pivot, which is where the shadow +// goes, so it comes to rest sitting on its own shadow +// * spins are whole turns, so the resting silhouette is always the same one Item { id: chip - property int kick: 0 + // Degrees, driven from outside. Each bat adds most of a turn and the + // Behavior lets it coast to a stop. + property real spin: 0 - readonly property real unit: width / 60 + readonly property real unit: width / 52 - implicitWidth: 60 - implicitHeight: 44 + implicitWidth: 52 + implicitHeight: 58 + + Behavior on spin { + NumberAnimation { duration: 750; easing.type: Easing.OutCubic } + } Item { - width: 60 - height: 44 + width: 52 + height: 58 transformOrigin: Item.TopLeft scale: chip.unit - Rectangle { // ground shadow - x: 14; y: 36 - width: 32; height: 6 - radius: 3 + Rectangle { // ground shadow, under where the curl comes to rest + x: 9; y: 48 + width: 26; height: 4 + radius: 2 color: "#000000" opacity: 0.18 antialiasing: true @@ -31,8 +45,10 @@ Item { Item { id: curl - x: 30; y: 22 - width: 0; height: 0 + x: 26; y: 33 + width: 0 + height: 0 + rotation: chip.spin Shape { x: -30; y: -22 @@ -58,13 +74,6 @@ Item { PathCubic { control1X: 5; control1Y: 19; control2X: 16; control2Y: 8; x: 30; y: 12 } } } - - RotationAnimation on rotation { - running: true - loops: Animation.Infinite - from: 0; to: 360 - duration: 2600 - } } } } diff --git a/qml/ChipWindow.qml b/qml/ChipWindow.qml index a7edb4c..eaad11f 100644 --- a/qml/ChipWindow.qml +++ b/qml/ChipWindow.qml @@ -10,10 +10,10 @@ Window { required property CatController cat required property AppSettings settings - readonly property int chipSize: Math.round(settings.catSize * 0.45) + readonly property int chipSize: Math.round(settings.catSize * 0.46) width: chipSize - height: Math.round(chipSize * 0.73) + height: Math.round(chipSize * CatDefs.chipAspect) x: cat.chipX - width / 2 y: Screen.desktopAvailableHeight - height - settings.bottomMargin color: "transparent" @@ -29,6 +29,6 @@ Window { Chip { anchors.fill: parent - kick: win.cat.chipKick + spin: win.cat.chipSpin } } diff --git a/qml/OverlayWindow.qml b/qml/OverlayWindow.qml index d05012b..570a170 100644 --- a/qml/OverlayWindow.qml +++ b/qml/OverlayWindow.qml @@ -59,10 +59,10 @@ Window { Chip { x: win.cat.chipX - width / 2 y: win.height - height - win.settings.bottomMargin - width: Math.round(win.settings.catSize * 0.45) - height: Math.round(width * 0.73) + width: Math.round(win.settings.catSize * 0.46) + height: Math.round(width * CatDefs.chipAspect) visible: win.cat.chipVisible - kick: win.cat.chipKick + spin: win.cat.chipSpin Behavior on x { NumberAnimation { duration: 320; easing.type: Easing.OutQuad } diff --git a/src/catcontroller.cpp b/src/catcontroller.cpp index 184b3ae..457e95e 100644 --- a/src/catcontroller.cpp +++ b/src/catcontroller.cpp @@ -179,6 +179,8 @@ void CatController::tossChip() setChipX(fromLeft ? margin : m_stageWidth - margin); m_batsLeft = rng->bounded(2, 5); + m_chipSpin = fromLeft ? 360.0 : -360.0; // it rolls in already turning + emit chipSpinChanged(); m_chipVisible = true; emit chipVisibleChanged(); @@ -223,9 +225,6 @@ void CatController::endCoffee() void CatController::batChip() { auto *rng = QRandomGenerator::global(); - ++m_chipKick; - emit chipKickChanged(); - const qreal distance = rng->bounded(140, 380); qreal next = m_chipX + (m_facingRight ? distance : -distance); const qreal edge = 40.0; @@ -235,6 +234,11 @@ void CatController::batChip() } setChipX(next); + // Whole turns in the direction it was hit, so it always lands on the same + // silhouette, right on top of its shadow. The QML side lets it coast. + m_chipSpin += (m_facingRight ? 1 : -1) * 360.0 * rng->bounded(1, 3); + emit chipSpinChanged(); + if (--m_batsLeft <= 0) { endChase(); holdMood(Mood::Sitting, 2500); // pleased with itself diff --git a/src/catcontroller.h b/src/catcontroller.h index 1bba9a2..058dfdc 100644 --- a/src/catcontroller.h +++ b/src/catcontroller.h @@ -29,7 +29,7 @@ class CatController : public QObject Q_PROPERTY(bool chipVisible READ chipVisible NOTIFY chipVisibleChanged) Q_PROPERTY(qreal chipX READ chipX NOTIFY chipXChanged) - Q_PROPERTY(int chipKick READ chipKick NOTIFY chipKickChanged) + Q_PROPERTY(qreal chipSpin READ chipSpin NOTIFY chipSpinChanged) Q_PROPERTY(bool cupVisible READ cupVisible NOTIFY cupVisibleChanged) Q_PROPERTY(qreal cupX READ cupX NOTIFY cupXChanged) @@ -68,7 +68,7 @@ public: bool chipVisible() const { return m_chipVisible; } qreal chipX() const { return m_chipX; } - int chipKick() const { return m_chipKick; } + qreal chipSpin() const { return m_chipSpin; } bool cupVisible() const { return m_cupVisible; } qreal cupX() const { return m_cupX; } @@ -90,7 +90,7 @@ signals: void lookChanged(); void chipVisibleChanged(); void chipXChanged(); - void chipKickChanged(); + void chipSpinChanged(); void cupVisibleChanged(); void cupXChanged(); @@ -130,7 +130,7 @@ private: bool m_chipVisible = false; qreal m_chipX = 0; - int m_chipKick = 0; + qreal m_chipSpin = 0; int m_batsLeft = 0; bool m_cupVisible = false;