Allegro.cc - Online Community

Allegro.cc Forums » Game Design & Concepts » Looking for animation classes

This thread is locked; no one can reply to it. rss feed Print
Looking for animation classes
Rick
Member #3,572
June 2003
avatar

Anyone here care to share their animation class with me? I've written so many (that I never saved) and I don't want to write another one. I'd love to use someone else's if they would be kind to share with a little doc.

========================================================
Actually I think I'm a tad ugly, but some women disagree, mostly Asians for some reason.

Neil Walker
Member #210
April 2000
avatar

Check out my sig. axl includes an animation library that can be used by itself.

the direct link to the online manual is here:
http://retrospec.sgn.net/users/nwalker/axl/index.html

Neil.
MAME Cabinet Blog / AXL LIBRARY (a games framework) / AXL Documentation and Tutorial

wii:0356-1384-6687-2022, kart:3308-4806-6002. XBOX:chucklepie

Dustin Dettmer
Member #3,935
October 2003
avatar

1#ifndef ANIMATION_H
2#define ANIMATION_H
3 
4#include "datafile.h"
5#include "stopwatch.h"
6#include "bitmap.h"
7#include <vector>
8#include <allegro.h>
9 
10class animation {
11public:
12
13 // path must be ready to use with the specified datafile.
14 // The path will be postfixed with a number starting at 0 and
15 // incremented until no image is found. An example path could
16 // be: CHARACTERS/BRILLY/FIST/LEFT/
17 //
18 // Note the object in the datafile must have an attribute called
19 // TIME which specifies how many milliseconds the frame will display
20 // for. If it is not specified the time defaults to 0
21 animation(const std::string &path, datafile_t* = &datafile);
22 
23 animation();
24 animation(const animation&);
25
26 // Animation is running (started) by default
27 void start();
28 void restart();
29 void unpause();
30 void stop();
31 void pause();
32 void setframe(unsigned int frame);
33
34 // Alais functions representing the same operations
35 bool unpaused();
36 bool paused();
37 bool started();
38 bool stopped();
39
40 // Calculates the current Bitmap and returns it
41 // Returns 0 if there is no frame available.
42 Bitmap *get_bmp();
43
44 // Finds the frame associated with the parameter 'frame'. Frame can be
45 // any value and this function will wrap it to the correct frame number.
46 // Returns 0 if there are no frames available.
47 Bitmap *get_bmp(unsigned int frame);
48
49 // Must be set to point to a variable that holds the milliseconds since
50 // program start
51 static volatile unsigned int *msecs;
52
53private:
54
55 struct Frame {
56
57 int msec_delay;
58 Bitmap bmp;
59
60 Frame(BITMAP *tmp) : bmp(tmp) {}
61 };
62
63 std::vector<Frame> frames;
64
65 unsigned int cur_frame;
66 unsigned int frame_msec_start;
67
68 bool running;
69};
70 
71#endif
72 
73// ....
74 
75#include "animation.h"
76#include "log.h"
77#include <sstream>
78#include <iostream>
79using namespace std;
80 
81volatile unsigned int *animation::msecs = 0;
82 
83animation::animation(const string &path, datafile_t *datafile)
84 : cur_frame(0), running(1)
85{
86 DATAFILE *datf;
87 BITMAP *bmp;
88
89 for(int i = 0; 1; i++) {
90
91 ostringstream os;
92
93 os << path << i;
94
95 bmp = (BITMAP*)datafile->loadfind(os.str(), &datf);
96
97 if(!bmp)
98 break;
99
100 frames.push_back(Frame(bmp));
101
102 frames.back().msec_delay = atoi(get_datafile_property(datf, DAT_ID('T', 'I', 'M', 'E')));
103 }
104
105 if(frames.empty())
106 out << "Unknown anim \"" << path << "\"\n";
107
108 frame_msec_start = *msecs;
109}
110 
111animation::animation()
112 : cur_frame(0), frame_msec_start(*msecs), running(1)
113{
114
115}
116 
117animation::animation(const animation &src)
118 : frames(src.frames), cur_frame(src.cur_frame), frame_msec_start(src.frame_msec_start), running(src.running)
119{
120
121}
122 
123Bitmap *animation::get_bmp()
124{
125 if(frames.empty())
126 return 0;
127
128 unsigned int s = frames.size();
129
130 while(running && frame_msec_start + frames[cur_frame].msec_delay < *msecs) {
131
132 frame_msec_start += frames[cur_frame].msec_delay;
133
134 cur_frame++;
135
136 if(cur_frame >= s)
137 cur_frame = 0;
138
139 if(!frames[cur_frame].msec_delay)
140 break;
141 }
142
143 Bitmap *ret = &frames[cur_frame].bmp;
144
145 if(!ret)
146 err << "Returning 0 for get_bmp()\n";
147
148 return ret;
149}
150 
151Bitmap *animation::get_bmp(unsigned int frame)
152{
153 if(frames.empty())
154 return 0;
155
156 Bitmap *ret = &frames[frame % frames.size()].bmp;
157
158 if(!ret)
159 err << "Returning 0 for get_bmp(" << frame << ")\n";
160
161 return ret;
162}
163 
164void animation::start()
165{
166 running = 1;
167 frame_msec_start = *msecs;
168}
169 
170void animation::setframe(unsigned int frame)
171{
172 running = 0;
173 if (frame>frames.size()-1) frame=frames.size()-1;
174 cur_frame=frame;
175}
176 
177void animation::restart()
178{
179 running = 1;
180 cur_frame = 0;
181 frame_msec_start = *msecs;
182}
183 
184void animation::unpause()
185{
186 running = 1;
187}
188 
189void animation::stop()
190{
191 cur_frame = 0;
192 running = 0;
193}
194 
195void animation::pause()
196{
197 running = 0;
198}
199 
200bool animation::unpaused()
201{
202 return running;
203}
204 
205bool animation::paused()
206{
207 return !running;
208}
209 
210bool animation::started()
211{
212 return running;
213}
214 
215bool animation::stopped()
216{
217 return !running;
218}

Obviously dependant on the datafile, stopwatch, bitmap and log modules of my engine which I haven't included.

Rick
Member #3,572
June 2003
avatar

My question with these is, what happens if I have multiples of the same unit? It would seem I would have duplicates of the images loaded into memory with these classes.

========================================================
Actually I think I'm a tad ugly, but some women disagree, mostly Asians for some reason.

Wilson Saunders
Member #5,872
May 2005
avatar

Rick said:

It would seem I would have duplicates of the images loaded into memory with these classes.

Well with amount of memory in most modern computers storing a new copy of a bitmap for each unit of a RTS probably will not cause much troubles. If you want to be efficient about it remember Allegro deals with (BITMAP *) pointers. That means you can set multiple units bitmap images to point at one bitmap in memory.
For example:

int itor;
BITMAT * GruntStand = LoadBitmap("GruntStand.bmp");
for(itor =0; itor < NUMGRUNTS; itor++){
   Army[itor] = new Grunt;
   Army[itor]->Image = GruntStand;
}

Will only store one copy of the Bitmap GruntStand.bmp in memory but all the Grunt instances will be able to access it as their own class variable.

________________________________________________
Play my games at http://monkeydev.com

Rick
Member #3,572
June 2003
avatar

Yeah I know. The 2 animation classes above store bitmaps and a current frame variable together. That means one of two things.

A) Every like unit animates the same
B) Duplicate copies of the bitmaps per units

I think I'll end up writting my own to handle these issues. Basically the currentFrame should be seperately stored from the bitmaps that make up the animation. That way each unit can have different currentFrame values and just get the image from a manager type class from this units currentFrame.

========================================================
Actually I think I'm a tad ugly, but some women disagree, mostly Asians for some reason.

Dustin Dettmer
Member #3,935
October 2003
avatar

Quote:

My question with these is, what happens if I have multiples of the same unit? It would seem I would have duplicates of the images loaded into memory with these classes.

The animation class has no concept of storing one copy of a bitmap.

The Bitmap class handles that.

Rick
Member #3,572
June 2003
avatar

I see now Dustin, you are using an already loaded datafile.

========================================================
Actually I think I'm a tad ugly, but some women disagree, mostly Asians for some reason.

piccolo
Member #3,163
January 2003
avatar

hey rick check out my game character editor I'm making it to were all animations are reusable
http://www.allegro.cc/depot/Thegame/

wow
-------------------------------
i am who you are not am i

23yrold3yrold
Member #1,134
March 2001
avatar

Posting the animation classes for The Mighty Stupid. It's two main classes; an animation class that holds all the animation data for a given entity, and a tracking class, which references the animation and handles all playback and frame tracking. That way I can have one animation loaded and have 20 different enemies (with 20 different trackers) running off it without wasting memory. :)

Just the interfaces ....

1class CAnimation
2{
3 public:
4 // a sprite with bounding boxes used for collision detection.
5 class CFrame
6 {
7 public:
8 class CBBox
9 {
10 public:
11 // all variables
12 int xpos, ypos, width, height;
13 char state; // for flags, like aggressive, passive, etc.
14 int type;
15 int ID;
16 int damage;
17 
18 // ctor; no dtor needed
19 CBBox(int x = 0, int y = 0, int w = 0, int h = 0, int s = 0): xpos(x), ypos(y), width(w), height(h), state(s){}
20 };
21 
22 // all variables
23 std::vector<CBBox> bboxes;
24 bool hflip;
25 BITMAP *bitmap;
26 int xoff, yoff;
27 long unsigned int keyframe;
28 
29 CFrame(): hflip(0) { }
30 CFrame(BITMAP* b, int x, int y, int k, int f): hflip(f), bitmap(b), xoff(x), yoff(y), keyframe(k) { }
31 
32 // for drawing ....
33 void DrawRects(BITMAP* b, int x, int y);
34 void Draw(BITMAP *b, int x, int y);
35 void DrawLit(BITMAP *b, int x, int y, int trans);
36 void DrawTrans(BITMAP *b, int x, int y, int trans);
37 void DrawTransLit(BITMAP *b, int x, int y, int trans, int color, int fade);
38 };
39 
40 // class that holds one 2D sequence of images and bounding boxes. It's just
41 // one big vector, with a few helper functions. An array wouldn't give any real
42 // speed here, since frames change relatively rarely. Very simple class ...
43 class CObjectAnime
44 {
45 public:
46 std::vector<CFrame> images;
47 int looping;
48 inline int size();
49 inline CFrame& operator[](int index);
50 };
51 
52 typedef std::vector<CFrame::CBBox>::iterator boxiterator;
53 
54 // CAnimation's variables. Just a map, a bitmap array, and the number of bmp's ...
55 std::map<std::string, CObjectAnime> sprites;
56 BITMAP** images;
57 int numimages;
58 
59 // ctors and dtor
60 CAnimation();
61 CAnimation(std::string filename);
62 void ConstructFromDatafile(std::string filename);
63 ~CAnimation();
64 
65 // add a frame of animation. If framename doesn't exist, the sequence is created
66 void AddFrame(std::string framename, int frame, BITMAP* b, int x, int y, int k, int f);
67 inline void Destroy();
68 inline bool IsEmpty();
69 inline bool Find(std::string s);
70};

1class CAnimeTracker
2{
3 private:
4 // all the variables
5 CAnimation* animations;
6 CAnimation::CObjectAnime* curanimation;
7 CAnimation::CFrame* cursprite;
8 int frame; // current frame of current animation
9 float time; // current time in animation
10 float oldtime; // time last update
11 float speed; // speed control
12 bool paused; // is it paused?
13 float delay; // pause delay
14 bool stopped; // is it stopped?
15 std::list<std::string> sequences; // for "programming" an animation sequence
16 
17 public:
18 // ctors and dtor
19 CAnimeTracker(CAnimation& a);
20 CAnimeTracker(CAnimation& a, std::string init);
21 ~CAnimeTracker();
22 
23 // advance animation
24 void Update(int externaltime = 0);
25 
26 // lots of inline junk
27 void ResetTime(); // moved to .cpp; explained there
28 void Delay(int d); // moved to .cpp; explained there
29 void Unpause(); // moved to .cpp; explained there
30 void SetTime(float t); // more than just time = x. moved to .cpp; explained there
31 inline void Pause();
32 inline bool IsPaused();
33 inline bool IsStopped();
34 inline void AdjustSpeed(float s);
35 inline void SetSpeed(float s);
36 inline float GetSpeed();
37 inline float GetTime();
38 
39 inline CAnimation::CFrame* GetCurrentSprite();
40 
41 // for changing, checking and manipulating the sequences
42 bool ChangeSequence(std::string str);
43 void AppendSequence(std::string str);
44 bool InterruptSequence(std::string str);
45 void MakeNextSequence(std::string str);;
46 void SwitchSequence(std::string str);
47 void ResetAnimation() { ResetTime(); }
48 
49 std::string CurrentSequence();
50 
51 // drawing functions
52 void Draw(BITMAP* b, int x, int y);
53 void DrawLit(BITMAP* b, int x, int y, int trans);
54 void DrawTrans(BITMAP* b, int x, int y, int trans);
55 void DrawTransLit(BITMAP* b, int x, int y, int trans, int color, int fade);
56 void DrawRects(BITMAP* b, int x, int y);
57};

Explanations available upon request, but I think it's pretty self explanitory. Implementations are left as an exercise for the reader. :)

--
Software Development == Church Development
Step 1. Build it.
Step 2. Pray.

Dustin Dettmer
Member #3,935
October 2003
avatar

Quote:

I see now Dustin, you are using an already loaded datafile.

Actually the images in the datafile are loaded into textures, which is handled by Bitmap.

Bitmap maintains a lookup table with pointers to items in the datafile as the key and the texture IDs as the value.

If passed a pointer to a bitmap that is already in the lookup table, that texture ID is used, otherwise the upload is performed.

Obviously there is the minute chance that a bitmap could be passed with the same address of an old bitmap that was deallocated, but the work-around for this is speed and memory demanding. And I'm keeping the whole datafile loaded into memory anyway.

piccolo
Member #3,163
January 2003
avatar

23yrold3yrold said:

That way I can have one animation loaded and have 20 different enemies (with 20 different trackers) running off it without wasting memory.

character editor I'm making it to were all animations are reusable:P
same thing i was shooting for

wow
-------------------------------
i am who you are not am i

Go to: