Qt
Internal/Contributor docs for the Qt SDK. <b>Note:</b> These are NOT official API docs; those are found <a href='https://doc.qt.io/'>here</a>.
Loading...
Searching...
No Matches
sprites.qdoc
Go to the documentation of this file.
1// Copyright (C) 2017 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
3
4/*!
5\page qtquick-effects-sprites.html
6\title Sprite Animations
7\brief Sprite-based animations with flexible transitioning
8
9\section1 Sprite Engine
10
11The \l {Qt Quick} sprite engine is a stochastic state machine combined with the ability
12to chop up images containing multiple frames of an animation.
13
14\section2 State Machine
15
16A primary function of the sprite engine is its internal state machine. This is not the same as
17the states and transitions in Qt Quick, and is more like a conventional state machine. Sprites
18can have weighted transitions to other sprites, or back to themselves. When a sprite animation
19finishes, the sprite engine will choose the next sprite randomly, based on the weighted transitions
20available for the sprite that just finished.
21
22You can affect the currently playing sprite in two ways. You can arbitrarily force it to immediately
23start playing any sprite, or you can tell it to gradually transition to a given sprite. If you
24instruct it to gradually transition, then it will reach the target sprite by going through valid
25state transitions using the fewest number of intervening sprites (but ignoring relative weightings).
26This allows you to easily insert a transitional animation between two different sprites.
27
28\image spriteenginegraph.png
29
30As an example, consider the above diagram which illustrates the sprites for a hypothetical 2D
31platform game character. The character starts by displaying the \e standing state. From this state,
32barring external input, he will transition to either the \e waiting animation, the \e walking animation,
33or play the \e standing animation again. Because the weights for those transitions are one, zero and three
34respectively, he has a one in four chance of playing the \e waiting animation when the \e standing animation
35finishes, and a three in four chance of playing the \e standing animation again. This allows for a character
36who has a slightly animated and variable behavior while waiting.
37
38Because there is a zero weight transition to the \e walking animation, the \e standing animation will not normally
39transition there. But if you set the goal animation to be the \e walking animation, it would play the \e walking
40animation when it finished the \e standing animation. If it was previously in the \e waiting animation, it would
41finish playing that, then play the \e standing animation, then play the \e walking animation. It would then continue to
42play the \e walking animation until the goal animation is unset, at which point it would switch to the \e standing
43animation after finishing the \e walking animation.
44
45If you then set the goal state to the \e jumping animation, it would finish the \e walking animation before
46playing the \e jumping animation. Because the \e jumping animation does not transition to other states, it will still
47keep playing the \e jumping animation until the state is forced to change. In this example, you could set it back to
48\e walking and change the goal animation to \e walking or to nothing (which would lead it to play the \e standing animation
49after the \e walking animation). Note that by forcibly setting the animation, you can start playing the animation
50immediately.
51
52\section2 Input Format
53
54The file formats accepted by the sprite engine are the same as the file formats accepted by other QML types,
55such as \l Image. In order to animate the image, however, the sprite engine requires the image file to contain
56all of the frames of the animation. They should be arranged in a contiguous line, which may wrap from the right
57edge of the file to a lower row starting from the left edge of the file (and which is placed directly below the
58previous row).
59
60\image spritecutting.png
61
62As an example, take the above image. For now, just consider the black numbers, and assume the squares are 40x40 pixels.
63Normally, the image is read from the top-left corner. If you specified the frame size as 40x40 pixels, and a frame count
64of 8, then it would read in the frames as they are numbered. The frame in the top left would be the first frame, the frame
65in the top right would be the fifth frame, and then it would wrap to the next row (at pixel location 0,40 in the file) to read
66the sixth frame. It would stop reading after the frame marked 8, and if there was any image data in the square below frame four
67then it would not be included in the animation.
68
69It is possible to load animations from an arbitrary offset, but they will still follow the same pattern.
70Consider now the red numbers. If we specify that the animation begins at pixel location 120,0, with a
71frame count of 5 and the same frame size as before, then it will load the frames as they are numbered in red.
72The first 120x40 of the image will not be used, as it starts reading 40x40 blocks from the location of 120,0.
73When it reaches the end of the file at 160,0, it then starts to read the next row from 0,40.
74
75The blue numbers show the frame numbers if you tried to load two frames of that size, starting from 40,40. Note
76that it is possible to load multiple sprites from one image file. The red, blue and black numbers can all
77be loaded as separate animations to the same sprite engine. The following code loads the animations as per the image.
78It also specifies that animations are to be played at 20 frames per second.
79
80\code
81Sprite {
82 name: "black"
83 source: "image.png"
84 frameCount: 8
85 frameWidth: 40
86 frameHeight: 40
87 frameRate: 20
88}
89Sprite {
90 name: "red"
91 source: "image.png"
92 frameX: 120
93 frameCount: 5
94 frameWidth: 40
95 frameHeight: 40
96 frameRate: 20
97}
98Sprite {
99 name: "blue"
100 source: "image.png"
101 frameX: 40
102 frameX: 40
103 frameCount: 2
104 frameWidth: 40
105 frameHeight: 40
106 frameRate: 20
107}
108\endcode
109
110Frames within one animation must be the same size. However, multiple animations within the same file
111do not. Sprites without a \l {Sprite::}{frameCount} specified assume that they take the entire file, and you must specify
112the frame size. Sprites without a frame size assume that they are square and take the entire file without wrapping,
113and you must specify a frame count.
114
115The sprite engine internally copies and cuts up images to fit in an easier-to-read internal format, which leads
116to some graphics memory limitations. Because it requires all the sprites for a single engine to be in the same
117texture, attempting to load many different animations can run into texture memory limits on embedded devices. In
118these situations, a warning will be output to the console containing the maximum texture size.
119
120There are several tools to help turn a set of images into sprite sheets. Here are some examples:
121\list
122 \li Photoshop plugin: \l http://www.johnwordsworth.com/projects/photoshop-sprite-sheet-generator-script
123 \li Gimp's SpriteSheet plugin
124 \li Cmd-line tool: \l http://www.imagemagick.org/script/montage.php
125\endlist
126
127\section2 QML Types Using the Sprite Engine
128
129Sprites for the sprite engine can be defined using the \l Sprite type. This type includes the input parameters,
130as well as the length of the animation and weighted transitions to other animations. It is purely a data class, and
131does not render anything.
132
133\l SpriteSequence is a type which uses a sprite engine to draw the sprites defined in it. It is a single and
134self-contained sprite engine, and does not interact with other sprite engines. \l Sprite types can be shared between
135sprite engine-using types, but this is not done automatically. So, if you have defined a sprite in one \l SpriteSequence
136you will need to redefine it (or reference the same \l Sprite type) in the sprites property of another \l SpriteSequence
137in order to transition to that animation.
138
139Additionally, \l ImageParticle can use \l Sprite types to define sprites for each particle. This is again a single
140sprite engine per type. This works similarly to \c SpriteSequence, but it also has the parameterized variability provided
141by the \l ImageParticle type.
142
143\section1 AnimatedSprite Type
144
145For use-cases which do not need to transition between animations, consider the \l AnimatedSprite type.
146This type displays sprite animations with the same input format, but only one at a time. It also provides more fine-grained
147manual control, as there is no sprite engine managing the timing and transitions behind the scenes.
148
149*/