Sprites and Sprite Cache
From DoonLunacy
Contents |
Theory of operation
SpriteCache (a singleton) loads the config file and appropriate images. The results are stored as Sprites, the objects holding information how to assemble the final image for different animation frame and direction. These informations are same for all sprite instances (eg: for all tanks), so there is no need for every tank to have its own rules how to draw itself. There is SpriteState class between the unit/building/etc. and Sprite. SpriteState holds information specific to given instance (direction, frame, color) and smartpointer to Sprite object to be used for drawing.
Notes:
- SomethingPtr means smartpointer to Something
Directions
There are number of different buildings, units and projectiles. Most of them are drawn in different number of direction. The number of directions used is determined by enum DirectionType.
// type of animation/mode
enum DirectionType
{
DT_D1, // static buildings
DT_D8, // most units
DT_D16, // rockets, projectiles, ...
DT_DB4, // bit-based directions (ground)
DT_DB44, // 2-level bit based directions (walls: 1st level - healthy wall, 2nd level - damaged wall)
};
Values for direction types folow:
// single direction building and default desert ground
enum D1
{
D1_N,
};
// units, towers
enum D8
{
D8_N,
D8_NE,
D8_E,
D8_SE,
D8_S,
D8_SW,
D8_W,
D8_NW,
};
// rockets
enum D16
{
D16_N,
D16_NNE,
D16_NE,
D16_NEE,
D16_E,
D16_SEE,
D16_SE,
D16_SSE,
D16_S,
D16_SSW,
D16_SW,
D16_SWW,
D16_W,
D16_NWW,
D16_NW,
D16_NNW,
};
// green, odd desert, spice, dense spice
enum DB4
{
DB4_NONE = 0,
DB4_N = 1,
DB4_E = 2,
DB4_S = 4,
DB4_W = 8,
DB4_ALL = 15,
};
// walls
enum DB44
{
DB44_NONE = 0,
// first level (healthy wall)
DB44_A_N = 1,
DB44_A_E = 2,
DB44_A_S = 4,
DB44_A_W = 8,
// second level (damaged wall)
DB44_B_N = 16,
DB44_B_E = 32,
DB44_B_S = 64,
DB44_B_W = 128,
DB44_ALL = 255,
};
// eg: (DB44_A_N | DB44_A_W | DB44_B_S) means healthy wall to north and west, damaged wall to south, no wall to east
Animation modes
Different animations can use different modes. AnimationMode enum is used to determine the mode for given sprite.
// type of animation used
enum AnimationMode
{
AN_LOOP, // loop whole animation (eg: building flags, animated buildings)
AN_ONESHOT, // keep the last frame (eg: explosions )
AN_PINGPONG, // loop playing forwarad and backward (eg: orni)
};
Sprite parts
Sprite parts are simple structures specifying which parts of source image should be copied to screen and where.
// part of sprite
struct SpritePart
{
Rect srcRect;
SPoint dstPoint; // 0,0 is top left corner of target rect (see ''Sprite'' for details about that rect)
};
Sprite
class Sprite
{
public:
Sprite(ConfigFile::MapNodePtr config);
~Sprite();
// draw this sprite on 'where' using 'state'
void draw(ConstUPoint where, const SpriteState &state);
// make remapped copy of sprite and add it to images (called if required by draw)
void generateColor(unsigned color);
protected:
DirectionType dt; // type of direction used
unsigned frames; // animation length in frames (same length for all directions required)
AnimationMode mode; // animation mode
UPoint size; // size of animation in pixels - to be used for selecting unit/building with mouse, also the reference rect for ''parts''
std::map<unsigned, Image> images; // image colored to given color (that ''unsigned'' key is first color that was remapped)
std::vector< std::vector< std::vector < SpritePart > > > parts; // parts of sprite, parts[direction][frame][partno]
SPoint offset; // point to subtract from target drawing coordinates;
// TODO: maybe coordinates for creating bullets, rockets, etc.
};
- I'm not sure about coordinates for creating bullets, rockets, etc. Maybe they should be also stored in Sprite class. Not sure how exactly: some units have more than one weapon, there are different coordinates required for different directions (maybe even for different frames)
SpriteState
class SpriteState
{
public:
SpriteState(ConstString name, unsigned color, unsigned angle = 0);
~SpriteState();
void advance(); // move to the next frame
// TODO: not sure about the speeds of animations (if there are animations of different speeds, i
void draw(ConstUPoint where); // just call sprite's method
void changeSprite(ConstString name);
void changeColor(unsigned color);
void setAngle(unsigned angle); // 0..360, automatically remaps to directions
protected:
SpritePtr sprite; // never NULL !
unsigned direction; // should be an value allowed by sprite->dt enum
unsigned frame; // current frame of animation (retains the value even while changing direction)
unsigned color; // color to be used for remapping the sprite (first target color)
};
Example of use:
class Unit
{
...
SpriteState sprite;
...
}
.. Unit::something()..
{
..
sprite.changeColor(players[0].color); // or something like that
sprite.setAngle(123); // spritestate selects the corresponding sprite direction itself
sprite.changeSprite("quad"); // trike has grown into a quad ;-)
sprite.draw(position);
..
}
SpriteCache
class SpriteCache : + that stuff for singleton ;-)
{
public:
SpriteCache();
~SpriteCache();
void load(ConstString configfile); // eg: "ADDITIONAL:graphics.cfg"
SpritePtr get(ConstString name);
protected:
};
- the only directly used method would be load
- the sprite state would itself get the sprite pointers from the cache

