## 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

> 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.