C

Qt Quick Ultralite sprite_animations Example

Demonstrates how to create a sprite animation.

Overview

The sprite_animations example shows how to create a sprite animation from frame sequences in an image file.

The image source for this example consist of 16 frames, where each frame size is 180x160.

Target platforms

Image formats

Qt Quick Ultralite lets you use a hardware image decoder instead of the default. Both the AnimatedSprite and AnimatedSpriteDirectory QML types support the registered image format for the sprite animation.

The example shows the use case of the image decoder on the STM32F769i and STM32H750b boards. For these two boards, the project configures the JPEG decoder and uses the raw image data of JPEG files in the ImageFiles node. The image decoder enables to decode and render the image data at runtime. See Qt Quick Ultralite imagedecoder Example and Using JPEG decoder for more details.

For the other boards and platforms, the project uses PNG image file and the resource compiler to decode the image at build time.

Project structure

CMake project file

The following CMake example shows how to decode images on platforms that does not use the JPEG decoder:

qul_add_target(sprite_animations
    QML_PROJECT mcu_sprite_animations.qmlproject
    GENERATE_ENTRYPOINT
)

The following QmlProject example show how you can configure a JPEG decoder with the necessary image resource properties and platform configuration:

qul_add_target(sprite_animations
    QML_PROJECT mcu_sprite_animations_jpeg.qmlproject
    os/${QUL_OS_LOWERCASE}/main.cpp
)
QmlProject file

The Qmlproject file includes the required Qml and Image files.

import QmlProject 1.3

Project {
    mainFile: "sprite_animations.qml"
    QmlFiles {
        files: [
            "ToggleButton.qml"
        ]
    }
    ImageFiles {
        files: [
            "qt-image-sequence.png"
        ]
        MCU.resourceAnimatedSpriteFrameWidth: 180
        MCU.resourceAnimatedSpriteFrameHeight: 160
    }
}

QmlProject offers ImageFiles.MCU.resourceAnimatedSpriteFrameWidth, ImageFiles.MCU.resourceAnimatedSpriteFrameHeight, and ImageFiles.MCU.resourceAnimatedSpriteOptimizations to let you optimize the image sources.

The resource compiler splits the image source into 16 frames internally, and applies the cropping technique to optimize them for better performance and lower memory footprint. This enables rendering only the changed parts between a series of the frames.

Application UI

The sprite_animations.qml file defines AnimatedSprite type. It defines the size of a single frame, number of frames in an image, and source of the image. The animation starts by default. When a user clicks the image, it runs or stops the animations based on the current running value.

    AnimatedSprite {
        id: sprite
        anchors.centerIn: parent
        source: "qt-image-sequence.png"

        frameDuration: 80
        frameCount: 16
        frameWidth: 180
        frameHeight: 160

        loops: AnimatedSprite.Infinite

        onFinished: {
            txtMsg.text = "Finished"
        }

        onRunningChanged: {
            if (sprite.running) {
                txtMsg.text = ""
            }
        }

        MouseArea {
            anchors.fill: parent
            onClicked: {
                if (sprite.running) {
                    sprite.stop()
                } else {
                    sprite.start()
                }
            }
        }
    }

On the top-left corner of the UI, the number and the duration of the current frame (in milliseconds) of each frame of the animation.

    Column {
        id: spriteInfo
        anchors.top: parent.top
        anchors.left: parent.left
        anchors.margins: 16
        spacing: 4

        Text {
            id: txtFrameNo
            text: "frame: " + (sprite.currentFrame + 1) + " / " + sprite.frameCount
            font.pixelSize: 14
            color: "white"
        }
        Text {
            id: txtDuration
            text: "duration: " + sprite.frameDuration
            font.pixelSize: 14
            color: "white"
        }
        Text {
            id: txtMsg
            font.pixelSize: 14
            text: ""
            color: "white"
        }
    }

The application has a button on the top-right corner to toggle the loops property value between AnimatedSprite.Infinite and 1.

    ToggleButton {
        id: toggleLoops
        width: parent.width / 4
        height: parent.height / 9
        anchors.right: parent.right
        anchors.top: parent.top
        anchors.margins: 8
        checkedText: "Infinite"
        uncheckedText: "Once"
        onCheckedChanged: {
            if (toggleLoops.checked) {
                sprite.loops = AnimatedSprite.Infinite
            } else {
                sprite.loops = 1
            }
        }
    }

The ToggleButton is a custom component using the simple visual QML types such as Rectangle, MouseArea, Text, and Row.

import QtQuick 2.15

Rectangle {
    id: control
    color: "white"

    property bool checked: true
    readonly property color foregroundColor: "black"
    readonly property int borderWidth: 1
    readonly property alias checkedText: txtChecked.text
    readonly property alias uncheckedText: txtUnchecked.text

    Row {
        x: control.borderWidth
        y: control.borderWidth
        spacing: control.borderWidth

        Rectangle {
            id: leftPart
            width: (control.width - control.borderWidth * 3) / 2
            height: (control.height - control.borderWidth * 2)
            color: control.checked? control.color : control.foregroundColor

            Text {
                id: txtChecked
                anchors.centerIn: parent
                color: control.checked? control.foregroundColor : control.color
                font.pixelSize: 14
            }
        }
        Rectangle {
            id: rightPart
            width: leftPart.width
            height: leftPart.height
            color: control.checked? control.foregroundColor : control.color

            Text {
                id: txtUnchecked
                anchors.centerIn: parent
                color: control.checked? control.color : control.foregroundColor
                font.pixelSize: 14
            }
        }
    }

    MouseArea {
        anchors.fill: parent
        onClicked: control.checked = !control.checked
    }
}
Using JPEG decoder

On platforms that use a JPEG decoder, you can use the MCU.resourceKeepRawData QmlProject property to bundle the JPEG files as the raw image data. You can also define MCU.Config.maxResourceCacheSize to make sure there is enough space to store the decoded image data at runtime.

import QmlProject 1.3

Project {
    MCU.Config {
        // enough size to contain one decoded image
        maxResourceCacheSize: 153600
    }
    QmlFiles {
        files: [
            "ToggleButton.qml",
            "sprite_animations_jpeg.qml"
        ]
    }
    ImageFiles {
        files: [
            "qt-image-sequence/00.jpg",
            "qt-image-sequence/01.jpg",
            "qt-image-sequence/02.jpg",
            "qt-image-sequence/03.jpg",
            "qt-image-sequence/04.jpg",
            "qt-image-sequence/05.jpg",
            "qt-image-sequence/06.jpg",
            "qt-image-sequence/07.jpg",
            "qt-image-sequence/08.jpg",
            "qt-image-sequence/09.jpg",
            "qt-image-sequence/10.jpg",
            "qt-image-sequence/11.jpg",
            "qt-image-sequence/12.jpg",
            "qt-image-sequence/13.jpg",
            "qt-image-sequence/14.jpg",
            "qt-image-sequence/15.jpg"
        ]
        MCU.resourceAnimatedSprite: true
        MCU.resourceKeepRawData: true
    }
}

The example uses a series of frame images with AnimatedSpriteDirectory to emphasize the benefit of the hardware decoding. This reduces memory usage and CPU load for the sprite animation.

    AnimatedSpriteDirectory {
        id: sprite
        anchors.centerIn: parent
        sourcePath: "qt-image-sequence"

        frameDuration: 80
        loops: AnimatedSprite.Infinite

        readonly property int frameCount: 16
        ...

Files:

Images:

See also Managing Resources.

Available under certain Qt licenses.
Find out more.