C

Qt Quick Ultralite精灵动画示例

演示如何创建精灵动画。

概述

sprite_animations示例显示如何从图像文件中的帧序列创建精灵动画。

此示例的图像源包含16帧,每帧大小为180x160。

目标平台

图像格式

Qt Quick Ultralite让您可以使用硬件图像解码器而不是默认的解码器。AnimatedSprite和AnimatedSpriteDirectory QML类型都支持注册的精灵动画图像格式。

STM32F769iSTM32H750bInfineon TRAVEO™ T2G CYT4DN 板上的示例展示了图像解码器的用例。对于这些板,项目配置了JPEG解码器,并使用 ImageFiles 节中的JPEG文件的原始图像数据。图像解码器允许在运行时解码和渲染图像数据。有关详细信息,请参阅Qt Quick Ultralite imagedecoder ExampleUsing JPEG decoder

注意:由于图形驱动程序的限制,目前支持源JPEG图像的唯一子采样模式为YUV420。有关更多信息,请参阅Sample application user guide for JPEG decode driver TRAVEO™ T2G cluster series User Manual。为了将源图像转换为YUV420子采样格式,您可以使用ImageMagick Convert工具:convert input.jpg -sampling-factor 4:2:0 output.jpg

注意:对于Infineon TRAVEO™ T2G CYT4DN,设置必需的CMake变量TVII_JPEG_DRIVER_DIR。它应指向JPEG解码器SDK的根目录。

对于其他板和平台,项目使用PNG图像文件和资源编译器在构建时解码图像。

项目结构

CMake项目文件

以下CMake示例展示了如何在没有使用JPEG解码器的平台上解码图像。

qul_add_target(sprite_animations
    QML_PROJECT mcu_sprite_animations.qmlproject
    GENERATE_ENTRYPOINT
)

以下QmlProject示例展示了如何配置JPEG解码器,需要的图像资源属性和平台配置。

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

Qmlproject文件包含了必需的Qml和Image文件。

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提供了ImageFiles.MCU.resourceAnimatedSpriteFrameWidthImageFiles.MCU.resourceAnimatedSpriteFrameHeightImageFiles.MCU.resourceAnimatedSpriteOptimizations,以使您优化图像源。

资源编译器内部将图像源分割成16帧,并应用裁剪技术以优化它们,以提高性能并降低内存占用。这允许只渲染一系列帧之间的变化部分。

应用程序UI

sprite_animations.qml文件定义了AnimatedSprite类型。它定义了单个帧的大小,图像中的帧数以及图像的源。动画默认启动。当用户点击图像时,根据当前的running值运行或停止动画。

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

在UI的左上角,显示了当前帧(以毫秒为单位)的帧数和持续时间。

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

应用程序在右上角有一个按钮,用于在AnimatedSprite之间的loops属性值之间切换无限和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
            }
        }
    }

ToggleButton是一个自定义组件,使用简单的QML类型如RectangleMouseAreaTextRow

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
    }
}
使用JPEG解码器

在您使用的JPEG解码器的平台上,您可以使用QmlProject的MCU.resourceKeepRawData属性来打包JPEG文件作为原始图像数据。您还可以定义MCU.Config.maxResourceCacheSize,以确保有足够的空间在运行时存储解码的图像数据。

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

示例使用一系列帧图像和AnimatedSpriteDirectory强调硬件解码的优点。这减少了精灵动画的内存使用和CPU负载。

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

        frameDuration: 80
        loops: AnimatedSprite.Infinite

        readonly property int frameCount: 16
        ...

文件

图像

另请参阅 资源管理

在特定Qt许可证下可用。
了解更多信息。