Behaviours

With a large application containing many animations, the use of just timelines can become unweldy and difficult to manage with much code duplication in the new-frame handlers that can require over complex code changes for minor animation modifications. To ease these problems the #ClutterAlpha and #ClutterBehaviour classes were created.

#ClutterAlpha and #ClutterBehaviour attempt to generalise the new-frame function by defining common actions or behaviours that can be quickly modified, applied to multiple actors or mixed on a single actor.

A ClutterAlpha is simply a 'function of time' (not pixel alpha!). It is created by referencing a source timeline and a function which produces a value between 0 and %CLUTTER_ALPHA_MAX dependant on the timeline position. Various prebuilt alpha functions are included with Clutter these include

%CLUTTER_ALPHA_RAMP_INC

Increasing ramp function

%CLUTTER_ALPHA_RAMP_DEC

Decreasing ramp function

%CLUTTER_ALPHA_RAMP

Full ramp function

%CLUTTER_ALPHA_SINE_INC

Increasing sine function

%CLUTTER_ALPHA_SINE_DEC

Decreasing sine function

%CLUTTER_ALPHA_SINE_HALF

Half sine function

%CLUTTER_ALPHA_SINE

Full sine function

%CLUTTER_ALPHA_SQUARE

Square waveform ("step") function

%CLUTTER_ALPHA_SMOOTHSTEP_INC

Increasing smooth transition step function

%CLUTTER_ALPHA_SMOOTHSTEP_DEC

Decreasing smooth transition step function

%CLUTTER_ALPHA_EXP_INC

Increasing exponential function

%CLUTTER_ALPHA_EXP_DEC

Decreasing exponential function

A Behaviour is created with a #ClutterAlpha and a set of limits for whatever the behaviour modifys actor wise. The current #ClutterAlpha value is then mapped to a value between these limits and this value set on any applied actors. With the #ClutterAlpha's underlying timeline playing the produced value will change and the behaviour will animate the actor.

A #ClutterBehaviour is effectively 'driven' by a supplied #ClutterAlpha and when then applied to an actor it will modify a visual property or feature of the actor dependant on the Alpha's value. For example a path based behaviour applied to an actor will alter its position along the path dependant on the current alpha value over time. The actual motion will depend on the chosen #ClutterAlphaFunc - a #CLUTTER_ALPHA_RAMP_INC making it to move at constant speed along the path, a #CLUTTER_ALPHA_SINE making it alternate from one end of the path to the other with non constant speed.

Multiple behaviours can of course be applied to an actor as well as a single behaviour being applied to multiple actors. The separation of timelines, alphas and behaviours allows for a single timeline to drive many behaviours each potentially using different alpha functions. Behaviour parameters can also be changed on the fly.

Figure 5. Effects of alpha functions on a path

Effects of alpha functions on a path
The actors position between the path's end points directly correlates to the #ClutterAlpha's current alpha value driving the behaviour. With the #ClutterAlpha's function set to %CLUTTER_ALPHA_RAMP_INC the actor will follow the path at a constant velocity, but when changing to %CLUTTER_ALPHA_SINE_INC the actor initially accelerates before quickly decelerating.


The behaviours included in Clutter are

#ClutterBehaviourBspline

Moves actors along a B-spline path

#ClutterBehaviourDepth

Changes the depth of actors

#ClutterBehaviourEllipse

Moves actors along an ellipsis

#ClutterBehaviourOpacity

Changes the opacity of actors

#ClutterBehaviourPath

Moves actors along a path

#ClutterBehaviourRotate

Rotates actors along an axis

#ClutterBehaviourScale

Changes the scaling factors of actors

Example 10. 

The following example demonstrates an ellipse behaviour in action.

#include <clutter/clutter.h>

int
main (int argc, char *argv[])
{
  ClutterTimeline  *timeline;
  ClutterBehaviour *behave;
  ClutterAlpha     *alpha;
  ClutterActor     *stage, *actor;
  GdkPixbuf        *pixbuf;

  clutter_init (&argc, &argv);

  stage = clutter_stage_get_default ();

  pixbuf = gdk_pixbuf_new_from_file ("ohpowers.png", NULL);

  actor  = clutter_texture_new_from_pixbuf (pixbuf);

  clutter_container_add_actor (CLUTTER_CONTAINER (stage), actor);

  timeline = clutter_timeline_new_for_duration (4000); /* milliseconds */
  clutter_timeline_set_loop (timeline, TRUE);

  /* Set an alpha func to power the behaviour */
  alpha = clutter_alpha_new_full (timeline,
                                  CLUTTER_ALPHA_SINE,
                                  NULL, NULL);

  behave = clutter_behaviour_ellipse_new (alpha, 
					  200,               /* center x */
					  200,               /* center y */
					  400,               /* width */
					  300,               /* height */
					  CLUTTER_ROTATE_CW, /* direction */
					  0.0,               /* initial angle */
					  360.0);            /* final angle */

  clutter_behaviour_apply (behave, actor);

  clutter_actor_show_all (stage);

  clutter_timeline_start (timeline);

  clutter_main();

  /* clean up */
  g_object_unref (behave);
  g_object_unref (timeline);

  return 0;
}

  

Note

Behaviour parameters can be changed whilst a animation is running

There can be many #ClutterAlpha's attached to a single timeline. There can be many behaviours for a #ClutterAlpha. There can be many behaviours applied to an actor. A #ClutterScore can be used to chain many behaviour together.

Warning

Combining behaviours that effect the same actor properties (i.e two separate paths) will cause unexpected results. The values will not be merged in any way with essentially a the last applied behaviour taking precedence.

Tips for implementing a new behaviour can be found here.