[SOLVED] Is this a reasonable way to do continuous sprite animation in QML?
-
I've been playing around with QML, trying to get beyond the basics (or my basics. . . ;-)
Looking into animations, I was wondering how to do a continuous "sprite" type animation. None of the built in types seems to do what I wanted so I made the one below using a Timer.(the classic "Bouncing ball" screensaver type thing).
Is this a valid approach? It works ok. I am wondering about the load/performance if there were many such "sprites", all with their own timers (and not doing a more sophisticated approach with one timer updating all the sprites).
Is there a better way to do this sort of continuous animation?
import QtQuick 2.5 Rectangle{ property int xspeed: 4 property int yspeed: 4 property int xpos: 100 property int ypos: 100 id: bouncy width:30 height: 30 color: "red" x: xpos y: ypos function updatePosition(){ xpos += xspeed if (xpos >= bouncy.parent.width - bouncy.width || xpos <= 0){ xspeed *= -1 } ypos += yspeed if (ypos >= bouncy.parent.height - bouncy.height || ypos <= 0){ yspeed *= -1 } } Timer { interval: 15; running: true; repeat: true; onTriggered: updatePosition() } }
-
The documentation recommends not using script for animation:
http://doc.qt.io/qt-5/qtquick-performance.html#animations
Another way would be to use a PathAnimation:
ApplicationWindow { id: root width: 640 height: 480 visible: true Rectangle{ property int xdir: 1 property int ydir: 1 id: bouncy width:30 height: 30 color: "red" x: 100 y: 100 function next_path() { var delta_x, delta_y; if (x == 0 || x == root.width - width) xdir= -xdir; if (y == 0 || y == root.height - height) ydir= -ydir; if (xdir == 1) delta_x = root.width - width - x; else delta_x = x; if (ydir == 1) delta_y = root.height - height - y; else delta_y = y if (delta_x > delta_y) delta_x = delta_y; else delta_y = delta_x; delta_x *= xdir; delta_y *= ydir; anim.path.pathElements[0].relativeX = delta_x; anim.path.pathElements[0].relativeY = delta_y; anim.duration = 3000 / root.width * Math.abs(delta_x); anim.running = true; } PathAnimation { id: anim target: bouncy path: Path { PathLine { } } onStopped: bouncy.next_path(); } Component.onCompleted: bouncy.next_path(); } }
-
The documentation recommends not using script for animation:
http://doc.qt.io/qt-5/qtquick-performance.html#animations
Another way would be to use a PathAnimation:
ApplicationWindow { id: root width: 640 height: 480 visible: true Rectangle{ property int xdir: 1 property int ydir: 1 id: bouncy width:30 height: 30 color: "red" x: 100 y: 100 function next_path() { var delta_x, delta_y; if (x == 0 || x == root.width - width) xdir= -xdir; if (y == 0 || y == root.height - height) ydir= -ydir; if (xdir == 1) delta_x = root.width - width - x; else delta_x = x; if (ydir == 1) delta_y = root.height - height - y; else delta_y = y if (delta_x > delta_y) delta_x = delta_y; else delta_y = delta_x; delta_x *= xdir; delta_y *= ydir; anim.path.pathElements[0].relativeX = delta_x; anim.path.pathElements[0].relativeY = delta_y; anim.duration = 3000 / root.width * Math.abs(delta_x); anim.running = true; } PathAnimation { id: anim target: bouncy path: Path { PathLine { } } onStopped: bouncy.next_path(); } Component.onCompleted: bouncy.next_path(); } }
Thanks! I think I'm starting to get the declarative thing now.
I came across this video from Qt dev 2015: The 8 mistakes of QtQuick newcomers which gives a fuller explanation.
-
No timer needed. Use SpriteSequence
http://doc.qt.io/qt-5/qml-qtquick-spritesequence.htmlexample:
http://doc.qt.io/qt-5/qtquick-imageelements-example.html -
No timer needed. Use SpriteSequence
http://doc.qt.io/qt-5/qml-qtquick-spritesequence.htmlexample:
http://doc.qt.io/qt-5/qtquick-imageelements-example.htmlThat's something different and doesn't seem to be relevant to a randomized animation.
-
The Sprite type has a property named to. In the to you can set randomized next sprite step.
For example:Sprite{ name: "still" source: "content/BearSheet.png" frameCount: 1 frameWidth: 256 frameHeight: 256 frameDuration: 100 to: {"still":0.9, "blink":0.1, "floating":0} }
In this Sprite after finish in 1/10 times Sprite named blink will be rendered and in 9/10 times this Sprite will be repeated. For more details aboud sequence you can read the example that I posted in past.