Take the 2-minute tour ×
Game Development Stack Exchange is a question and answer site for professional and independent game developers. It's 100% free, no registration required.

I'm having trouble coming up with a way to animate these 2D isometric sprites. The sprites are stored like this:

(Game Folder Root)/Assets/Sprites/(Sprite Name)/(Sprite Animation)/(Sprite Direction)/(Frame Number).png

So for example,

/Assets/Sprites/Worker/Stand/North-East/01.png

Sprite sheets aren't really viable for this type of animation. The example stand animation is 61 frames. 61 frames for all 8 directions alone is huge, but there's more then just a standing animation for each sprite. Creating an sf::Texture for every image and every frame seems like it will take up a lot of memory and be hard to keep track of that many images. Unloading the image and loading the next one every single frame seems like it will do a lot of unnecessary work. What's the best way to handle this?

The reason I am not using a sprite sheet is because these sprites are hi-res images with many animations which all have a large quantity of frames. The resulting sprite sheet would be massive. In case you're wondering, here was my implementation of creating animated sprites.

// Animation class declaration
class Animation
{
public:
        Animation(std::string path, int frames);
        ~Animation();
        void nextFrame();
        void gotoStart();
        bool loadFrames();
        sf::Texture& getActiveFrame();

private:
        int frameCount;
        std::string pathToAnimation;
        int currentFrame;
        sf::Texture frame[];
};

// Animation class implementation
Animation::Animation(std::string path, int frames)
{
        pathToAnimation = path;
        frameCount = frames;
}

Animation::~Animation()
{
        // destructor
}

void Animation::nextFrame()
{
        if(currentFrame < frameCount)
        {
            currentFrame = 1;
        }
        else
            currentFrame += 1;
}

void Animation::gotoStart()
{
        currentFrame = 1;
}

bool Animation::loadFrames()
{
        for(int i = 01; i < frameCount; i++)
        {
            if(!frame[i].loadFromFile(pathToAnimation + std::to_string(i) + ".jpg")) return false;
        }
        return true;
}

sf::Texture& Animation::getActiveFrame()
{
    return frame[currentFrame];
}

// Actor class declaration
class Actor
{
public:
        Actor();
        ~Actor();
        void setActiveAnimation(std::shared_ptr<Animation> anim);
        void draw(sf::RenderWindow& win);

private:
        sf::Sprite sprite;
        std::shared_ptr<Animation> activeAnimation;
};

// Actor class implementation
Actor::Actor()
{
    // constructor
}

Actor::~Actor()
{
    // destructor
}

void Actor::setActiveAnimation(std::shared_ptr<Animation> anim)
{
    activeAnimation = anim;
    activeAnimation->gotoStart();
}

void Actor::draw(sf::RenderWindow& win)
{
    sprite.setTexture(activeAnimation->getActiveFrame());
    win.draw(sprite);
    activeAnimation->nextFrame();
}

It's still not 100% where I'd like it to be but it's working and it's pretty easy to use.

share|improve this question
4  
1. You don't need 61 frames for a animation. Most should look really smooth with 16 frames already. (Depending on how long the animation is of course.) 2. It's huge, yes, but the computer has a huge amount of memory too. A 100MB (= a enormous amount of data) is a little nowadays. 3. Load them once and keep them. Its not "per Frame", its once. –  Mr. Beast Jun 7 '12 at 20:24
add comment

1 Answer

You would not want to load/unload a texture after each frame. This is because it would involve accessing the hard drive each time. This takes a very long time compared to accessing memory and you would certainly see a slow down in rendering. So what you want to do is to load all of the textures into memory.

If we have 60, 32x32, rgba8 textures for each 8 directions, this is about 2MB. So we can see that it really isn't that much memory.

(You could just keep each texture in memory and swap around, but the following is the more "correct" way to do it)

I believe you are using SFML, I haven't used it personally but after searching there is a class you can use just for this purpose, an sf::Sprite. This is just the same as rendering an sf::Texture, however you need to pass it a texture to start with. Whats the difference? Well you need to pass this sprite a rectangle in the texture to use. So you say this sprite will use this part of the texture.

This is better because we can make one big texture with all of our sprites on and reference each sprite individually. It means we do not have to swap textures after each frame (this is expensive for the GPU to do).

Of course this means that you will have to add all of your separate sprites into one texture before you load them. It also means that you need to know the rectangle that each sprite occupies. After a quick google search you could use this http://spritesheetpacker.codeplex.com/ it outputs a final texture and a .txt file that gives you where each sprite is located.

share|improve this answer
    
In sfml, an sf::Texture is simply an image that we load into memory. The object we use to actually display the image and do things with it is sf::Sprite. I could use sf::Sprite::setTextureRect as you said if I were using a sprite sheet, but I stated in the edit why I chose not to do so. Thanks anyways. –  user7383 Jun 9 '12 at 16:15
add comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.