cookbook: Added "inverting an animation" recipe
Added a new recipe (based on the skeleton in the animations section of the cookbook) about inverting an animation by reversing the direction of its timeline. Uses clutter_actor_animate() as the basic approach, but mentions ClutterState and ClutterAnimator as well.
This commit is contained in:
parent
bfb51adf97
commit
6a443a0cd3
@ -15,7 +15,7 @@
|
||||
<para>introduction</para>
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<section id="animations-inversion">
|
||||
<title>Inverting Animations</title>
|
||||
|
||||
<section>
|
||||
@ -28,13 +28,156 @@
|
||||
<section>
|
||||
<title>Solution</title>
|
||||
|
||||
<para>...</para>
|
||||
<para>Reverse the direction of the <type>ClutterTimeline</type>
|
||||
associated with the animation.</para>
|
||||
|
||||
<para>For example, here's how to invert an implicit
|
||||
animation which moves an actor along the <varname>x</varname>
|
||||
axis. The direction of the animation is inverted when the
|
||||
movement along the <varname>x</varname> axis is completed; it is
|
||||
also inverted if the mouse button is pressed on the actor.</para>
|
||||
|
||||
<para>First, set up the animation:</para>
|
||||
|
||||
<informalexample>
|
||||
<programlisting>
|
||||
<![CDATA[
|
||||
ClutterAnimation *animation;
|
||||
|
||||
/*
|
||||
* animate actor to x = 300.0;
|
||||
* the implicit animation functions return a ClutterAnimation
|
||||
* which we can use to invert the timeline
|
||||
*/
|
||||
animation = clutter_actor_animate (actor,
|
||||
CLUTTER_EASE_IN_OUT_CUBIC,
|
||||
2000,
|
||||
"x", 300.0,
|
||||
NULL);
|
||||
|
||||
/* callback for when the animation completes */
|
||||
g_signal_connect (animation,
|
||||
"completed",
|
||||
G_CALLBACK (_animation_done_cb),
|
||||
NULL);
|
||||
|
||||
/*
|
||||
* callback for when the mouse button is pressed on the actor;
|
||||
* note the animation is passed as user data, so we can
|
||||
* get at the timeline
|
||||
*/
|
||||
g_signal_connect (actor,
|
||||
"button-press-event",
|
||||
G_CALLBACK (_on_click_cb),
|
||||
animation);
|
||||
]]>
|
||||
</programlisting>
|
||||
</informalexample>
|
||||
|
||||
<para>Next, add a function for inverting the timeline:</para>
|
||||
|
||||
<informalexample>
|
||||
<programlisting>
|
||||
<![CDATA[
|
||||
static void
|
||||
_invert_timeline (ClutterTimeline *timeline)
|
||||
{
|
||||
ClutterTimelineDirection direction = clutter_timeline_get_direction (timeline);
|
||||
|
||||
if (direction == CLUTTER_TIMELINE_FORWARD)
|
||||
direction = CLUTTER_TIMELINE_BACKWARD;
|
||||
else
|
||||
direction = CLUTTER_TIMELINE_FORWARD;
|
||||
|
||||
clutter_timeline_set_direction (timeline, direction);
|
||||
}
|
||||
]]>
|
||||
</programlisting>
|
||||
</informalexample>
|
||||
|
||||
<para>Then add a function which calls <function>_invert_timeline</function>
|
||||
when the animation completes. More importantly, the callback should
|
||||
stop emission of the "completed" signal by the animation. This
|
||||
prevents the <type>ClutterAnimation</type> underlying the implicit
|
||||
animation from being unreferenced; which in turn allows it to be
|
||||
inverted:</para>
|
||||
|
||||
<informalexample>
|
||||
<programlisting>
|
||||
<![CDATA[
|
||||
static void
|
||||
_animation_done_cb (ClutterAnimation *animation,
|
||||
gpointer user_data)
|
||||
{
|
||||
/* stop the completed signal before the ClutterAnimation is unreferenced */
|
||||
g_signal_stop_emission_by_name (animation, "completed");
|
||||
|
||||
/* invert the timeline associated with the animation */
|
||||
ClutterTimeline *timeline = clutter_animation_get_timeline (animation);
|
||||
_invert_timeline (timeline);
|
||||
}
|
||||
]]>
|
||||
</programlisting>
|
||||
</informalexample>
|
||||
|
||||
<para>Finally, the click callback function uses the same
|
||||
<function>_invert_timeline</function> function if the animation
|
||||
is playing; but if the animation is stopped, it will
|
||||
start it instead:</para>
|
||||
|
||||
<informalexample>
|
||||
<programlisting>
|
||||
<![CDATA[
|
||||
static void
|
||||
_on_click_cb (ClutterActor *actor,
|
||||
ClutterEvent *event,
|
||||
gpointer user_data)
|
||||
{
|
||||
ClutterAnimation *animation = (ClutterAnimation *)user_data;
|
||||
|
||||
ClutterTimeline *timeline = clutter_animation_get_timeline (animation);
|
||||
|
||||
if (clutter_timeline_is_playing (timeline))
|
||||
{
|
||||
_invert_timeline (timeline);
|
||||
}
|
||||
else
|
||||
{
|
||||
clutter_timeline_start (timeline);
|
||||
}
|
||||
}
|
||||
]]>
|
||||
</programlisting>
|
||||
</informalexample>
|
||||
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<title>Discussion</title>
|
||||
|
||||
<para>...</para>
|
||||
<para>If you are using <type>ClutterAnimator<type> rather than
|
||||
implicit animations, <function>clutter_animator_get_timeline()</function>
|
||||
enables you to get the underlying timeline; you could then use
|
||||
the techniques shown above to invert it.</para>
|
||||
|
||||
<para><type>ClutterState</type> enables a different approach
|
||||
to "inverting" an animation: rather than having a single animation
|
||||
which you invert, you would define two or more
|
||||
<emphasis>keys</emphasis> for an actor (or set of actors) and
|
||||
transition between them.</para>
|
||||
|
||||
<para>For the example above, you would define two keys:
|
||||
one for the actor's initial position; and a second for the actor
|
||||
at <code>x = 300.0</code>. You would also define the
|
||||
transition between them: 2000 milliseconds with a
|
||||
<constant>CLUTTER_EASE_IN_OUT_CUBIC</constant> easing mode.</para>
|
||||
|
||||
<para>With the states defined, you would then use
|
||||
<function>clutter_state_set_state()</function> inside callbacks to
|
||||
animate the actor between the two <varname>x</varname> positions.
|
||||
Behind the scenes, <type>ClutterState</type> would handle the
|
||||
animations and timelines for you.</para>
|
||||
|
||||
</section>
|
||||
|
||||
</section>
|
||||
|
Loading…
Reference in New Issue
Block a user