The Allegro Wiki is migrating to github at

Ibito's animated sprite class

From Allegro Wiki
Jump to: navigation, search

This is an animated sprite class, you need TinyXML for this to work.

First, we need a tiny .h file

datatypes.h <highlightSyntax language="c">

  1. ifndef _IAPP_DATATYPES_H
  2. define _IAPP_DATATYPES_H
  1. pragma once

namespace IApp { struct position { float x; float y; };


  1. endif


Then, we have the sprite.h file sprite.h <highlightSyntax language="c">

  1. ifndef _IAPP_SPRITE_H
  2. define _IAPP_SPRITE_H
  1. pragma once
  2. include <allegro5/allegro.h>
  3. include <allegro5/allegro_image.h>
  4. include <vector>
  5. include <map>
  6. include <string>
  7. include <utility>
  8. include "datatypes.h"
  9. include "tinyxml.h"

namespace IApp { typedef std::multimap<std::string, std::pair<ALLEGRO_BITMAP*, int> >::iterator c_it; class sprite { private:

int total_frames; std::string current_animation;

std::vector<int> frame_duration; std::vector<ALLEGRO_BITMAP*> frame;

std::multimap<std::string, std::pair<ALLEGRO_BITMAP*, int> > animations; std::multimap<std::string, std::pair<ALLEGRO_BITMAP*, int> >::iterator current_frame;

std::pair<c_it, c_it> animation_range;

bool last_frame; double current_frame_time;

public: position pos;

sprite(void); sprite(std::string filename); ~sprite(void); void draw(); void load(std::string animation_xml_file_to_load); void update(); void set_animation(std::string animation); std::string get_animation();

}; }

  1. endif


And the sprite.cpp file sprite.cpp <highlightSyntax language="c">

  1. include "sprite.h"

namespace IApp { sprite::sprite(void) {


sprite::sprite(std::string filename) { this->load(filename); }

sprite::~sprite(void) { for(std::multimap<std::string, std::pair<ALLEGRO_BITMAP*, int> >::iterator animations_to_destroy = this->animations.begin();animations_to_destroy != this->animations.end(); animations_to_destroy++) { al_destroy_bitmap(animations_to_destroy->second.first); } }

void sprite::draw() { // simply draw our current frame. al_draw_bitmap(this->current_frame->second.first, this->pos.x, this->pos.y, NULL); }

void sprite::load(std::string animation_xml_file_to_load) { this->last_frame = false; // let's see which sequence is our first bool first_read = true; // just a string to store temprary an animation name std::string animation_name;

TiXmlDocument doc(animation_xml_file_to_load.c_str()); // check if XML file loaded ok bool is_xml_loaded = doc.LoadFile(); if(!is_xml_loaded) return; // not loaded, bye

// find our root node (<document>) TiXmlNode *root_node = doc.FirstChild("document"); if(root_node != NULL) { // iterate trough <sequence>'s nodes TiXmlNode *sequence_node = root_node->FirstChild("sequence"); while(sequence_node != NULL) { animation_name = sequence_node->ToElement()->Attribute("name");

// is this our first sequence read? if(first_read) { this->current_animation = animation_name;

// first sequence no more first_read = false; }

// making a tinyxml node for node read. TiXmlNode *frame_node = sequence_node->FirstChild("frame");

// now iterate trough <frame> nodes while(frame_node != NULL) {

					//this->animations.insert(std::pair<std::string, ALLEGRO_BITMAP*>(animation_name, al_load_bitmap(frame_node->ToElement()->Attribute("name"))));

// a cleaner way (to me) for insert stuff to a multimap =) this->animations.insert(std::make_pair(animation_name, std::make_pair(al_load_bitmap(frame_node->ToElement()->Attribute("name")), atoi(frame_node->ToElement()->Attribute("duration")))));

frame_node = sequence_node->IterateChildren("frame", frame_node); } sequence_node = root_node->IterateChildren("sequence", sequence_node); } }

// set the range of frames to our first sequence we read in this xml file this->animation_range = this->animations.equal_range(this->current_animation);

// let's put our current frame to the first frame in our range this->current_frame = this->animation_range.first;

// this->current_frame_time = al_current_time(); }

void sprite::update() { // check if the current time is greater than the current frame time // this way we know if it's time to change to the next frame if(al_current_time() >= this->current_frame_time) { // set current frame time equal to the current time + current frame / 1000 so we can // trait our duration unit like milliseconds. this->current_frame_time = (al_current_time()) + ((double)this->current_frame->second.second / 1000);

// get our next frame this->current_frame++;

// check if we need to return to the first frame again. if(this->current_frame == this->animation_range.second) { this->current_frame = this->animation_range.first;




void sprite::set_animation(std::string animation) { this->current_animation = animation; this->animation_range = this->animations.equal_range(this->current_animation); this->current_frame = this->animation_range.first; this->current_frame_time = (al_current_time()) + ((double)this->current_frame->second.second / 1000); }

std::string sprite::get_animation() { return this->current_animation; } } </highlightSyntax>

An example how a XML animation file should be:

dragon.xml <highlightSyntax language="xml"> <?xml version="1.0" encoding="UTF-8"?> <document> <sequence name="idle"> <frame name="dragon/DRAGON01.png" duration="100"></frame> <frame name="dragon/DRAGON02.png" duration="100"></frame> <frame name="dragon/DRAGON03.png" duration="100"></frame> <frame name="dragon/DRAGON04.png" duration="100"></frame> <frame name="dragon/DRAGON05.png" duration="100"></frame> <frame name="dragon/DRAGON06.png" duration="100"></frame> <frame name="dragon/DRAGON07.png" duration="100"></frame> <frame name="dragon/DRAGON08.png" duration="100"></frame> <frame name="dragon/DRAGON09.png" duration="100"></frame> <frame name="dragon/DRAGON10.png" duration="100"></frame> <frame name="dragon/DRAGON11.png" duration="100"></frame> <frame name="dragon/DRAGON12.png" duration="100"></frame> <frame name="dragon/DRAGON13.png" duration="100"></frame> <frame name="dragon/DRAGON14.png" duration="100"></frame> <frame name="dragon/DRAGON15.png" duration="100"></frame> <frame name="dragon/DRAGON16.png" duration="100"></frame> <frame name="dragon/DRAGON17.png" duration="100"></frame> <frame name="dragon/DRAGON18.png" duration="100"></frame> <frame name="dragon/DRAGON19.png" duration="100"></frame> <frame name="dragon/DRAGON20.png" duration="100"></frame> <frame name="dragon/DRAGON21.png" duration="100"></frame> <frame name="dragon/DRAGON22.png" duration="100"></frame> <frame name="dragon/DRAGON23.png" duration="100"></frame> <frame name="dragon/DRAGON24.png" duration="100"></frame> <frame name="dragon/DRAGON25.png" duration="100"></frame> </sequence> </document> </highlightSyntax>