Welcome, Guest. Please login or register. Did you miss your activation email?

Author Topic: Sprite sheet animation - Am I going about it okay?  (Read 14340 times)

0 Members and 1 Guest are viewing this topic.

Pyrius

  • Newbie
  • *
  • Posts: 39
    • View Profile
Sprite sheet animation - Am I going about it okay?
« on: October 16, 2011, 12:57:11 am »
I couldn't seem to find anything to help me with sprite animation using sprite sheets, so I experimented a bit and got it to work. I was wondering if I could do this in a better way or if someone has a link to a useful page. Here's my code:

Code: [Select]

//SpriteSheet.h:


#include <SFML/Graphics.hpp>

class SpriteSheet
{
public:
    SpriteSheet(sf::Image &spritesheet, int frameHeight, int frameWidth, int frames);
    void updateSprite(int animationID);
    // Some functions that aren't important here

private:
    sf::Image imgSheet;
    sf::Sprite sheet;

    int currentFrame;
    int frameHeight;
    int frameWidth;
    int animationID;
};


// SpriteSheet.cpp:


#include <SFML/Graphics.hpp>
#include "SpriteSheet.h"

using namespace sf;

SpriteSheet::SpriteSheet(Image &spriteSheet, int frameHeight, int frameWidth, int frames)
{
    imgSheet = spriteSheet;
    sheet.SetImage(spriteSheet);
    sheet.SetSubRect(IntRect(0, 0, frameWidth, frameHeight)); // Default subrect
}

void SpriteSheet::updateSprite(int animationID)
{
    currentFrame++; // Increments the frame
    currentFrame %= imgSheet.GetWidth() / frameWidth; // Makes the animation loop
    sheet.SetSubRect(IntRect(frameWidth * currentFrame,
                             frameHeight * animationID,
                             frameWidth * (currentFrame + 1),
                             frameHeight * animationID));
}

// Some functions here that aren't important


Any help would be appreciated, thanks.

Geoff

  • Newbie
  • *
  • Posts: 17
    • View Profile
Sprite sheet animation - Am I going about it okay?
« Reply #1 on: October 16, 2011, 10:09:31 am »
I think that your class isn't very flexible...

for my part, I have already implemented this type of class (in python),  and I prefer give a list of subrect (std:List<IntRect>) to the constructor, in order to handle different layout in my animation image. And this allow you to put several animations in the same spriteSheet.

after that, I create a vector of sprite inside my class, each correspond to a different SubRect, and I simply iterate over it for make my animation.

Excuse my bad english  :wink:

Pyrius

  • Newbie
  • *
  • Posts: 39
    • View Profile
Sprite sheet animation - Am I going about it okay?
« Reply #2 on: October 16, 2011, 11:14:08 am »
Your English is fine :) .  By different layout do you mean animations with different amounts of frames in one spritesheet? I decided to draw the image so that each animation had the same amount of frames, ie the standing image for my player is the same frame 8 times. I guess if I had a different animation like, for instance, jumping, with a different amount of frames, I would run into trouble.

Rather than passing in a list of subrect, I have the class calculate the number of frames and where all of the frames are located, assuming all of the frames have the same height and width as eachother.

I think I'll override the constructor to have the option to pass in a list of subrect if I'll ever feel the need for it. Thanks for the response  :) .

Haikarainen

  • Hero Member
  • *****
  • Posts: 545
    • MSN Messenger - fredrik.haikarainen@gmail.com
    • View Profile
    • Email
Sprite sheet animation - Am I going about it okay?
« Reply #3 on: October 16, 2011, 12:05:54 pm »
You could do it more flexible. I basically have these classes to complete a full animation-class, all of wich i'm managing in my own resourceeditor;

Code: [Select]
cTexture{
sf::Texture;
};

cTile{
sf::IntRect SubRect;
sf::Sprite Sprite;
// Pointer to a texture
cTexture* Texture;
};

cAnimation{
void Update();
// A vector of pointers to tiles
std::vector<cTile*> Tiles;
sf::Clock/thor::Timer Timer;
};


Why the timer? Because animations should be controlled with time, not hardware dependent updaterates. Now you just do; if Timer > 300ms then nextframe&reset timer.

Edit; Thats actually just a very simplified class list, I have classes like AnimationFrame's and such also, to control framespeeds, hotspots, actionpoints etc ;P

Pyrius

  • Newbie
  • *
  • Posts: 39
    • View Profile
Sprite sheet animation - Am I going about it okay?
« Reply #4 on: October 16, 2011, 05:13:26 pm »
I was planning on updating it with a Clock object in the main game loop, but I guess if I had too many spritesheets with different times between frames it could get pretty messy. Maybe I could try doing something with arrays or vectors or some kind of container and have each animation in a sprite sheet have their own IDs, so in my main loop I could do something like:

Code: [Select]

for(int ID = 0; ID < amountOfAnimations; ID++)
{
     if(clock.GetElapsedTime() >= updateRate[ID])
     {
          updateSprite(ID);
     }
}


EDIT: I just realized there's an error in the code I first posted. I edited in the fixed version.

Nexus

  • SFML Team
  • Hero Member
  • *****
  • Posts: 6278
  • Thor Developer
    • View Profile
    • Bromeon
Sprite sheet animation - Am I going about it okay?
« Reply #5 on: October 16, 2011, 06:37:15 pm »
For more inspiration, you can also take a look at how I did it in my library.

There's no complete sprite-sheet loader, just a few generic classes. It can still be made more flexible.
Zloxx II: action platformer
Thor Library: particle systems, animations, dot products, ...
SFML Game Development:

Pyrius

  • Newbie
  • *
  • Posts: 39
    • View Profile
Sprite sheet animation - Am I going about it okay?
« Reply #6 on: October 16, 2011, 11:06:03 pm »
Thank you all for your help :D. I skimmed through the page you linked me to, Nexus, and it looks pretty good. I really wish the Clock class had some of the functions your Timer class had. I'll take a closer look at it some other time, though.

I think the class works great now. You can have animations with different amounts of frames and different delays between frames (the delay varies by animation, not the frames it's between), and the updateSprite() function checks whether it's supposed to update at the time it's called by itself. Here's the revised code:

SpriteSheet.h:

Code: [Select]

class SpriteSheet
{
public:
    SpriteSheet();
    void setSpriteSheet(sf::Image &spriteSheet, short frameHeight, short frameWidth);
    void configureAnimation(short ID, short frames, int updateRate);
    void updateSprite(short ID);
    //Unimportant functions

    short currentID;

    sf::Sprite frame;

private:
    short currentFrame;
    short frameHeight;
    short frameWidth;
    std::vector <short> updateRate; // Stores update rates for each animation
    std::vector <short> frames; // Stores the amount of frames in each animation

    sf::Clock timer;
};


SpriteSheet.cpp:

Code: [Select]

SpriteSheet::SpriteSheet() // The constructor no longer "constructs" everything because I needed to create a spritesheet in a class.
{
    currentFrame = 0;
    currentID = 0;
}

void SpriteSheet::setSpriteSheet(Image &spriteSheet, short frameheight, short framewidth) // This is where you create the actual sprite sheet
{
    frameWidth = framewidth; // Store the frame width as a variable within the class
    frameHeight = frameheight; // Store the frame height as a variable within the class
    spriteSheet.SetSmooth(false);

    frame.SetImage(spriteSheet);
    frame.SetSubRect(IntRect(0, 0, frameWidth, frameHeight)); // Default subrect is the top right frame
}

void SpriteSheet::configureAnimation(short ID, short numOfFrames, int delay) // Delay is in milliseconds
{
    if(ID < 0) // The ID can't be less than 1
    {
        ID = 0;
    }
    frames.resize(frames.capacity() + 1, 0); // Make room for the new variable
    updateRate.resize(updateRate.capacity() + 1, 0); // Make room for the new variable

    frames.at(ID) = (numOfFrames > 1 ? numOfFrames : 1); // The amount of frames has to be at least 1
    updateRate.at(ID) = delay;
}

void SpriteSheet::updateSprite(short ID)
{
    if(currentID != ID) // If a new animation is being updated
    {
        currentID = ID;
        currentFrame = 0;
    }

    if(timer.GetElapsedTime() >= updateRate.at(currentID) * 0.001)
    {
        currentFrame %= frames.at(currentID); // Loops the frames

        frame.SetSubRect(IntRect(frameWidth * currentFrame,
                                 frameHeight * currentID,
                                 frameWidth * (currentFrame + 1),
                                 frameHeight * (currentID + 1)));
        currentFrame++; // Increments the frame
        timer.Reset();
    }
}

// Unimportant functions


In case anyone comes across this thread and wants to see how I revised it.

Nexus

  • SFML Team
  • Hero Member
  • *****
  • Posts: 6278
  • Thor Developer
    • View Profile
    • Bromeon
Sprite sheet animation - Am I going about it okay?
« Reply #7 on: October 16, 2011, 11:15:48 pm »
Is there a reason why you have arrays with exactly 10 elements? I would rather work with dynamic STL containers such as std::vector, which can be resized at runtime. The usage of containers is easier and less error-prone anyway. And for fixed-size arrays, you can use std::(tr1::)array, which has a lot of advantages over raw C style arrays, with the same performance.
Zloxx II: action platformer
Thor Library: particle systems, animations, dot products, ...
SFML Game Development:

Pyrius

  • Newbie
  • *
  • Posts: 39
    • View Profile
Sprite sheet animation - Am I going about it okay?
« Reply #8 on: October 16, 2011, 11:26:49 pm »
Nope, no reason at all. I didn't use vectors because I'm not very good with them; I have very little experience with them. I guess now is a good time to get some practice with them :). I'll edit the code real quick.

EDIT: Everything works fine now. I just need to figure out and implement collision detection and I'll be able to actually add a goal to the game I'm making :D.

Geoff

  • Newbie
  • *
  • Posts: 17
    • View Profile
Sprite sheet animation - Am I going about it okay?
« Reply #9 on: October 17, 2011, 01:36:13 pm »
Quote
By different layout do you mean animations with different amounts of frames in one spritesheet?


Yes, and different dispositions (vertical, horizontal). For example, with this spritesheet : http://img2.smackjeeves.com/images/uploaded/comics/7/8/78bc6b62fEySW.gif you have multiple animations in the same image, with differents size and amount of frames.

The goal is to create multiple animations with one spritesheep, by specifying all subrects of each animation.

But this is my opinion, it depends on your needs
 :wink:

Pyrius

  • Newbie
  • *
  • Posts: 39
    • View Profile
Sprite sheet animation - Am I going about it okay?
« Reply #10 on: October 17, 2011, 07:39:48 pm »
Quote
   
Yes, and different dispositions (vertical, horizontal).


Well now the class lets you give each animation different amounts of frames and different time between frames, but the height and width of each frame must be the same in every animation in a single spritesheet. I don't think I'll ever be in need of different sized animations in one spritesheet for my project, so I'll just leave that out.