Animation Library

XML File

The Animation library serves two purposes, firstly it is a repository for graphics and animations (allowing sheet/tiled graphics, support for memory, system and video bitmaps) and secondly an animation playback library to perform various actions on your bitmaps (such as animate to a set time/framerate, fade, use countdown timers, etc). The animations and graphics are fully described in the XML (file or string). The code in the examples (main.cpp file) simply applies different actions to the animations and graphics. The sample XML files contain full documentation for the XML file elements and attributes and are described below as well.

This is the core of an animation file:

<?xml version="1.0" encoding="UTF-8"?> <animations> <global /> <graphic /> <animation /> <animation> <animationitem /> <animationitem /> </animation> </animations>

There is one 'animations' block that contains zero or one global section and a number of graphic/animation elements. Each 'graphic' describes one bitmap only. It can be simply a static graphic you wish to use in your game or if you are using sheet/tiled graphics it can be a sheet/tiled master file, or it can even be a child element within a sheet/tiled master file.

Each 'animation' element describes a series of bitmaps that you use as an animation. Each item is contained within a 'animationitem' element.

For each element there are a number of attributes that can be set (e.g. the name of the file to load, the number of milliseconds to show each frame for). Not every graphic/animation/animationitem has to contain every element. If none are set then the missing attributes take their value from it's parent. 'animationitems' take defaults from 'animation', 'animation' and 'graphic' take from 'global', and 'global' uses hard-coded defaults. For example the attribute 'bmp_type' determines whether you want to load the bitmap as a memory, system or video bitmap. If it isn't set in an 'animationitem' the value is taken from 'animation', if 'animation' does not contain the attribute then 'global' is checked, and if 'global' does not contain anything then the default is used (which happens to be memory bitmap).

animationitems->animation->global->hard coded.

graphic->global->hard coded.

Not all attributes are valid for all elements, for example the attribute 'bmp_file' is the name of the bitmap file to load. It makes no sense for it to appear in either the 'global' or 'animation' element, but it can appear in 'graphic' or 'aninationitem' elements. Also some values are mandatory and omission will result in an error (e.g. bmp_file is one such mandatory item.

Elements and Attributes

Full details appear below for all attributes, however a short and concise version is contained in the animation.xml file that is in the tests\animation directory. It's probably best to open up the animations.xml file and map the table below to what you see:

Attributeglobalgraphicanimationanimationitemdefaultdetails
idYYthe filename The name of the animation. Must be unique
bmp_fileYYerror if omitted The name of the bmp file/master bitmap file referenced
bmp_typeYYYY1 (memory) How bitmap is created 1 for memory, 2 for system and 3 for video
depthYYY32 Colour depth of image. 8,15,16,24,32
ppmaskYYY0 Setting to 1 will create a PPCOL mask for the graphic.
millisecondwaitYYY0 The time in milliseconds to show this or 0 for no pause
framewaitYYY0 Similar to millisecondwait but in frames
loopYYonce Dictates what happens after the last animation frame has been shown:
once : animation stops after the last one
start : animation repeats from start
reverserepeat : animation reverses direction
reverseonce : reverses to start then stops
reverseback : reverses to start, goes forward then stops
automodeYY1 If set to off (0) then the animation will only change when you tell it.
Default: 1

Sheet/Tiled Image attributes
Attributeglobalgraphicanimationanimationitemdefaultdetails
isasheetgraphicYYYY0 This graphic is a sheet (tiled) item, i.e. it is a sub-section of a larger graphic.
sheetgridYY0 Sheet items have a 1 pixel border
sheetitemwidthYYYY64 The width/height in pixels of the graphic.
sheetitemheightYYYY64 The width/height in pixels of the graphic.
originxYYY0 The location within the bitmap where this animation/graphic starts.
originyYYY0 The location within the bitmap where this animation/graphic starts.
tilexYY-1 -1 to use absolute pixel postions (originx/originy)
0 or more the grid location (multiples of sheetitemwidth/height) within the master bitmap
tileyYY-1As tilex for the y co-ordinate
sequencecountY0 If the graphics in the animation simply go from tilex=0 for a number of sequential tiles then instead of using the animationitem elements, simply set this value to the number of animationitems and the system will do the rest (0 means not being used, with a maximum of 100 - to avoid daft errors). It will not read any animation item elements. For example if you set this to be 4, then from originx/originy it will get tiles for tilex=0,1,2,3 all with size sheetitemwidth/height. This attribute overrides isasheetgraphic, tilex and tiley.

Methods

There are two main classes to use, AnimationLibrary and Animation. AnimationLibrary manages the bitmaps and the XML and is used mainly to initialise and load the graphics described in the XML file. The main class used is the Animation class that controls the loaded graphics and animations.
The class 'Animation' actually refers to animations and static graphics. A static graphic is stored internally as a single frame animation, i.e. for static graphics you would create an animation object as normal and can make use of all the functions, like the timers, fade, etc. If you don't need all the bloat associated with an animation object and just wish to retrieve the BITMAP and that is all, see the section below entitled 'Static Graphics'.

AnimationLibrary class

Method/DataDetails
AnimationLibrary(string file, int fps, BitmapType maxbmp,(*bitmapcreator)(string))Constructor. See Usage section below for full details. This constructor initialises the Animation library/repository, loads up all the graphics and creates the animations. file is the XML file or string of XML data to load. FPS is the FPS the Animation system should expect (for timing the animations correctly). maxbmp is the 'best' graphic type to use (memory, system, video). This effectively will override what is set in the XML as the bitmap type to use (see also the 'capbmptype' attribute of the Configurator module). bitmapcreator is a function pointer. By default all graphics references by the XML attribute 'bmp_file' are initially loaded using load_bmp. If you wish to have the system do something else (e.g. apply pre-rendering, load a file in a different system/format), use this. See 'Custom bitmap loader' section below. Defaults to 'animations.xml', 60FPS, video memory is the maximum (i.e. no maximum) and NULL (no function pointer). To avoid the graphics being loaded, simply pass in "" as the XML and ignore the error, then call LoadAnimations()
LoadErrorSet to true if an error occurred during the constructor or loading of animations. Useful if the configuration class is not being used (therefore no access to the GlobalErrorString)
GetAnimation(string)Retrieve an animation. See code examples for why you would need this rather than using an Animation object
GetFirstGraphic(string)returns a BITMAP (or null) of the first (or usually only) item in the repository called 'string'. See 'static graphics' section below
DestroyAll()remove everything and clean up. Normally you DO NOT call this as deleting the AnimationLibrary object you create automatically calls this
LogEntry()lets you write stuff to a log file. See code for examples. this is a static
DebugData()dump the entire repository structure to a file. done automatically
fpsthe fps the system is using. only modify if not set via the xml or constructors for some reason. Note, if the AXL Framework is being used then it's FPS will override this value if different. This is because the AXL Framework runs a game timer loop set by it's FPS.
SetGlobalErrorString()set the current error for use somewhere or other
GetGlobalErrorString()get the current error for use somewhere or other
StoredBitmapsmap<string, BITMAP*> of all the graphics used in the system (but not subbitmaps)
LoadAnimations()load and populate the repository from an XML file. This is not normally required as the constructor above automatically calls this method. see next section

Animation class

Method/DataDetails
Animation(AnimationLibrary* l, string name)
Animation(AnimationLibrary* l, AnimationLibraryFrames* f)
Create an animation object. Get it via a name or a pre-initialised object (see next section).
NextMove() This performs all the calculations for the animation and should be called every frame.
Pause() Stops the current animation, freezing the time and image
Resume() Continues from a Pause() call
Reset() This will reset the animation to the beginning and all values to the defaults set in the animation library
FadeOut(int milliseconds, bool alterbmp=true, int colour=0, int startinglevel=-1)Fades the sprite to 'colour' (black if omitted) in 'milliseconds' in 256 steps. 'startinglevel' (255 invisible to 0 solid) starts it from another value (-1 from where it last finished). Will make use of FBlend if included for faster fading (see below). If you wish to fade the sprite to transparent rather than a colour, set 'alterbmp' to false and fade will only update it's current level in the range 0-255 and not modify the bitmap.
FadeIn(int milliseconds, bool alterbmp=true, int colour=0, int startinglevel=-1)Opposite of FadeOut, going from 0 to 255
ReadOnly_CurrentItemVariable. The BITMAP pointer to the current graphic. You usually grab this after creating an animation, after calling NextMove or Fade step.
GetAutoMode() Whether automode has been set. True means you should simply call NextMove() to progress the animation. False means it is being manually stepped and ManualTimerUpdate() should be called every frame instead and NextMove() should be called when the next frame should be shown.
ManualTimerUpdate()When using single stepping you still need the timers (Fade/countdown - see below) to function correctly. Call this function everyframe if in manual step mode. See code examples below for more details.
SetNewAnimation (string id)Changes the current animation to a new one and resets all attributes to their innitial state. See usage below.
SetNewAnimation (AnimationLibraryFrames*) This is the same as the string variant above but takes in a raw animation pointer (kind of equivalent to the animation object but for the library). This is useful for when speed is of the essence as no lookups are required - the string version has to search it's list of animations to find the correct one. You would usually call this before the game starts:

AnimationLibraryFrames* Ptr; Ptr=GameLibrary->GetAnimation("ship1");

Returns NULL on failure.
GetStandardDimensions (int* w, int* h); Sets the two passed parameters to the size of the BITMAP (passes back the size of the first image only, i.e. assumes all images in the animation are the same size). Use this to avoid using the BITMAP object.
CheckCollision (int this_x, int this_y, PPCOL_MASK mask, int mask_x, int mask_y); Pixel Perfect Collision detection. This function may be best in your sprite class or abstracted by it, but it is here to show how to do pixel perfect collision. The first two parameters are the x/y co-ordinates of this animation object (i.e. you supply them because they are not stored with the animation, hence why it may be best to move this to your sprite class), mask is the PPCOL_MASK of the other bitmap and the mask_x, mask_y are the co-ordinates of the other bitmap. You do not supply this animations mask because it is already known. Returns true for collision, false for not. example use:
myAnimation->CheckCollision(x,y, otherAnimation->ReadOnly_CurentPPCOLMask, otherx, othery);
Returns 0 if no collision, 1 if bounding box collision only, 2 if pixel perfect collision, -1 if either animation has no PPCOL mask set up.
check_bb_collision_general(x1, y1,w1,h1, x2,y2, w2,h2)
check_bb_collision(mask1, mask2, x1,y1, x2,y2)
If bounding box collision detection is all you need, then these two macros will do the job for you. The first takes in co-ordinates and width/height of two rectangles and returns 0 or 1 for no collision or collision. The second takes two PPCOL_MASK structures instead (it then gets the width/height from these).

Timers and Flags

Method/Data Details
SetCustomCountDown(int timer, int milliseconds)Start a custom countdown timer. Useful for things like keeping a logo on screen, delaying the start of a sprite, setting a time for an animation to end, etc. You are allowed four timers (1,2,3,4). The parameter 'timer' is one of these values and 'milliseconds' is the time taken. When the timer has reached zero a flag is set. Refer to the flags below for more details.

NOTE: the current system is set up to 4, but is actually defined by a constant (MAX_COUNTDOWN_TIMERS) that can be changed to any value.
ReadOnly_EndReached This is set to true when the animation has finished. Obviously this is only set for non-repeating animations. It is just a flag and can be ignored if nothing special is to happen when an animation finishes (animations ended will simply show the last image).
ReadOnly_Timers[x] x Represents 0,1,2,3,4 being the fade timer (0 element) and the four custom timers available to be set with SetCustomCountDown(). When no timer/fade has been set/started the value will be true, when a timer/fade is in progress the value will be false, when the timer/fade has finished the value will be true. i.e. finished is the same as not started.
ReadOnly_TimersCounter[x]Returns the current value of the countdown/fade timer. Use the fade timer in conjunction with FadeIn/Out() to pass the value to you own custom fader (e.g. transparent.)

Less Commonly Used Functions/Data

Method/Data Details
SetNewSpeedMS(int) SetNewSpeedFramecount(int) Will change the animation rate in milliseconds or frames for all frames in this animation.
SetNewLoopType (LoopType) Change the way the animation loops. LoopType can be one of LOOP_START, LOOP_REVERSEREPEAT, LOOP_REVERSEONCE, LOOP_REVERSEBACK, LOOP_ONCE
GetCurrentSpeedMS() GetCurrentSpeedFrameCount()Returns the current animation speed in milliseconds or frames
BitmapType ReadOnly_TypeOfBitmapReturns the type of the bitmap, TYPE_VIDEO, TYPE_SYSTEM, TYPE_MEMORY
PPCOL_MASK* ReadOnly_CurentPPCOLMask For the current bitmap this returns the PPCOL mask for it (if set up to be used in the XML/library). Use the supplied functions (below) or download the whole PPCOL library for implementing pixel perfect collision detection.

Optimisations and Setup

The class mainly used in games in real time will be the Animation class. Within this the method most called and available for optimisation is the NextMove() as it is called every frame and contains the main animation logic. To speed up this functions set up the following definitions at the top of the axl.h header file

Usage

Initialising and Loading

In your source code you need to include the main header file and use the AXL namespace:

#include "axl_animations.h"; using namespace AXL_Projects;

To start using an animation you need to create an animation library object (one global or static scope item should be enough):

AnimationLibrary* GameLibrary; GameLibrary=new AnimationLibrary();

AnimationLibrary actually takes a number of parameters but all have defaults as the defaults take all the values from the XML file. Note, The playback library does not use timers, it relies on your code calling an update function every frame and uses this in conjunction with the FPS parameter to determine when the next frame is to be shown:

AnimationLibrary(string XMLfile, int fps, BitMapType maxbmp)

The defaults are the animation file to load being 'animations.xml', fps=60 and the maximum type of graphic being TYPE_VIDEO (i.e. no maximum as Video is the highest, other choices are TYPE_SYSTEM and TYPE_MEMORY)

During the constructor, the XML file is loaded which creates the library of animation items and sets all the defaults mentioned in the full constructor above. Adding resources to the library in code instead of XML is mentioned later. To check if the animations loaded ok check the LoadError data member:

if(!GameLibrary->LoadError) abort();

The parameter 'XMLfile' does not have to be a filename, it can be the actual XML data as well. See example1 in the animation test directory.
At any time, new animations can be loaded (old ones automatically destroyed) by using the method 'LoadAnimations':

if(!GameLibrary->LoadAnimations()) abort();

LoadAnimations() takes two parameters, that can both be defaulted (as in the code above):

LoadAnimations(string file="animations.xml", bool wipelog=false);

The first is the filename of the data file to load and defaults to animations.xml This can also be actual XML data. The second is to wipe the log file (if used) on loading the XML file. On loading of a library, a log file is produced.

Whenever LoadAnimations() is called any previously loaded bitmaps for the object will be deleted and all memory freed.

NOTE: You must have Allegro initialised first so it can create and open bitmaps and do any converstion of the colour depth correctly.

If you wisht to initialise the AnimationLibrary but not load/set the animations for some reason then pass in "" to the constructor, ignore the LoadError flag then call LoadAnimations()

Running Animations

Once the library is set up, you need to create animation items for playback. The samples do not use any sprite library, they simply create one animation object and draw it. Normally you would have one animation object per sprite:

Animation* myAnimation; myAnimation=new Animation(GameLibrary,"fuel");

The first parameter is the AnimationLibrary object previously created. The second parameter assigns its animation, this is the name given to the animation and is referenced by the ID attribute in the XML file (or the name string you give it if not using XML).

Within your game logic (called every frame) you tell the animation object to update its state:

if(key[KEY_SPACE]) CanMove=true; if(GetAutoMode) myAnimation->NextMove(); else { if(CanMove) TempAnimation->NextMove(); else TempAnimation->ManualTimerUpdate(); }

If in auto mode then a call to NextMove is all that is required. When in maual mode we need to only update the frames when told to but still keep to keep the timers/fade running. So we call NextMove if the SPACE key is pressed or if not we just update the timers (NextMove will call the timer updates itself).

In your drawing code you simply reference the public data variable 'ReadOnly_CurrentItem' to get a BITMAP pointer to the current frame, e.g.

draw_sprite(buffer, myAnimation->ReadOnly_CurrentItem, 100,180);

The current frame is set by the call to NextMove().

If you need to change animations then use myAnimation->SetNewAnimation("item_id"); to change the animation and reset all values to the animation 'item_id' stored in the XML. Obviously this requires a string lookup, so if speed is critical then you can do:

AnimationLibraryFrames* newAnimation; newAnimation=GameLibrary->GetAnimation("item_id"); myAnimation->SetNewAnimation(newAnimation);

That is about it really for simply showing and animation.

Static Graphics

If all you want is to retrieve a static graphic and have no need for any of the animation helper methods/data, then you can access the BITMAP directly without the overhead of creating a new object:

BITMAP* logo=GameLibrary->GetFirstGraphic("logo");

This assumes you have already instantiated an AnimationLibrary object and called it GameLibrary.

Graphics Mode Change

If you change graphics modes (e.g. set_gfx_mode() ), for example from a menu option to allow the user to change resolution, etc, then you should delete all animations and reload. This can be done by simply calling 'delete anim' where anim is your animation library, and re-initialising it. If you are using the Framework, it will try to do it for you if you call the Framework method RestartSystem(). This is because if video or system bitmaps are being used they will/might become invalid and/or corrupted. Memory bitmaps should be ok though any change to colour depth/conversion may affect them.

Custom Bitmap Loader

When graphics are initially loaded they are created using the load_bmp function. After this they are transformed into the correct format (e.g. video, system, memory). If you wish to use another file format, e.g. png, or maybe retrieve the graphic from a different location (e.g. a dat file, a custom file system), or if you wish to apply some kind of transformation (e.g. rotation, lighting, etc) then you can pass in the name of a function you write to the Animation Library constructor. This will receive a std::string as the entry name (which is the XML attribute 'bmp_file') and should return a BITMAP* on exit. Or if it fails, passing back NULL will let the system know that an error occurred. Animation example 4 shows an example of this pointer, but assuming you called the constructor like this:

AnimationLibrary* al=new AnimationLibrary("animations.xml", 60, TYPE_VIDEO, MyBitmapCallback);

And in your code you created MyBitmapCallback as:

BITMAP* MyBitmapCallback(const std::string& filename) { BITMAP* tmp=load_bmp(filename.c_str(),NULL); if(tmp) { BITMAP* newtmp=create_bitmap(tmp->w,tmp->h); clear_to_color(newtmp,makecol(255,0,255)); draw_sprite_v_flip(newtmp,tmp,0,0); destroy_bitmap(tmp); return newtmp; } else return NULL; }

It will simply pass back a flipped version. You could easily change this to interrogate the string name and appy different things, e.g. simply return back a bitmap created using load_bmp for most, but for those ending in ROTATExxx (where xxx is a number), you could rotate the bitmap by xxx degrees. You could then simply pass in the same bitmap for each graphic item and let the code do the work.

NOTE: the callback will only be called for graphics that are actually loaded. i.e. it will not be called for subbitmaps (those with the 'issheetgraphic' set to 1) or those that are duplicates (have the same bmp_file entry). Also note, that you should ALWAYS return back a memory bitmap as the transformation to the correct type will be made by the system.

Examples

These are found in the tests\animation directory (.\example1 and .\example2). VS2005 and Dev-C++ projects have already been created. If not using either of these two IDe's then follow the installation section, i.e. include tinyXML library file (or tinyXML source files), the main.cpp in the example directory and axl_animation.cpp. Additionally, example 2 requires axl_config.cpp, and example three requires axl_config.cpp and axl_framework.cpp

XML as data

Instead of passing in the name of a XML file to the constructor you can specify XML as a string instead. This is useful if you are reading the XML from a source other than a file (e.g. a dat file) or you do not wish the user to modify values. Remember that all attributes need to be quoted. The easiest way to do this is to simply copy the XML data from the sample animations.xml files. For example:

std::string anim="<?xml version=\"1.0\" encoding=\"UTF-8\"?>" "<animations>" " <global " " depth=\"32\"" " bmp_type=\"1\"" " />" " <graphic " " id=\"master\" " " bmp_file=\"sheet.bmp\" " " isasheetgraphic=\"0\" " " />" " <animation id=\"fuel\" " " bmp_file=\"sheet.bmp\" " " originx=\"0\" originy=\"32\" " " sheetitemwidth=\"24\" sheetitemheight=\"24\" " " isasheetgraphic=\"1\" " " sequencecount=\"4\"" " />" "</animations>"; MyAnimLibrary=new AnimationLibrary(anim);

Manual Library

This section deals with writing code to create an animation library rather than using an XML file. It can be safely skipped. Only public data/methods will be described.

The AnimationLibrary object has one or more AnimationLibraryFrames objects
AnimationLibraryFrames has one or more AnimationLibraryFrame objects

AnimationLibrary

This represents your library of animations. It is the object you interact with most when maintaining the library and is what is used in the playback library.

Commonly Used Methods and Data

Method/Data Details
AnimationLibrary() The constructor. Create an animationlibrary first before all else. Refer to the Playback section for details on this method. The destructor will deleted all stored data (i.e. all AnimationLibraryFrames objects)
AddAnimation (AnimationLibraryFrames* anim) The animation library stores a list of all your animations, use this method to add an animation to the list. Refer to animationlibrary frames for more information.
Bool LoadAnimations (string file="animations.xml", bool wipelog=false) This will load up an XML file detailing the animations rather than having to code AddAnimation() calls. Refer to the playback library above for more details.
int fps The fps set for the library. This is how the library knows when to change frames automatically. This is really for read-only purposes and should be set in the constructor.
DebugData (char* file="animationslogdebug.log") If you are using the allegro_core library (refer to introduction) then this will output to the log file all the animations in a nice format.

AnimationLibraryFrames

This represents one unit of animation. It is a series of AnimationLibraryFrame objects, i.e. one AnimationLibraryFrame represents one bitmap/animation frame. AnimationLibraryFrames describes how the animation is synchronised, looped and controlled. This can be equated to the Animation object in the playback library as it represents the same unit of work (a series of frames).

Commonly Used Methods and Data

Method/Data Details
AnimationLibraryFrames(string id)

AnimationLibraryFrames(
string id, LoopType lt=LOOP_INVALID,
int msWait=-1, int fWait=-1,
bool autom=true);
The constructor. Id is how you refer to an animation in code (each animation series is stored in a hash table). Normally the first constructor will do. The parameters are:
  • LoopType: how the animation loops at the end
  • msWait/fWait: default waiting time between frames in milliseconds (ms) or number of frames. MS takes precendence. Default is to use what is set in the AnimationLibrary object.
  • Autom: true to automatic mode (animation is shown as described by the wait/looptype and other methods), manual is single stepping.
  • Refer to the playback library for further details on these parameters.
The destructor will deleted all stored data (i.e. all AnimationLibraryFrame objects)
AddAnimationFrame (AnimationLibraryFrame* ai); The animationlibraryframes stores a list of all your animation items in a list, use this method to add an animation item to the list. Refer to animationlibrary frame object for more information.
String IdThe ID of the animation. This is really for read-only purposes and should be set in the constructor.

AnimationLibraryFrame

This represents a single animation frame. A bitmap if you like, but with additional data.

Commonly Used Methods and Data

Method/Data Details
AnimationLibraryFrame (string file="", int msWait=-1, int fWait=-1); The constructor. Default is to use what is set in the AnimationLibrary object. The first parameter is the name of the bitmap file (in a sub-directory called gfx.
A file will be added to the library once only. This means that loading will occur once and no memory will be wasted with multiple versions of the same file.
The destructor will delete all stored data (i.e. loaded bitmaps)

Summary

As you can see, you create a AnimationLibrary for both playback, manual creation of a library and automated creation of a library via an XML file.

A library is created as follows:

  1. Create a single AnimationLibrary object for your library
  2. Create an AnimationLibraryFrames object for each animation sequence
  3. For each item in the animation create a AnimationLibraryFrame object and add it to the AnimationLibraryFrames object via the AddAnimationFrame method.
  4. When you delete an AnimationLibrary object all AnimationLibraryFrames objects are deleted and memory reclaimed. When an AnimationLibraryFrames object is deleted all the AnimationLibraryFrame objects and bitmaps are deleted and memory reclaimed.