Data Structures for character animation
Hi, basically one of my projects is a 2D tile-based engine which I want to use for both a RTS and a turn-based game. Scrolling, DirectDraw, clipping etc, none of that is a problem.
What I am having trouble with is finding some effective way of storing animation. It seems like most articles on animation are very basic, saying "Animation is done by using a list of different pictures for 1 character" and leaving it up to the programmer to figure out how to implement this. I''ve experimented with several different ways of doing it but I am never satisfied with the result. The RTS book by Mickey Kawick seems to suggest loading in the individual frames for each instance of a character... which would be wasteful if you have 100 orcs and each time you made a new orc you had to load in all the orc textures. I got round this by using a SpriteManager class, where you request a texture by filename and it returns a pointer to the Sprite, only loading it in if it isn''t already there. But it did seem to be a bit of a hack - all orc characters should be able to share a common pool of animations.
Storing the lists of frames is awkward. How are people handling variable game speeds (ie. you can''t consider frames of animation to equal times through the game loop)? A static variable stored with each framelist indicating the current position along the animation? I currently store 8 lists of Frames per Action, and an unspecified number of Actions per CreatureType. Is there a better way? I want to do as little hard-coding as possible (ie. I want to be able to load in frame lists from a file.) as opposed to the ''resource files'' full of #defines that many graphics libraries seem to produce for you.
How are animations linked to in-game actions? Do you trigger the actions from the relevant frame of animation, or time the animation to suit the actions? I was currently thinking of storing an Operation variable with each frame, which would contain an Opcode and Operand to allow very basic scripting actions triggered by the animation.
Do people use separate classes to distinguish between the type of a creature, and an instance of a creature? (For example, call CreatureType::Create() to produce an object of class Creature.)
As you can see, I have some ideas, but I''d really like to know what other people are doing to resolve these issues! Object Oriented viewpoints are of most use to me, but straight C or whatever would be helpful too.
March 24, 2000 06:22 AM
A very good question.
But I don''t really have a good answer.
This kind(s) of problem(s) has been bugging me too
for some time. I''ve tried to use MAIN FUNCTION
lookuptables with the indexes to the correct frames.
But I guess this is a pretty bad idea.
I would much rather see the "animation list" as a part
of the object(CLASS). And should be easy to manipulate
by just calling some methods.
And you really should be able to load animations
from files. And to dynamically allocate the space
for the array. So that you don''t have a fixed size
array which I''ve seen in quite a lot of structures.
If you have any ideas to add something I would really
like to hear. And I too think this is a topic that has''nt
been discussed a lot.
Sorry I know this was''nt really any help
But I don''t really have a good answer.
This kind(s) of problem(s) has been bugging me too
for some time. I''ve tried to use MAIN FUNCTION
lookuptables with the indexes to the correct frames.
But I guess this is a pretty bad idea.
I would much rather see the "animation list" as a part
of the object(CLASS). And should be easy to manipulate
by just calling some methods.
And you really should be able to load animations
from files. And to dynamically allocate the space
for the array. So that you don''t have a fixed size
array which I''ve seen in quite a lot of structures.
If you have any ideas to add something I would really
like to hear. And I too think this is a topic that has''nt
been discussed a lot.
Sorry I know this was''nt really any help
There are several ways to implement what you want.
Your use of a sprite manager is a sound one. It is wasteful to load the same graphics more than once.
The most logical division into which to organize your animation frames is into sequences (walk north, attack north, pick up object, etc)
another logical division would be by direction of action (north, west, whatever)
for example, you might have a warrior character who can move and act in four directions(NSEW), so you''d have move, attack, and defend in each of these directions. you may also have some misc sequences, such as pick up object, drink potion, and probably a death sequence.
animation in games is by its nature very application dependent, since different games will have different requirements, so putting down one exact way is impossible.
my advice is just to group your frames into sequences, and then put the sequences into some sort of logical order based on your need.
Your use of a sprite manager is a sound one. It is wasteful to load the same graphics more than once.
The most logical division into which to organize your animation frames is into sequences (walk north, attack north, pick up object, etc)
another logical division would be by direction of action (north, west, whatever)
for example, you might have a warrior character who can move and act in four directions(NSEW), so you''d have move, attack, and defend in each of these directions. you may also have some misc sequences, such as pick up object, drink potion, and probably a death sequence.
animation in games is by its nature very application dependent, since different games will have different requirements, so putting down one exact way is impossible.
my advice is just to group your frames into sequences, and then put the sequences into some sort of logical order based on your need.
Get off my lawn!
also, if you are using DirectX
the first time that an ORC or whatever is loaded, you can have the unit load in all of graphics onto surfaces, and then when another orc is loaded, it checks to see if an orc is already in memory, so you can use DuplicateSurface to get the same information without loading it more than once. then, when all the orcs are unloaded, the surfaces automatically disappear. (COM reference counting can make sure of this)
the first time that an ORC or whatever is loaded, you can have the unit load in all of graphics onto surfaces, and then when another orc is loaded, it checks to see if an orc is already in memory, so you can use DuplicateSurface to get the same information without loading it more than once. then, when all the orcs are unloaded, the surfaces automatically disappear. (COM reference counting can make sure of this)
Get off my lawn!
Well, the SpriteManager does what I want (ie. allows me to 'load' all the frames of animation for each instance of each character' without unnecessary duplication of resources) but I don't like naively 'attempting' to load in all these graphics on a per-creature-instance basis. Besides, there are other statistics that only need 1 instance for each type of Creature, for instance the maximum hit points.
So I decided that instances of Creature (for example, a single orc or human) would have a pointer to the relevant instance of CreatureType (one for all Orcs, one for all Humans, etc) which contains all the animations for that type of character. Obviously this means that while the graphics only have to be loaded once, it means each individual creature has to have its own iterator into the current frame sequence stored within CreatureType.
Here's a condensed version of how I am doing it currently:
class CreatureType
{
friend class Creature; // To allow access to the Framelist
// All racial characteristics go here (eg. int attack, bool canFly, int maxHitPoints) so that individual creature can copy the values
FrameList animation[NUM_STATES][NUM_DIRS];
void LoadAnims(); // Loads all animations in
};
class Creature
{
// All 'instance' characteristics (eg. int currentHitPoints, ObjectList carried, int xPos, int yPos)
CreatureType* type; // Pointer to the 'archetypical' version of this Creature
int direction; // Which direction we ar facing
int state; // What we are doing
int frameNumber; // How far into the current animation we are
};
So, when I need to draw a creature, I take its current direction and state, grab the relevant FrameList from the archetype, increment frameNumber, and draw that frame. Currently, this will animate faster on faster computers. What would be a good way of passing a high-res timer value to the animations? Storing an extra variable to record fractional parts of a frame's duration?
Is this way of storing Creature instances and Creature Definitions a good one? I could obviously hardcode in the creature types (eg. class Orc : public Creature {}; class Human : public Creature{}; ) and then just use instances of that class to represent instances in the game, and class static variables to define the frames of animation for each type (meaning they are only defined once per type of creature, obviously). But that means a recompile everytime I want to add a new race, which I'd like to avoid if possible, as I'd like the game to be user-extensible. Perhaps I am just trying to put too much flexibility into my engine at this stage...
Does anyone have any source for this sort of thing? Or any comments on what I am doing right/wrong, or how it could be improved? I often hold myself back as I feel I am doing something badly, even if I am not
Edited by - Kylotan on 3/24/00 1:24:45 PM
So I decided that instances of Creature (for example, a single orc or human) would have a pointer to the relevant instance of CreatureType (one for all Orcs, one for all Humans, etc) which contains all the animations for that type of character. Obviously this means that while the graphics only have to be loaded once, it means each individual creature has to have its own iterator into the current frame sequence stored within CreatureType.
Here's a condensed version of how I am doing it currently:
class CreatureType
{
friend class Creature; // To allow access to the Framelist
// All racial characteristics go here (eg. int attack, bool canFly, int maxHitPoints) so that individual creature can copy the values
FrameList animation[NUM_STATES][NUM_DIRS];
void LoadAnims(); // Loads all animations in
};
class Creature
{
// All 'instance' characteristics (eg. int currentHitPoints, ObjectList carried, int xPos, int yPos)
CreatureType* type; // Pointer to the 'archetypical' version of this Creature
int direction; // Which direction we ar facing
int state; // What we are doing
int frameNumber; // How far into the current animation we are
};
So, when I need to draw a creature, I take its current direction and state, grab the relevant FrameList from the archetype, increment frameNumber, and draw that frame. Currently, this will animate faster on faster computers. What would be a good way of passing a high-res timer value to the animations? Storing an extra variable to record fractional parts of a frame's duration?
Is this way of storing Creature instances and Creature Definitions a good one? I could obviously hardcode in the creature types (eg. class Orc : public Creature {}; class Human : public Creature{}; ) and then just use instances of that class to represent instances in the game, and class static variables to define the frames of animation for each type (meaning they are only defined once per type of creature, obviously). But that means a recompile everytime I want to add a new race, which I'd like to avoid if possible, as I'd like the game to be user-extensible. Perhaps I am just trying to put too much flexibility into my engine at this stage...
Does anyone have any source for this sort of thing? Or any comments on what I am doing right/wrong, or how it could be improved? I often hold myself back as I feel I am doing something badly, even if I am not
Edited by - Kylotan on 3/24/00 1:24:45 PM
Since no-one has anything to post on the subject, does anyone have any links to examples of source code I could download? Or is the complexity of animation and associated structures the reason everyone these days writes Yet Another 3D Engine With Lots Of Features But No Game? I get the impression that anyone can read a math book and get the computer to shove a few matrices about, but actual game logic is where the difficulty is.
One other thing: if DuplicateSurface uses the same surface memory (as I see in the SDK docs), and is therefore sharing the surface, why not just copy the LPDIRECTDRAWSURFACE7 pointer? Is it just to keep the reference count valid?
One other thing: if DuplicateSurface uses the same surface memory (as I see in the SDK docs), and is therefore sharing the surface, why not just copy the LPDIRECTDRAWSURFACE7 pointer? Is it just to keep the reference count valid?
March 29, 2000 05:06 PM
Hi Kylotan. Excellent question!
Everybody who wants to write games seems to be talking about how to use DirectX ect., nobody seems to be adressing the fundamental structure of the games (the game logic as you call it).
I''ve never really got started on a game project on my own because of exactly the same considerations. Sure I could propaly hack something together, but would it be any good if I wanted to change the game later on?
I would like an engine where I''m able to use some kind of homebuild editor to define a new sort of creature: Graphics, MaxHitPoints and the like and then load it into the game when required.
One way to do it is, as you say, to make classes representing a Races as well as classes representing individual Creatures. The Race classes will then act a a ''Ressource'' for each creature to get such things as graphics and the like. This could also be expanded to include ressources for other objects in the game world, such as doors and chests. But I don''t like this approach because I think it decouples data that should be kept together and creates a mess of classes to administrate.
Another option is using static member variables. You mentioned that this would cause the statics for each class to be ''hard coded'' into the game. I don''t think that it is so. Just because a member variable is static, doesn''t mean that it is final (or constant). It can still be changed during runtime (at least in Java and OP, I''m not sure about C++). So in the constructor for the Orc class you could do something like this:
public Orc() {
if (this is the first orc = true) {
load Orc Race chararistics into static fields
indicate that the first orc has been created
}
// else Orcs already exists in the game, no loading
set Creature specific (non static) fields
}
Right now I think maybe this would be the best to do. But I really dont know for sure.
Maybe you would care to coorporate with me to make a complete framework of such an engine? That is to try to find an flexible and yet intuitive way to represent a tile-game world in terms of an Object Oriented structure of classes and their associations and interactions which each other.
Regards
Nicolai Buch-Andersen
Everybody who wants to write games seems to be talking about how to use DirectX ect., nobody seems to be adressing the fundamental structure of the games (the game logic as you call it).
I''ve never really got started on a game project on my own because of exactly the same considerations. Sure I could propaly hack something together, but would it be any good if I wanted to change the game later on?
I would like an engine where I''m able to use some kind of homebuild editor to define a new sort of creature: Graphics, MaxHitPoints and the like and then load it into the game when required.
One way to do it is, as you say, to make classes representing a Races as well as classes representing individual Creatures. The Race classes will then act a a ''Ressource'' for each creature to get such things as graphics and the like. This could also be expanded to include ressources for other objects in the game world, such as doors and chests. But I don''t like this approach because I think it decouples data that should be kept together and creates a mess of classes to administrate.
Another option is using static member variables. You mentioned that this would cause the statics for each class to be ''hard coded'' into the game. I don''t think that it is so. Just because a member variable is static, doesn''t mean that it is final (or constant). It can still be changed during runtime (at least in Java and OP, I''m not sure about C++). So in the constructor for the Orc class you could do something like this:
public Orc() {
if (this is the first orc = true) {
load Orc Race chararistics into static fields
indicate that the first orc has been created
}
// else Orcs already exists in the game, no loading
set Creature specific (non static) fields
}
Right now I think maybe this would be the best to do. But I really dont know for sure.
Maybe you would care to coorporate with me to make a complete framework of such an engine? That is to try to find an flexible and yet intuitive way to represent a tile-game world in terms of an Object Oriented structure of classes and their associations and interactions which each other.
Regards
Nicolai Buch-Andersen
Kylotan,
Why not have a member function called Update() which can be called everytime the game loop completes. Call it was the time delta of the screen loop:
for (i = 0; i < m_totalMonsters; i++)
m_monster->Update(frameTimeDelta);
Inside that function, update the positition of the object (based on a speed vector) and its frame (based on how often you want it updating). This could be a function that is in the base class and inherited so that all objects animate at the same rate, or change it so that some monsters animate faster (because you have more frames for them, or not) or some monsters animate differently (instead of looping through all of the animation cels each time you loop through the first four three times then complete the loop so a monster can scratch his head back and forth three times before stomping his feet).
I think you''re close on how you''ve implemented your monsters. If you want to keep you monsters dynamic, I would declare them as an array like this:
CMonster *m_monsters[MAX_MONSTER_TYPES][MAX_MONSTER_PER_TYPE];
You could make it a dynamic array, too. When a person wants to add a new monster type, you are adding to the first array. When they add more of the same monsters, you increment the second type.
Why not have a member function called Update() which can be called everytime the game loop completes. Call it was the time delta of the screen loop:
for (i = 0; i < m_totalMonsters; i++)
m_monster->Update(frameTimeDelta);
Inside that function, update the positition of the object (based on a speed vector) and its frame (based on how often you want it updating). This could be a function that is in the base class and inherited so that all objects animate at the same rate, or change it so that some monsters animate faster (because you have more frames for them, or not) or some monsters animate differently (instead of looping through all of the animation cels each time you loop through the first four three times then complete the loop so a monster can scratch his head back and forth three times before stomping his feet).
I think you''re close on how you''ve implemented your monsters. If you want to keep you monsters dynamic, I would declare them as an array like this:
CMonster *m_monsters[MAX_MONSTER_TYPES][MAX_MONSTER_PER_TYPE];
You could make it a dynamic array, too. When a person wants to add a new monster type, you are adding to the first array. When they add more of the same monsters, you increment the second type.
Nicolai,
I do think this sort of thing is an issue for anyone who wants to make more modular programs and games that the end user (or the programmer) can extend easily. I''d like to be able to add a new unit type just by adding a new text file to the Units directory, for example.
Your idea for loading in the static data is similar to what I have been using in one of my projects. You are right - it allows it to be changed without a recompile, so you can alter game balance more easily. That is good. But it still doesn''t allow extra unit types to be added, since the class must be hardcoded, which is a shame. Still, it is a good compromise, and adding a new class is not -too- much trouble, especially if you derive from a base class which contains much of the functionality already. The alternative I mentioned, storing a list of ''archetype'' classes, allows them to be loaded dynamically, but certainly does get bogged down in levels of indirection after a while. (Query the instance for its archetype, query the archetype for its animations, query the animations with the current direction and the state, etc).
I do think this sort of thing is an issue for anyone who wants to make more modular programs and games that the end user (or the programmer) can extend easily. I''d like to be able to add a new unit type just by adding a new text file to the Units directory, for example.
Your idea for loading in the static data is similar to what I have been using in one of my projects. You are right - it allows it to be changed without a recompile, so you can alter game balance more easily. That is good. But it still doesn''t allow extra unit types to be added, since the class must be hardcoded, which is a shame. Still, it is a good compromise, and adding a new class is not -too- much trouble, especially if you derive from a base class which contains much of the functionality already. The alternative I mentioned, storing a list of ''archetype'' classes, allows them to be loaded dynamically, but certainly does get bogged down in levels of indirection after a while. (Query the instance for its archetype, query the archetype for its animations, query the animations with the current direction and the state, etc).
quote: Original post by Sphet
Kylotan,
Why not have a member function called Update() which can be called everytime the game loop completes. Call it was the time delta of the screen loop:
for (i = 0; i < m_totalMonsters; i++)
m_monster ->Update(frameTimeDelta);
What if Windows decided to defrag its swap file during one of my frames (it inevitably does)? Then I might get a frame where a creature overshot its destination, moved 3 tiles, and that would screw with my pathfinding terribly
quote: This could be a function that is in the base class and inherited so that all objects animate at the same rate, or change it so that some monsters animate faster (because you have more frames for them, or not) or some monsters animate differently (instead of looping through all of the animation cels each time you loop through the first four three times then complete the loop so a monster can scratch his head back and forth three times before stomping his feet).
I was hoping to store frame duration (in milliseconds) with each frame of animation. So when you pass the timedelta to the animation function, it takes your current frame (+ time offset), adds on the elapsed time, and if the new time is greater than this frame''s duration, move to the next frame and the difference is carried forward as the offset. make sense? It still doesn''t handle excessively long frames well. Nor do I have a good solution to handling transitions between states - what if your character is half-way through 1 animation when they press a different key and start doing something else? Do you immediately change? That looks ok if your animations are short, but if they are 1/2 way through a 2 second animation, it could look wrong. Is it generally acceptable to prevent state changes until an animation is completed (or near the end)?
quote:
I think you''re close on how you''ve implemented your monsters. If you want to keep you monsters dynamic, I would declare them as an array like this:
CMonster *m_monsters[MAX_MONSTER_TYPES][MAX_MONSTER_PER_TYPE];
You could make it a dynamic array, too. When a person wants to add a new monster type, you are adding to the first array. When they add more of the same monsters, you increment the second type.
Well, my issue is more about how to invent a totally new type without having to touch the code, if possible I know this goes further than most commercial games, but I''d like to have that kind of flexibility. In the end, I might abandon that idea and instead concentrate on making them quick and easy to define in the code, combined with making most of a creaturetype''s parameters to be loaded in from a file.
Thanks for the comments all, keep them coming!
This topic is closed to new replies.
Advertisement
Popular Topics
Advertisement