The chip window was 60 x 44 with the curl tumbling about its centre. The curl reaches 24.2 units from that pivot once the stroke is counted, so a half height of 22 clipped the top and bottom off it on every turn. The box is now 52 x 58 with the pivot at (26, 33), measured off the actual Bezier curve rather than its control points. The shadow sits at 15.1 below the pivot, which is where the curl comes to rest, so the chip lands on its own shadow instead of floating above it. The endless rotation is gone. Each bat now adds one or two whole turns in the direction it was hit and coasts to a stop, so the resting silhouette is always the same one, the one the shadow was placed under. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
80 lines
2.7 KiB
QML
80 lines
2.7 KiB
QML
pragma ComponentBehavior: Bound
|
|
import QtQuick
|
|
import QtQuick.Shapes
|
|
|
|
// A curled steel chip, the kind that comes off a milling cutter.
|
|
//
|
|
// 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
|
|
|
|
// 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 / 52
|
|
|
|
implicitWidth: 52
|
|
implicitHeight: 58
|
|
|
|
Behavior on spin {
|
|
NumberAnimation { duration: 750; easing.type: Easing.OutCubic }
|
|
}
|
|
|
|
Item {
|
|
width: 52
|
|
height: 58
|
|
transformOrigin: Item.TopLeft
|
|
scale: chip.unit
|
|
|
|
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
|
|
}
|
|
|
|
Item {
|
|
id: curl
|
|
x: 26; y: 33
|
|
width: 0
|
|
height: 0
|
|
rotation: chip.spin
|
|
|
|
Shape {
|
|
x: -30; y: -22
|
|
width: 60; height: 44
|
|
preferredRendererType: Shape.CurveRenderer
|
|
|
|
ShapePath { // the curl
|
|
strokeColor: "#8d99ae"
|
|
strokeWidth: 5
|
|
capStyle: ShapePath.RoundCap
|
|
fillColor: "transparent"
|
|
startX: 12; startY: 32
|
|
PathCubic { control1X: 2; control1Y: 20; control2X: 14; control2Y: 6; x: 30; y: 10 }
|
|
PathCubic { control1X: 44; control1Y: 14; control2X: 48; control2Y: 30; x: 38; y: 34 }
|
|
PathCubic { control1X: 30; control1Y: 37; control2X: 26; control2Y: 28; x: 32; y: 24 }
|
|
}
|
|
ShapePath { // highlight along the outer edge
|
|
strokeColor: "#dfe6ee"
|
|
strokeWidth: 1.6
|
|
capStyle: ShapePath.RoundCap
|
|
fillColor: "transparent"
|
|
startX: 13; startY: 29
|
|
PathCubic { control1X: 5; control1Y: 19; control2X: 16; control2Y: 8; x: 30; y: 12 }
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|