diff --git a/doc/cookbook/Makefile.am b/doc/cookbook/Makefile.am index 78ca1984c..9ce15c241 100644 --- a/doc/cookbook/Makefile.am +++ b/doc/cookbook/Makefile.am @@ -57,6 +57,7 @@ VIDEO_FILES = \ videos/textures-split-go.ogv \ videos/events-mouse-scroll.ogv \ videos/textures-crossfade-two-textures.ogv \ + videos/animations-complex.ogv \ $(NULL) EXTRA_DIST = \ diff --git a/doc/cookbook/animations.xml b/doc/cookbook/animations.xml index ee0b61b12..49c9a0832 100644 --- a/doc/cookbook/animations.xml +++ b/doc/cookbook/animations.xml @@ -1011,4 +1011,431 @@ clutter_actor_set_z_rotation_from_gravity (actor, +
+ Creating complex animations with + <type>ClutterAnimator</type> + +
+ Problem + + You want to create a complex animation involving one or more + actors. The animation will consist of a sequence of transitions + over multiple properties on each actor. + + An example might be moving several actors between points, + with different types of movement for each part of the path, while + transforming each actor (e.g. scaling or rotating it). + +
+ +
+ Solution + + Use a ClutterAnimator to define the animation. + + Because there are many complex animations you + could implement, the example below does + this: + + + + + + + Video showing a complex animation of an actor + using ClutterAnimator + + + + Although this uses a single actor, the animation is complex + enough to make it difficult to implement with implicit animations + or ClutterState (see + the Discussion + section for reasons why). + + Here is a JSON definition of the stage, actors, and + the ClutterAnimator for this + animation: + + + JSON definition of a complex animation using + <type>ClutterAnimator</type> + + + a code sample should be here... but isn't + + + + + + The core to understanding this example is understanding + how to define keys for a CutterAnimator. As + this is an involved topic, further explanation + is given in the + Discussion section. + + + The program for loading this JSON definition from a file + is as follows: + + + Simple program for loading a JSON script; + any key press starts the animation + + + a code sample should be here... but isn't + + + + + + It is also possible to use the ClutterAnimator + C API to define keys for an animation, but this will + typically be much more verbose than the JSON equivalent. + + One other advantage of JSON is that it is much simpler + to tweak and test an animation, as you don't have to recompile + the application each time you edit it (you just load + the new JSON file). + + +
+ +
+ Discussion + + You can think of ClutterAnimator + as a way to give directions to actors. For example, + you could give a real (human) actor a direction like "move + downstage; when you get there, stop and + rotate 90 degrees to your right". In code, + this might equate to a transition in the x + and y properties of the actor, followed by a + rotation in one axis. + + + ClutterAnimator can give + "directions" to any type of GObject, but we concentrate + on animating ClutterActors in this section. + + + Each direction like this has an implicit + timeline, spanning the length of time the direction should + take to fulfil (you set the length of the timeline through + the duration property of the + ClutterAnimator). But within that timeline, you may + change the proportion of time spent on each action: "move + downstage quickly, then slowly rotate 90 degrees + to your right". The direction is the same, but we've + specified how much of the timeline should be devoted to each + action. + + In ClutterAnimator, this concept is + captured by key frames. A + key frame represents a point somewhere along the timeline, + with one or more target property values for one or more actors. + A ClutterAnimator manages the transitions + between property values for each object, ensuring that + the target values are reached when the associated key frame + is reached. + + To change the amount of time a transition + should take, you change the percentage of the timeline + between key frames. Using our real stage directions as an + example, you might define the key frames like this: + + + + 0.2 (after 20% of the timeline): + arrive downstage + + + 1.0 (by the end of the timeline): + achieve a 90 degree rotation to the right + + + + See + this + section for more details about keys and key frames. + + Finally, a direction might be further refined with + a description of the kind of movement to use: + rather than saying "move downstage quickly, then + slowly rotate 90 degrees to your right" a director could say: + "start off slowly, but build up to a run; + run downstage quickly; then stop and start rotating + slowly to your right, gradually speeding up, turn a little more, then slow + down gradually; you should end up rotated 90 degrees to your right" + (this granularity of description is closer to what you might + see in dance notation like + Laban; + though of course you can't animate human opacity, scale, dimensions + etc...). + + ClutterAnimator gives you this level of + granularity. Each transition to a property value between + key frames can have a separate easing mode: + for example, starting off slowly and building to a constant + speed equates to an "ease in" mode; starting slowly, speeding + up, maintaining a constant speed, then gradually slowing down + equates to "ease in and ease out". + + To summarise: creating a complex animation means deciding: + + + + Which properties need to change on which actors? + + + What target value should each property transition to? + + + How quickly (by which key frame) should the property + reach the target value? + + + What "shape" (easing mode) should the change to + the target value follow? + + + +
+ Understanding keys and key frames + + A ClutterAnimator maintains a list of + properties objects, each being a unique pair + of object (an object to be animated) + + name (name of the property + to be animated on that object). + + Each properties object in turn has a + list of keys, with each key having three elements: + + + + The key frame, expressed as a fraction + (between 0.0 and 1.0) of the duration of the animation. At this + point, the named property should reach a target value. + + + The easing mode to use to transition + the property to that value. + + + The target value the property + should transition to. + + + + For example: + + + +{ + "object" : "rectangle", + "name" : "x", + "ease-in" : true, + "keys" : [ + [ 0.0, "linear", 0.0 ], + [ 0.1, "easeInCubic", 150.0 ], + [ 0.8, "linear", 150.0 ], + [ 1.0, "easeInCubic", 0.0 ] + ] +} + + + + defines a sequence of transitions for the x + property (position on the x axis) of the rectangle + object, as follows: + + + + [ 0.0, "linear", 0.0 ]: + At the start of the animation, x should be + 0.0; linear is used as the easing mode, as there + is no transition here. + + + + [ 0.1, "easeInCubic", 150.0 ]: + By 10% of the way through the animation, + x should reach a value of 150.0. + This moves the rectangle horizontally across the stage. + + The easeInCubic easing mode means that + the transition to the new value starts slow and speeds up. + This makes the movement look more "natural". + + + + [ 0.8, "linear", 150.0 ]: + From 10% of the way through the animation to 80% + of the way through, the x value remains at + 150.0. This makes the rectangle stay still + on the x axis throughout this period. + + It's important to specify interim key frames if + in a later key frame you intend to change the value again + (as is done for the x value here). Otherwise + you can get premature transitions to a value over longer + periods than you intended. By specifying the interim + key frames where the value remains constant, you ensure + that it doesn't change before you want it to. + + + + [ 1.0, "easeInCubic", 0.0 ]: + From 80% of the way through the animation to the end, + the x value should transition back to + 0.0. This moves the actor back to its + starting position on the x axis. Again, an easeInCubic + easing mode is used to make the transition appear more natural. + + + + There are two more properties you can set for each + object/property pair: + + + + Set ease-in to true to + animate to the target value at the first key frame. If + ease-in is false, the animation will + "jump" to the target value instead (if the target value is + different from the current value). + + + + Set interpolation to either + "linear" (the default) or "cubic". + This sets how ClutterAnimator transitions between + key frames; in effect, it further modulates any easing modes + set on individual keys: if set to "cubic", you + get a slightly more natural and gentle transition between + key frames than you do if set to "linear". + + + +
+ +
+ Why <type>ClutterAnimator</type>? + + Why use ClutterAnimator and not the other + Clutter animation + approaches for complex animations? + + + + Implicit animations can animate + properties on a single actor; however, you can only specify a + single transition for each property. Also, it's not possible + to describe complex movement along a path in a single implicit + animation: you would have to chain several animations together + to do that. + + To animate multiple actors, you'd also need multiple + implicit animations, one for each actor. These animations would + also need to be synchronized (for example, by sharing a + single timeline). + + So it would be possible, but more difficult than + an implementation using ClutterAnimator. + + + + ClutterState can + be used for complex animations: each state can describe + transitions for multiple actors and multiple properties. + However, to make continuous movement (as in the example), + you would need to write a state for each movement between a + pair of points; then add a callback so that when each state + is reached, the animation moves onto the next state. This + adds some code (a handler for the completed + signal emitted by the ClutterState to set + the next state). This could work OK for a few states, + but doesn't scale as well as ClutterAnimator + if you have many transitions. + + + ClutterState and + ClutterAnimator are not mutually exclusive. If + you generally need to transition between several known states + (e.g. hiding/revealing menus which stay in the same place, + moving between two UI layouts), but want to create a + complex animation between states, you can use + ClutterAnimators to define the transitions: see + the documentation for + clutter_state_set_animator() for + details. + + + + + + ClutterAnimator is a good fit for complex + animations, and probably the best fit for the most complex: + it is the simplest way to encode a sequence of transitions + for a list of object/property pairs which can be treated + as a single animation. This is largely because + ClutterAnimator is effectively managing the + chaining together of the individual transitions into a whole. + + One other feature of ClutterAnimator which + isn't demonstrated here is how it enables transitions to overlap. + For example, let's say you wanted an actor + to move along a complex path (e.g. described by five pairs of + x,y coordinates); but during that movement, you + wanted the actor to continuously transition to a scale of + 4.0 on both the x and y axes. + + To achieve this with ClutterState, you would + need to set up five transitions (one to move to each pair of + x,y coordinates); plus a callback to chain the state transitions + together; and within each transition, you'd have to figure out a + percentage of the scaling to apply, so that the actor + was at a scale of 4.0 on reaching the final state. + + With ClutterAnimator, you can treat the + movement between the coordinates and the scaling separately + within the same animation, but overlap their key frames. This + makes coding overlapping animations of different properties + much more straightforward. See + this JSON + definition for an example of how to do this. + +
+ +
+ +
+ Full example + + + Running multiple transition sequences with + different key frames in parallel using + <type>ClutterAnimator</type> + + + This JSON file can be loaded with the same code + as used for this + example, by passing the JSON file name on the command line: + + + $ ./animations-complex animations-complex-overlapping.json + + + + + + a code sample should be here... but isn't + + + +
+ +
+ diff --git a/doc/cookbook/videos/animations-complex.ogv b/doc/cookbook/videos/animations-complex.ogv new file mode 100644 index 000000000..1effec846 Binary files /dev/null and b/doc/cookbook/videos/animations-complex.ogv differ