Difference between revisions of "Animation System"

From CEGUI Wiki - Crazy Eddie's GUI System (Open Source)
Jump to: navigation, search
m (moved Animation System Introduction to Animation System: Introduction makes it sound hard (quoting kornerr :D))
(Basic concepts: clarified what affected and source properties mean)
Line 3: Line 3:
  
 
== Basic concepts ==
 
== Basic concepts ==
In UI lots of animations are likely to be shared (for example widget specific animation), so CEGUI splits the animation between definition and instance. You can have one animation definition animating large amount of Windows, having only one animation per window is also fine (one animation with only one instance). Animation definitions aren't tied to window type, the only condition  is that the target must have all affected and source properties.
+
In UI lots of animations are likely to be shared (for example widget specific animation), so CEGUI splits the animation between definition and instance. You can have one animation definition animating large amount of Windows, having only one animation per window is also fine (one animation with only one instance). Animation definitions aren't tied to window type, the only condition  is that the target must have all affected (target properties of all affectors inside the animation) and source properties (all source properties in key frames, if any).
  
 
== Meaning of animation classes ==
 
== Meaning of animation classes ==

Revision as of 11:57, 21 August 2010

Note: Animation System is a new feature, it's currently in the stable svn branch (v0-7). It will most likely be released with CEGUI 0.7.2

Basic concepts

In UI lots of animations are likely to be shared (for example widget specific animation), so CEGUI splits the animation between definition and instance. You can have one animation definition animating large amount of Windows, having only one animation per window is also fine (one animation with only one instance). Animation definitions aren't tied to window type, the only condition is that the target must have all affected (target properties of all affectors inside the animation) and source properties (all source properties in key frames, if any).

Meaning of animation classes

Animation Definition (class CEGUI::Animation)

This class holds defining data for animations. Specifically duration, replay mode, auto start and list of Affectors. This class doesn't directly animate anything. You have to instantiate it via CEGUI::AnimationManager::instantiateAnimation.

Affector (class CEGUI::Affector)

Affector affects (changes the value of) one property. It holds application method (more about that later), target property, used interpolator and list of key frames.

Key Frame (class CEGUI::KeyFrame)

Key frame represents the value of affected property at given time position. It holds value, source property and time position. Key frames can use values of properties of the affected window. If source property is not empty, property is saved when animation starts and used as value for this key frame.

Animation Instance (class CEGUI::AnimationInstance)

This class uses animation definition to animate Window. It holds animation position and playback speed.

Animation Manager (class CEGUI::AnimationManager

Singleton class. You use it to create new animation definitions and instantiate existing animation definitions. (You should not construct Animation definitions or Animation instances directly, always use Animation Manager).

Interpolator (class CEGUI::Interpolator)

To be able to animate smoothly between 2 discrete keyframes, interpolators had to be introduced. You don't have to use the directly, everything is done for you in the animation classes. You only need to understand their internals if you need custom interpolator (as all basic interpolators are included in CEGUI, if you find some property that can't be animated with stock interpolators, let us know).

Defining animations

Via code

This sample animation takes 0.3 seconds and in that time, it fades the window and rotates it 10 degrees around Y axis. <cpp/> {

  CEGUI::Animation* anim = CEGUI::AnimationManager::getSingleton().createAnimation("Testing");
  anim->setDuration(0.3f); // duration in seconds
  anim->setReplayMode(CEGUI::Animation::RM_Once); // when this animation is started, only play it once, then stop
  
  // now we define affector inside our Testing animation
  {
   // this affector changes YRotation and interpolates keyframes with float interpolator
   CEGUI::Affector* affector = anim->createAffector("YRotation", "float");
   // at 0.0 seconds, the animation should set YRotation to 10.0 degrees
   affector->createKeyFrame(0.0f, "0.0");
   // at 0.3 seconds, YRotation should be 0 degrees and animation should progress towards this in an accelerating manner
   affector->createKeyFrame(0.3f, "10.0", CEGUI::KeyFrame::P_QuadraticAccelerating);
  }

  // animation can have more than one affectors! lets define another affector that changes Alpha
  {
   // this affector will again use float interpolator
   CEGUI::Affector* affector = anim->createAffector("Alpha", "float");
   affector->createKeyFrame(0.0f, "1.0"); // at 0.0 seconds, set alpha to 0.5
   affector->createKeyFrame(0.3f, "0.5", CEGUI::KeyFrame::P_QuadraticDecelerating); // at 1.0 seconds, set alpha to 1.0, now decelerating!
  }

}

Via Falagard looknfeel XML

<WidgetLook ...> ...

 <AnimationDefinition name="Testing" duration="0.3" replayMode="once">
   <Affector property="Alpha" interpolator="float">
     <KeyFrame position="0.0" value="1.0" />
     <KeyFrame position="0.3" value="0.5" />
   </Affector>
   <Affector property="YRotation" interpolator="float">
     <KeyFrame position="0.0" value="0" />
     <KeyFrame position="0.3" value="10" />
   </Affector>
 </AnimationDefinition>

</WidgetLook>

Via separate animation list XML (AnimationManager::loadAnimationsFromXML)

<Animations>

 <AnimationDefinition name="Testing" duration="0.3" replayMode="once">
   <Affector property="Alpha" interpolator="float">
     <KeyFrame position="0.0" value="1.0" />
     <KeyFrame position="0.3" value="0.5" />
   </Affector>
   <Affector property="YRotation" interpolator="float">
     <KeyFrame position="0.0" value="0" />
     <KeyFrame position="0.3" value="10" />
   </Affector>
 </AnimationDefinition>

</Animations>

Instantiating animations

If you created the animation in code or via separate animation definition file, you have to instantiate it (only Falagard instantiates and sets target automatically).

<cpp/> CEGUI::AnimationInstance* instance = CEGUI::AnimationManager::getSingleton().instantiateAnimation(anim); // after we instantiate the application, we have to set it's target window instance->setTargetWindow(mRoot);

// at this point, you can start this instance and see the results instance->start();

Connecting events and animations

You often want your animation to start when something happens (Mouse gets over the widget, new FrameWindow is opened, etc). You have two options to achieve this.

If you already are using XML to define animations, the easiest solution is to use the auto event subscription facility. You add pairs of Event name and action that should happen with the animation ("Start", "Stop", "Pause", "Unpause", etc.) and when target window is set, these subscriptions are automatically made for your convenienve.

Both Falagard and Animations.xml approaches are the same with regards to this. This XML snippet starts the animation when mouse enters the target window's area. <AnimationDefinition name="Testing" duration="0.3" replayMode="once">

 ...
 <Subscription event="MouseEntersArea" action="Start" />

</AnimationDefinition>

Doing this in code is much more powerful (you can subscribe to a window that's different than target window) but also more messy: <cpp/> windowWithEvent->subscribeEvent(CEGUI::Window::EventMouseEntersArea, CEGUI::Event::Subscriber(&CEGUI;::AnimationInstance::handleStart, instance));

Progression

As I created the implementation, I noticed that linear animations look really boring and predictable. Often times accelerating or decelerating anims will look much better and lively. To make creating those easier, I introduced progression to key frames. This enum tells the system how to progress towards the key frame that holds the progression (that means progression on the first key frame is never used!). The default is linear, meaning that progress towards the keyframe is completely linear. Try the other options yourself to see the differences.

Application methods

Affectors offer 3 different "application methods". One is absolute, meaning that the keyframe value is taken as absolute and is directly set to the property after interpolation. The other 2 are relative. That means that when the animation starts, the old values of properties are saved and later used when animating. AM_Relative means saved_value + interpolated_value, AM_RelativeMultiply means saved_value * interpolated_float (TODO: We should add some examples of this)