diff --git a/doc/cookbook/Makefile.am b/doc/cookbook/Makefile.am index 2d3e6a87a..e8ca016e5 100644 --- a/doc/cookbook/Makefile.am +++ b/doc/cookbook/Makefile.am @@ -62,6 +62,8 @@ VIDEO_FILES = \ videos/textures-crossfade-two-textures.ogv \ videos/animations-complex.ogv \ videos/animations-reuse.ogv \ + videos/animations-moving-anchors.ogv \ + videos/animations-moving-depth.ogv \ $(NULL) EXTRA_DIST = \ diff --git a/doc/cookbook/animations.xml b/doc/cookbook/animations.xml index 284f48c4a..f9496a9ae 100644 --- a/doc/cookbook/animations.xml +++ b/doc/cookbook/animations.xml @@ -1816,4 +1816,478 @@ foo_button_pressed_cb (ClutterActor *actor, +
+ Moving actors + +
+ Problem + + You want to animate the movement of one or more actors. + For example: + + + + To move user interface elements in response to user input + (e.g. keyboard control of a character in a game). + + + To move a group of actors "off stage" to make way + for another group of actors (e.g. paging through + thumbnails in a photo viewer). + + + To move an actor to a different position in the + interface (e.g. moving an icon for a trashed file into + a wastebin). + + + +
+ +
+ Solutions + + Animate the actors movement on one or more axes + (x, y, + z/depth) using one or more of the approaches + available in the Clutter API (implicit animations, + ClutterState, ClutterAnimator). + +
+ Solution 1: Implicit animations + + This works well for simple movement of a single actor to + a single set of coordinates. Here is an example of how to animate + movement of a ClutterActor actor + to position 100.0 on x axis: + + + +clutter_actor_animate (actor, CLUTTER_LINEAR, 500, + "x", 100.0, + NULL); + + + + See this + example which demonstrates movement in each axis, + in response to (mouse) button presses. + +
+ +
+ Solution 2: <type>ClutterState</type> + + This suits simple, repeated movement of one or more actors + between sets of coordinates. Here is an example of how to + create two states for a ClutterState instance to + move two actors, actor1 and + actor2: + + + +ClutterState *transitions = clutter_state_new (); + +/* all state transitions take 250ms */ +clutter_state_set_duration (transitions, NULL, NULL, 250); + +/* create a state called move-down which moves both actors to y = 200.0 */ +clutter_state_set (transitions, NULL, "move-down", + actor1, "y", CLUTTER_EASE_OUT_CUBIC, 200.0, + actor2, "y", CLUTTER_EASE_OUT_CUBIC, 200.0, + NULL); + +/* create a state called move-up which moves both actors to y = 0.0 */ +clutter_state_set (transitions, NULL, "move-up", + actor1, "y", CLUTTER_EASE_OUT_CUBIC, 0.0, + actor2, "y", CLUTTER_EASE_OUT_CUBIC, 0.0, + NULL); + +/* move the actors by setting the state */ +clutter_state_set (transitions, "move-down"); + + + + This full + example shows how to move and simultaneously + scale two actors. When a button is pressed on one actor, it is + moved and scaled to occupy the right-hand side of the stage; + the other actor is simultaneously moved back to the left-hand + side of the stage and scaled down. + +
+ +
+ Solution 3: <type>ClutterAnimator</type> + + This is a good way to implement complex movement of + one or more actors between sets of coordinates. + + + +ClutterAnimator *animator = clutter_animator_new (); + +/* the animation takes 500ms */ +clutter_animator_set_duration (animator, 500); + +/* at the start of the animation, actor should be at 0.0,0.0; + * half-way through, at 100.0,100.0; + * by the end, actor should be at 150.0,200.0; + * note that you can set different easing modes for each + * part of the animation and for each property at each key + */ +clutter_animator_set (animator, + + /* keys for the start of the animation */ + actor, "x", CLUTTER_LINEAR, 0.0, 0.0, + actor, "y", CLUTTER_LINEAR, 0.0, 0.0, + + /* keys for half-way through the animation */ + actor, "x", CLUTTER_EASE_OUT_CUBIC, 0.5, 100.0, + actor, "y", CLUTTER_EASE_IN_CUBIC, 0.5, 100.0, + + /* keys for the end of the animation */ + actor, "x", CLUTTER_EASE_OUT_EXPO, 1.0, 150.0, + actor, "y", CLUTTER_EASE_OUT_CUBIC, 1.0, 200.0, + + NULL); + +/* run the animation */ +clutter_animator_start (animator); + + + + The full + example demonstrates how ClutterAnimator + can be used to programmatically animate multiple actors: in this + case, to simultaneously move three actors to random positions + along the x axis. Synchronising the + movement of three actors simultaneously using implicit + animations would be possible but awkward; + ClutterState might be another option, + but it wasn't really designed for this case: there are no persistent + states to transition between, as the actor positions are + generated on each key press. + + + If you want to apply the same movement to a group of + actors, rather than different movements for each actor, + it's often better to put the actors into a container + of some kind and move that instead of moving the actors + individually. + + +
+ +
+ +
+ Discussion + +
+ Movement can take an actor "outside" its container + + Actor movement in the x and + y axes is relative to the actor's parent + container. There is nothing to stop you animating an actor + until it falls outside the bounds of its container. This + could result in the actor moving "off" the interface; though it's + worth remembering that the actor is not unparented or destroyed + if this happens. + + To ensure that an actor remains visible, its position + should remain within the visible area of the container. In practice, + this means either anywhere in the container, if no clip area + has been set; or within the container's clip area, if set. + +
+ +
+ Anchor points can affect movement + + An actor's anchor point is defined as an x,y + coordinate relative to the top-left of the actor. The default + anchor point for an actor is in its top-left + corner. However, it is possible to set this to some other + coordinate, relative to the actor's top-left corner, + using the clutter_anchor_set_anchor_point() + function. For example: + + + +/* set the actor's size to 100px x 100px */ +clutter_actor_set_size (actor, 100, 100); + +/* set an anchor point half-way along the top of the actor */ +clutter_actor_set_anchor_point (actor, 50.0, 0.0); + + + + A positive anchor point within the width/height bounds of the + actor is inside the actor. An anchor point outside these bounds + is outside the actor. You can also set a negative + x or y value for + the anchor point, which will again place the point outside + the actor's bounds. + + This is important with respect to moving an actor, because + you are actually moving the anchor point and "dragging" the + actor along with it. + + For example: you have an actor with width 50px, and you + set its anchor-x property to 25.0. + If you move that actor on the x axis, you are + effectively moving a point half-way across the top of the + actor along the x axis (which in turn moves the + actor). + + Similarly, you could set the same actor's + anchor-x to -25.0. If you then + moved the actor along the x axis, you would + effectively be moving the point 25px left of the top of the actor + along that axis. + + The video below demonstrates the effect on movement of shifting + the anchor point on the x axis. The + red rectangle has anchor-x + set to 25.0; the green rectangle has + anchor-x set to 0.0 (the default); the + blue rectangle has anchor-x + set to -25.0. + + + + + + + Video showing the effect of anchor point on movement + + + + A ClutterAnimator is + used to move each of the rectangles to x = 225.0. + Although the three rectangles move to the same position on the + x axis, it's actually the the anchor points + which are at the same position. These all align on the + x axis with the left-hand edge of the green + rectangle. + +
+ +
+ Actors can move in the <varname>z</varname> axis + + The examples so far have shown how to move actors in + the x and y axes; but it + is also possible to move actors in the z + axis (i.e. move them closer or further away from the view point). + This lets you move actors under/over each other. + + To move an actor in the z axis, animate + its depth property. Animating to a negative + depth moves the actor away from the view point; animating to a + positive depth moves the actor towards the view point. + + Changing the depth of an actor also causes perspective + effects: the actor gets smaller and converges on the center + of the stage as it gets further from the view point, and + gets larger and diverges from the center of the stage as it gets + closer. This results in an apparent (but not actual) change in + the x,y position and scale of the actor. + + + Animating the depth of an actor is slightly different + from animating its x and y coordinates, as depth is relative + to the whole stage, not just the parent container of the + actor. This means that perspective effects are with + respect to the whole stage: so as an actor's depth + moves below 0.0, it converges on the center + of the stage, and may even apparently move outside its + container (if the container stays at the same depth). + + + The video below demonstrates the effect of animating + the depth of four actors to a value of -15000.0. + Note how the actors converge on the center of the stage, + as well as appearing to change position and scale; also note + that they appear to move outside the bounds of their parent containers + (the four yellow ClutterBoxes). + + + + + + + Video showing perspective effects when animating + actor depth + + + +
+ +
+ Movement is affected by constraints + + An actor can have its x,y position constrained by + the position of other actors through ClutterBindConstraints. + This can affect movement in two ways: + + + + If an actor has its x and/or + y properties + bound or aligned to another actor's, you can't animate + those properties. + + In effect this means that the bound actor can't be + moved on a bound axis directly, but can only be moved by + animating the constraint's properties. + + + + If you move an actor which has other actors bound to + it, the bound actors will also move. For example, if + the actor has several other actors whose x + properties are bound to its x property, + moving the actor on the x axis will also + move the bound actors on that axis. + + Similarly, if some actor is the source for + alignment constraints on other actors, moving the source + will cause those other actors to move, so that they remain in + alignment with it. + + + + For example, consider two actors bound by constraints + as follows: + + + +/* the source actor for the constraint */ +ClutterActor *source; + +/* the actor bound by the constraint */ +ClutterActor *target; + +/* a constraint to be added to target */ +ClutterConstraint *constraint; + +/* ...initialize actors etc... */ + +/* create a constraint for binding the x position of some actor to the + * x position of source + */ +constraint = clutter_bind_constraint_new (source, CLUTTER_BIND_X, 0.0); + +/* add the constraint to target with a name */ +clutter_actor_add_constraint_with_name (target, "bind-x", constraint); + + + + Animating source on the x + axis also animates target on the same axis: + + + +clutter_actor_animate (source, CLUTTER_LINEAR, 500, + "x", 250.0, + NULL); + + + + ...while this has no effect, as it would violate + constraint (it's best not to animate + target's x property + directly): + + + +clutter_actor_animate (target, CLUTTER_LINEAR, 500, + "x", 250.0, + NULL); + + + + But the constraint's properties can be animated, to change + how source and target + are bound; which in turn moves target: + + + +clutter_actor_animate (target, CLUTTER_LINEAR, 500, + "@constraints.bind-x.offset", 250.0, + NULL); + + + + Note the @constraints.<constraint name>.<constraint property> + syntax (which is why we needed to use + clutter_actor_add_constraint_with_name(), + so that the constraint can be accessed through the actor). + We are still animating target, but really + we're indirectly animating a property of one of its constraints. + + Another alternative would be to directly animate + the constraint's properties through ClutterState + or ClutterAnimator, rather than using + pseudo-properties on the actor animation: + + + +ClutterAnimator *animator = clutter_animator_new (); +clutter_animator_set_duration (animator, 500); + +clutter_animator_set (animator, + constraint, "offset", CLUTTER_LINEAR, 0.0, 0.0, + constraint, "offset", CLUTTER_LINEAR, 1.0, 250.0, + NULL); + +clutter_animator_start (animator); + + + + This could be useful if you need to animate + multiple constraints between multiple values simultaneously. + +
+ +
+ +
+ Full examples + + + Simple movement using implicit animations + + + a code sample should be here... but isn't + + + + + + Using <type>ClutterState</type> to repeatedly move + (and scale) two actors + + + a code sample should be here... but isn't + + + + + + Using <type>ClutterAnimator</type> to randomly move + three actors along the <varname>x</varname> axis + + + a code sample should be here... but isn't + + + + +
+ +
+ diff --git a/doc/cookbook/videos/animations-moving-anchors.ogv b/doc/cookbook/videos/animations-moving-anchors.ogv new file mode 100644 index 000000000..5fc7952d2 Binary files /dev/null and b/doc/cookbook/videos/animations-moving-anchors.ogv differ diff --git a/doc/cookbook/videos/animations-moving-depth.ogv b/doc/cookbook/videos/animations-moving-depth.ogv new file mode 100644 index 000000000..93c75cdd6 Binary files /dev/null and b/doc/cookbook/videos/animations-moving-depth.ogv differ