/usr/share/gtk-doc/html/clutter-cookbook/animations-path.html is in libclutter-1.0-doc 1.24.2-1.
This file is owned by root:root, with mode 0o644.
The actual contents of the file can be viewed below.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 | <html><head><meta http-equiv="Content-Type" content="text/html; charset=utf-8"><title>10. Animating an actor along a curved path</title><link rel="stylesheet" type="text/css" href="style.css"><meta name="generator" content="DocBook XSL Stylesheets V1.78.1"><link rel="home" href="index.html" title="The Clutter Cookbook"><link rel="up" href="animations.html" title="Chapter 5. Animations"><link rel="prev" href="animations-scaling.html" title="9. Animated scaling"><link rel="next" href="text.html" title="Chapter 6. Text"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">10. Animating an actor along a curved path</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="animations-scaling.html">Prev</a> </td><th width="60%" align="center">Chapter 5. Animations</th><td width="20%" align="right"> <a accesskey="n" href="text.html">Next</a></td></tr></table><hr></div><div class="section"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="animations-path"></a>10. Animating an actor along a curved path</h2></div></div></div><div class="section"><div class="titlepage"><div><div><h3 class="title"><a name="idp62554784"></a>10.1. Problem</h3></div></div></div><p>You want to animate an actor along a curved path: for
example, to move an actor in a circle or spiral.</p></div><div class="section"><div class="titlepage"><div><div><h3 class="title"><a name="idp62556064"></a>10.2. Solution</h3></div></div></div><p>Create a <span class="type">ClutterPath</span> to describe the
path the actor should move along; then create a
<span class="type">ClutterPathConstraint</span> based on that path:</p><div class="informalexample"><pre class="programlisting">ClutterPath *path;
ClutterConstraint *constraint;
/* create the path */
path = clutter_path_new ();
/* first node is at 30,60 */
clutter_path_add_move_to (path, 30, 60);
/* add a curve to the top-right of the stage, with control
* points relative to the start point at 30,60
*/
clutter_path_add_rel_curve_to (path,
120, 180,
180, 120,
240, 0);
/* create a constraint based on the path */
constraint = clutter_path_constraint_new (path, 0.0);</pre></div><div class="note" style="margin-left: 0.5in; margin-right: 0.5in;"><h3 class="title">Note</h3><p>For more on the types of curve and line segment available,
see the <span class="type">ClutterPath</span> API documentation.</p></div><p>Next, add the constraint to an actor; in this case, the
actor is a red rectangle:</p><div class="informalexample"><pre class="programlisting">ClutterActor *rectangle;
ClutterActor *stage = clutter_stage_new ();
/* ...set size stage, color, etc... */
const ClutterColor *red_color = clutter_color_new (255, 0, 0, 255);
rectangle = clutter_rectangle_new_with_color (red_color);
clutter_actor_set_size (rectangle, 60, 60);
/* add the constraint to the rectangle; note that this
* puts the rectangle at the start of the path, i.e. at position 30,60;
* we also give the constraint a name, so we can use it from an implicit
* animation
*/
clutter_actor_add_constraint_with_name (rectangle, "path", constraint);
/* add the rectangle to the stage */
clutter_actor_add_child (stage, rectangle);</pre></div><p>Note how the constraint has to be assigned a name (here, "path")
to make it accessible via implicit animations.</p><p>Finally, animate the constraint's <code class="varname">offset</code>
property; which in turn moves the actor along the path:</p><div class="informalexample"><pre class="programlisting">ClutterTimeline *timeline;
/* create a timeline with 1000 milliseconds duration, which loops
* indefinitely and reverses its direction each time it completes
*/
timeline = clutter_timeline_new (1000);
clutter_timeline_set_repeat_count (timeline, -1);
clutter_timeline_set_auto_reverse (timeline, TRUE);
/* animate the offset property on the constraint from 0.0 to 1.0;
* note the syntax used to refer to the constraints metadata for the
* rectangle actor:
*
* "@constraints.<constraint name>.<property>"
*/
clutter_actor_animate_with_timeline (rectangle, CLUTTER_LINEAR, timeline,
"@constraints.path.offset", 1.0,
NULL);
/* ...show the stage, run the mainloop, free memory on exit... */</pre></div><p>The <a class="link" href="animations-path.html#animations-path-example-1" title="Example 5.16. Using a ClutterPathConstraint with implicit animations to move an actor along a curved path">full
example</a> shows how these fragments fit together.
The animation produced by this example looks
like this:</p><p><video controls="controls" src="videos/animations-path.ogv"><a href="videos/animations-path.ogv"></a></video></p><p>The <a class="link" href="animations-path.html#animations-path-example-2" title="Example 5.17. Using a ClutterPathConstraint with ClutterAnimator to animate an actor on a simulated circular path">second full
example</a> animates an actor around a simulated circle
using a more complex <span class="type">ClutterPath</span>.</p></div><div class="section"><div class="titlepage"><div><div><h3 class="title"><a name="idp62571232"></a>10.3. Discussion</h3></div></div></div><p>Animating an actor using <span class="type">ClutterPathConstraint</span>
is the recommended way to animate actors along curved paths. It
replaces the older <span class="type">ClutterBehaviourPath</span>.</p><p>A <span class="type">ClutterPathConstraint</span> constrains an
actor's <code class="varname">x</code> and <code class="varname">y</code> properties
to a position along such a <span class="type">ClutterPath</span>: a path through
2D space. The <span class="type">ClutterPath</span> itself is composed of nodes
(x,y positions in 2D space), connected by straight lines or (cubic)
<a class="ulink" href="http://en.wikipedia.org/wiki/B%C3%A9zier_curve" target="_top">Bézier
curves</a>.</p><div class="note" style="margin-left: 0.5in; margin-right: 0.5in;"><h3 class="title">Note</h3><p><span class="type">ClutterPath</span> doesn't have to be used in animations:
it can also be used in drawing (see the
<a class="link" href="actors-non-rectangular.html" title="6. Creating an actor with a non-rectangular shape">non-rectangular actor
recipe</a>).</p></div><p>The actor's position along the path is determined by the constraint's
<code class="varname">offset</code> property, which has a
value between 0.0 and 1.0. When the offset is 0.0, the actor
is at the beginning of the path; when the actor is at 1.0, the
actor is at the end of the path. Between 0.0 and 1.0, the actor
is some fraction of the way along the path.</p><p>If you immediately set the <code class="varname">offset</code> for the
constraint (e.g. to <code class="code">0.5</code>), the actor is instantly placed
at that position along the path: for <code class="code">offset = 0.5</code>,
at the halfway point.</p><p>By contrast, to animate an actor along a path, you
<span class="emphasis"><em>animate</em></span> the offset property of a
<span class="type">ClutterPathConstraint</span>. The actor's position
along the path is dependent on the progress of the animation:
when the animation starts, the actor is at the beginning of the path;
by the end of the animation, it will have reached its end.</p><p>If you animate the constraint using a linear easing mode,
the progress of the animation matches progress along the path: at
half-way through the animation, the actor will be half-way along
the path.</p><p>However, if you are using a non-linear easing mode
(e.g. a quintic or cubic mode), the offset along the path and
progress through the animation may differ. This is because the
offset along the path is computed from the alpha value at that
point in the animation; this in turn depends on the alpha function
applied by the animation. (See the
<a class="link" href="animations.html#animations-introduction" title="1. Introduction">animations introduction</a>
for more details about alphas.)</p><p>One way to think about this is to imagine the actor
making a journey along the path. The alpha function governs the
actor's speed, including how it speeds up and slows down
during its journey. The actor's speed may be constant
(as in a linear easing mode). Alternatively, the actor's speed
may not be constant: it might start out fast then slow down
(ease out); or start slow and speed up (ease in); or start and
end fast, but slow down in the middle (ease in and ease out); or
some other more complex arrangement (as in the bounce and elastic
easing modes). So where the actor is on the path at a particular
time doesn't directly relate to how long it's been travelling:
the position is determined both by how long it's been travelling,
and changes in its speed throughout the journey.</p><div class="section"><div class="titlepage"><div><div><h4 class="title"><a name="idp62585504"></a>10.3.1. Other ways to animate along a path</h4></div></div></div><p><span class="type">ClutterPathConstraint</span> is the only
decent way of animating along curves in a predictable
and manageable fashion. It can also be used to animate along
paths composed of straight lines, though this isn't essential: you
can do straight line animations directly with <span class="type">ClutterAnimator</span>,
<span class="type">ClutterState</span> or implicit animations. But if
you need to animate between more than a half a dozen sets of
points joined by straight lines, <span class="type">ClutterPathConstraint</span>
makes sense then too.</p><p>It is also possible to animate actors over very simple, non-Bézier
curves without using <span class="type">ClutterPathConstraint</span>. This
can be done by animating the actor's position properties using
a non-linear easing mode (see the <span class="type">ClutterAlpha</span>
documentation for available modes, or write your own custom
alpha function). <a class="link" href="animations-path.html#animations-path-example-3" title="Example 5.18. Animating actors on curved paths using easing modes">This
example</a> shows how to animate two actors on
curved paths around each other without
<span class="type">ClutterPathConstraint</span>.</p><p>However, it is difficult to precisely calculate paths
with this approach. It is also only practical where you have a
very simple curve: if you want to chain together several curved
motions (as in the <a class="link" href="animations-path.html#animations-path-example-2" title="Example 5.17. Using a ClutterPathConstraint with ClutterAnimator to animate an actor on a simulated circular path">circle
example</a>), this quickly becomes unwieldy.</p><div class="tip" style="margin-left: 0.5in; margin-right: 0.5in;"><h3 class="title">Tip</h3><p>
If you want physics-based animation, look at
<a class="ulink" href="http://git.clutter-project.org/clutter-box2d/" target="_top">clutter-box2d</a>.
</p></div></div></div><div class="section"><div class="titlepage"><div><div><h3 class="title"><a name="animations-path-examples"></a>10.4. Full examples</h3></div></div></div><div class="example"><a name="animations-path-example-1"></a><p class="title"><b>Example 5.16. Using a <span class="type">ClutterPathConstraint</span> with
implicit animations to move an actor along a curved path</b></p><div class="example-contents"><pre class="programlisting">#include <stdlib.h>
#include <clutter/clutter.h>
int
main (int argc,
char *argv[])
{
ClutterActor *stage;
ClutterPath *path;
ClutterConstraint *constraint;
ClutterActor *rectangle;
ClutterTimeline *timeline;
const ClutterColor *stage_color = clutter_color_new (51, 51, 85, 255);
const ClutterColor *red_color = clutter_color_new (255, 0, 0, 255);
if (clutter_init (&argc, &argv) != CLUTTER_INIT_SUCCESS)
return 1;
stage = clutter_stage_new ();
clutter_actor_set_size (stage, 360, 300);
clutter_stage_set_color (CLUTTER_STAGE (stage), stage_color);
g_signal_connect (stage, "destroy", G_CALLBACK (clutter_main_quit), NULL);
/* create the path */
path = clutter_path_new ();
clutter_path_add_move_to (path, 30, 60);
/* add a curve round to the top-right of the stage */
clutter_path_add_rel_curve_to (path,
120, 180,
180, 120,
240, 0);
/* create a constraint based on the path */
constraint = clutter_path_constraint_new (path, 0.0);
/* put a rectangle at the start of the path */
rectangle = clutter_rectangle_new_with_color (red_color);
clutter_actor_set_size (rectangle, 60, 60);
/* add the constraint to the rectangle */
clutter_actor_add_constraint_with_name (rectangle, "path", constraint);
/* add the rectangle to the stage */
clutter_container_add_actor (CLUTTER_CONTAINER (stage), rectangle);
/* set up the timeline */
timeline = clutter_timeline_new (1000);
clutter_timeline_set_repeat_count (timeline, -1);
clutter_timeline_set_auto_reverse (timeline, TRUE);
clutter_actor_animate_with_timeline (rectangle, CLUTTER_LINEAR, timeline,
"@constraints.path.offset", 1.0,
NULL);
clutter_actor_show (stage);
clutter_main ();
return EXIT_SUCCESS;
}
</pre></div></div><br class="example-break"><div class="example"><a name="animations-path-example-2"></a><p class="title"><b>Example 5.17. Using a <span class="type">ClutterPathConstraint</span> with
<span class="type">ClutterAnimator</span> to animate an actor on
a simulated circular path</b></p><div class="example-contents"><pre class="programlisting">#include <stdlib.h>
#include <clutter/clutter.h>
#define STAGE_SIDE 400.0
static const ClutterColor stage_color = { 0x33, 0x33, 0x55, 0xff };
static const ClutterColor red_color = { 0xff, 0x00, 0x00, 0xff };
/* Build a "circular" path out of 4 Bezier curves
*
* code modified from
* http://git.clutter-project.org/dax/tree/dax/dax-traverser-clutter.c#n328
*
* see http://www.whizkidtech.redprince.net/bezier/circle/
* for further explanation
*/
static ClutterPath *
build_circular_path (gfloat cx,
gfloat cy,
gfloat r)
{
ClutterPath *path;
static gfloat kappa = 4 * (G_SQRT2 - 1) / 3;
path = clutter_path_new ();
clutter_path_add_move_to (path, cx + r, cy);
clutter_path_add_curve_to (path,
cx + r, cy + r * kappa,
cx + r * kappa, cy + r,
cx, cy + r);
clutter_path_add_curve_to (path,
cx - r * kappa, cy + r,
cx - r, cy + r * kappa,
cx - r, cy);
clutter_path_add_curve_to (path,
cx - r, cy - r * kappa,
cx - r * kappa, cy - r,
cx, cy - r);
clutter_path_add_curve_to (path,
cx + r * kappa, cy - r,
cx + r, cy - r * kappa,
cx + r, cy);
clutter_path_add_close (path);
return path;
}
static gboolean
key_pressed_cb (ClutterActor *actor,
ClutterEvent *event,
gpointer user_data)
{
ClutterTimeline *timeline = CLUTTER_TIMELINE (user_data);
if (!clutter_timeline_is_playing (timeline))
clutter_timeline_start (timeline);
return TRUE;
}
int
main (int argc,
char *argv[])
{
ClutterPath *path;
ClutterConstraint *constraint;
ClutterAnimator *animator;
ClutterTimeline *timeline;
ClutterActor *stage;
ClutterActor *rectangle;
if (clutter_init (&argc, &argv) != CLUTTER_INIT_SUCCESS)
return 1;
stage = clutter_stage_new ();
clutter_actor_set_size (stage, STAGE_SIDE, STAGE_SIDE);
clutter_stage_set_color (CLUTTER_STAGE (stage), &stage_color);
g_signal_connect (stage, "destroy", G_CALLBACK (clutter_main_quit), NULL);
rectangle = clutter_rectangle_new_with_color (&red_color);
clutter_actor_set_size (rectangle, STAGE_SIDE / 8, STAGE_SIDE / 8);
clutter_actor_set_position (rectangle,
STAGE_SIDE / 2,
STAGE_SIDE / 2);
clutter_container_add_actor (CLUTTER_CONTAINER (stage),
rectangle);
/* set up a path and make a constraint with it */
path = build_circular_path (STAGE_SIDE / 2,
STAGE_SIDE / 2,
STAGE_SIDE / 4);
constraint = clutter_path_constraint_new (path, 0.0);
/* apply the constraint to the rectangle; note that there
* is no need to name the constraint, as we will be animating
* the constraint's offset property directly using ClutterAnimator
*/
clutter_actor_add_constraint (rectangle, constraint);
/* animation to animate the path offset */
animator = clutter_animator_new ();
clutter_animator_set_duration (animator, 5000);
/* use ClutterAnimator to animate the constraint directly */
clutter_animator_set (animator,
constraint, "offset", CLUTTER_LINEAR, 0.0, 0.0,
constraint, "offset", CLUTTER_LINEAR, 1.0, 1.0,
NULL);
timeline = clutter_animator_get_timeline (animator);
clutter_timeline_set_repeat_count (timeline, -1);
clutter_timeline_set_auto_reverse (timeline, TRUE);
g_signal_connect (stage,
"key-press-event",
G_CALLBACK (key_pressed_cb),
timeline);
clutter_actor_show (stage);
clutter_main ();
/* clean up */
g_object_unref (animator);
return EXIT_SUCCESS;
}
</pre></div></div><br class="example-break"><div class="example"><a name="animations-path-example-3"></a><p class="title"><b>Example 5.18. Animating actors on curved paths using easing modes</b></p><div class="example-contents"><pre class="programlisting">#include <stdlib.h>
#include <clutter/clutter.h>
typedef struct {
ClutterActor *red;
ClutterActor *green;
ClutterTimeline *timeline;
} State;
static const ClutterColor stage_color = { 0x33, 0x33, 0x55, 0xff };
static const ClutterColor red_color = { 0xff, 0x00, 0x00, 0xff };
static const ClutterColor green_color = { 0x00, 0xff, 0x00, 0xff };
static void
reverse_timeline (ClutterTimeline *timeline)
{
ClutterTimelineDirection dir = clutter_timeline_get_direction (timeline);
if (dir == CLUTTER_TIMELINE_FORWARD)
dir = CLUTTER_TIMELINE_BACKWARD;
else
dir = CLUTTER_TIMELINE_FORWARD;
clutter_timeline_set_direction (timeline, dir);
}
/* a key press either starts the timeline or reverses it */
static gboolean
key_pressed_cb (ClutterActor *actor,
ClutterEvent *event,
gpointer user_data)
{
State *state = (State *) user_data;
if (clutter_timeline_is_playing (state->timeline))
reverse_timeline (state->timeline);
else
clutter_timeline_start (state->timeline);
return TRUE;
}
int
main (int argc,
char *argv[])
{
State *state = g_new0 (State, 1);
ClutterActor *stage;
ClutterAnimator *animator;
if (clutter_init (&argc, &argv) != CLUTTER_INIT_SUCCESS)
return 1;
stage = clutter_stage_new ();
clutter_actor_set_size (stage, 400, 400);
clutter_stage_set_color (CLUTTER_STAGE (stage), &stage_color);
g_signal_connect (stage, "destroy", G_CALLBACK (clutter_main_quit), NULL);
state->red = clutter_rectangle_new_with_color (&red_color);
clutter_actor_set_size (state->red, 100, 100);
clutter_actor_set_position (state->red, 300, 300);
state->green = clutter_rectangle_new_with_color (&green_color);
clutter_actor_set_size (state->green, 100, 100);
clutter_actor_set_position (state->green, 0, 0);
animator = clutter_animator_new ();
clutter_animator_set_duration (animator, 1000);
clutter_animator_set (animator,
state->red, "x", CLUTTER_LINEAR, 0.0, 300.0,
state->red, "y", CLUTTER_LINEAR, 0.0, 300.0,
state->red, "x", CLUTTER_LINEAR, 1.0, 0.0,
state->red, "y", CLUTTER_EASE_IN_QUINT, 1.0, 0.0,
NULL);
clutter_animator_set (animator,
state->green, "x", CLUTTER_LINEAR, 0.0, 0.0,
state->green, "y", CLUTTER_LINEAR, 0.0, 0.0,
state->green, "x", CLUTTER_LINEAR, 1.0, 300.0,
state->green, "y", CLUTTER_EASE_IN_QUINT, 1.0, 300.0,
NULL);
state->timeline = clutter_animator_get_timeline (animator);
clutter_timeline_set_auto_reverse (state->timeline, TRUE);
g_signal_connect (stage,
"key-press-event",
G_CALLBACK (key_pressed_cb),
state);
clutter_container_add (CLUTTER_CONTAINER (stage), state->red, state->green, NULL);
clutter_actor_show (stage);
clutter_main ();
g_object_unref (animator);
g_free (state);
return EXIT_SUCCESS;
}
</pre></div></div><br class="example-break"></div></div><div class="navfooter"><hr><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="animations-scaling.html">Prev</a> </td><td width="20%" align="center"><a accesskey="u" href="animations.html">Up</a></td><td width="40%" align="right"> <a accesskey="n" href="text.html">Next</a></td></tr><tr><td width="40%" align="left" valign="top">9. Animated scaling </td><td width="20%" align="center"><a accesskey="h" href="index.html">Home</a></td><td width="40%" align="right" valign="top"> Chapter 6. Text</td></tr></table></div></body></html>
|