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

Project structure

CMake project file

The CMake project file has a basic build script.

cmake_minimum_required (VERSION 3.21.1)

project(sprite_animations VERSION 0.0.1 LANGUAGES C CXX ASM)
if (NOT TARGET Qul::Core)
    find_package(Qul)
endif()

qul_add_target(sprite_animations QML_PROJECT mcu_sprite_animations.qmlproject GENERATE_ENTRYPOINT)

app_target_setup_os(sprite_animations)
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
    }
}

Specifying the frame size with ImageFiles.MCU.resourceAnimatedSpriteFrameWidth and ImageFiles.MCU.resourceAnimatedSpriteFrameHeight offers a chance to optimize the image source.

The resource compiler (qulrcc tool) splits the image source into 16 frames internally, and it figures out common parts between the series of the frames and reduce memory footprint by sharing them.

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
    }
}

Files:

Images:

See also Managing Resources.

Available under certain Qt licenses.
Find out more.