Page 1 of 1

Re-visiting my Animation Class [Not Solved]

Posted: Thu May 12, 2011 8:27 am
by superLED
Hello! I'm currently working on my animation class, and I've come across some problems while trying to make it more flexible.
I am using SDL, but I guess that's not much of relevance on this topic.

What i've used to do so far, is to have an SDL_Rect to each "animation" (one SDL_Rect for "idle", one for "walkingLeft", and so on), as an array to hold 4 frames (4 frames for each state).
And to set them up, I've done something like this:

Code: Select all

walkingRight[0].x = 0;
walkingRight[0].y = 0;
walkingRight[0].w = width;
walkingRight[0].h = height;

walkingRight[1].x = width;
...
walkingLeft[0].x = something
This can become very tedious. And I'm not quite sure how I can loop all these either to do the work for me.

So, I want to be able, in it's init function, to specify how many states I want for my characters. With a function like "void Anim::init(int numberOfStates, int numberOfFrames);"
And then the animation class should be able to handle all this by itself, with no fixed number of states and frames.

To sum it up: What I need help with, or be guided to, is to make my animation class a little more flexible, so I'm not stuck to the hardcoded states and frames.
In contrast of how my animation class is working now: I am limited to 4 frames (I can add more, but then I'd need to continue hardcoding it), limited to 4 states (the same as frames).

Here is some copy-paste of some of my animation class (my most horryfying class):

Anim.h

Code: Select all

class Anim : public Graph
{
protected:
	int frame, status;
	int frameCount, frameMax;

	SDL_Rect clipsUp[4];
	SDL_Rect clipsDown[4];
	SDL_Rect clipsLeft[4];
	SDL_Rect clipsRight[4];

public:
	Anim();
	~Anim();

	void setClips();

	// Setters
	void setFrame(int myFrame);

	// Getters
	SDL_Rect getClipsUp();
	SDL_Rect getClipsDown();
	SDL_Rect getClipsLeft();
	SDL_Rect getClipsRight();
};
Anim.cpp

Code: Select all

Anim::Anim() {
	frame = 0;
	status = 0;
	frameCount = 0;
	frameMax = 10;
}

Anim::~Anim() {
	//
}

void Anim::setClips() {
	// DOWN

	// #1 frame
    clipsRight[ 0 ].x = 0;
    clipsRight[ 0 ].y = 0;
    clipsRight[ 0 ].w = width;
    clipsRight[ 0 ].h = height;
    
	// #2 frame
    clipsRight[ 1 ].x = width;
    clipsRight[ 1 ].y = 0;
    clipsRight[ 1 ].w = width;
    clipsRight[ 1 ].h = height;
    
	// #3 frame
    clipsRight[ 2 ].x = width * 2;
    clipsRight[ 2 ].y = 0;
    clipsRight[ 2 ].w = width;
    clipsRight[ 2 ].h = height;
    
	// #4 frame
    clipsRight[ 3 ].x = width * 3;
    clipsRight[ 3 ].y = 0;
    clipsRight[ 3 ].w = width;
    clipsRight[ 3 ].h = height;
    
	//UP

	// #1 frame
    clipsLeft[ 0 ].x = 0;
    clipsLeft[ 0 ].y = height;
    clipsLeft[ 0 ].w = width;
    clipsLeft[ 0 ].h = height;
    
	// #2 frame
    clipsLeft[ 1 ].x = width;
    clipsLeft[ 1 ].y = height;
    clipsLeft[ 1 ].w = width;
    clipsLeft[ 1 ].h = height;
    
	// #3 frame
    clipsLeft[ 2 ].x = width * 2;
    clipsLeft[ 2 ].y = height;
    clipsLeft[ 2 ].w = width;
    clipsLeft[ 2 ].h = height;
    
	// #4 frame
    clipsLeft[ 3 ].x = width * 3;
    clipsLeft[ 3 ].y = height;
    clipsLeft[ 3 ].w = width;
    clipsLeft[ 3 ].h = height;

	// LEFT
	
	// #1 frame
    clipsDown[ 0 ].x = 0;
    clipsDown[ 0 ].y = height * 2;
    clipsDown[ 0 ].w = width;
    clipsDown[ 0 ].h = height * 2;
    
	// #2 frame
    clipsDown[ 1 ].x = width;
    clipsDown[ 1 ].y = height * 2;
    clipsDown[ 1 ].w = width;
    clipsDown[ 1 ].h = height * 2;
    
	// #3 frame
    clipsDown[ 2 ].x = width * 2;
    clipsDown[ 2 ].y = height * 2;
    clipsDown[ 2 ].w = width;
    clipsDown[ 2 ].h = height * 2;
    
	// #4 frame
    clipsDown[ 3 ].x = width * 3;
    clipsDown[ 3 ].y = height * 2;
    clipsDown[ 3 ].w = width;
    clipsDown[ 3 ].h = height * 2;
    
	// RIGHT

	// #1 frame
    clipsUp[ 0 ].x = 0;
    clipsUp[ 0 ].y = height * 3;
    clipsUp[ 0 ].w = width;
    clipsUp[ 0 ].h = height * 3;
    
	// #2 frame
    clipsUp[ 1 ].x = width;
    clipsUp[ 1 ].y = height * 3;
    clipsUp[ 1 ].w = width;
    clipsUp[ 1 ].h = height * 3;
    
	// #3 frame
    clipsUp[ 2 ].x = width * 2;
    clipsUp[ 2 ].y = height * 3;
    clipsUp[ 2 ].w = width;
    clipsUp[ 2 ].h = height * 3;
    
	// #4 frame
    clipsUp[ 3 ].x = width * 3;
    clipsUp[ 3 ].y = height * 3;
    clipsUp[ 3 ].w = width;
    clipsUp[ 3 ].h = height * 3;
}

void Anim::setFrame(int myFrame) {
	frame = myFrame;
}

SDL_Rect Anim::getClipsUp() {
	return clipsUp[frame];
}

SDL_Rect Anim::getClipsDown() {
	return clipsDown[frame];
}

SDL_Rect Anim::getClipsLeft() {
	return clipsLeft[frame];
}

SDL_Rect Anim::getClipsRight() {
	return clipsRight[frame];
}

Re: Re-visiting my Animation Class [Not Solved]

Posted: Thu May 12, 2011 8:42 pm
by LeonBlade
Hello,

Instead of making an array of frames, you can just keep an integer for your current frame instead and just move the frame accordingly.

Code: Select all

if(oldTime + frameRate > SDL_GetTicks())
	return;

oldTime = SDL_GetTicks();
currentFrame += frameIncrease;
    
// if you want to oscillate back (used in player animations)
if (oscillate)
{
	if (frameIncrease > 0) 
	{
		if (currentFrame >= maxFrames - 1)
			frameIncrease = -frameIncrease;
	}
	else
	{
		if (currentFrame <= 0)
			frameIncrease = -frameIncrease;
	}
}
else 
{
	if (currentFrame >= maxFrames - 1)
		currentFrame = 0;
}
And this is how I render

Code: Select all

frameRect.x = this->animationControl.GetCurrentFrame() * TILE_SIZE;
frameRect.y = facing * TILE_SIZE;
frameRect.w = TILE_SIZE;
frameRect.h = TILE_SIZE;

Re: Re-visiting my Animation Class [Not Solved]

Posted: Thu May 12, 2011 9:37 pm
by like80ninjas
In my 2D engine(s), I use a few values,

int image_index
float image_speed;
float speed_index;

so I add image_speed to speed_index every step, and then set the int image_index = float image_speed, which drops the decimal from the value(you will get a warning for this).

with this image_speed integer, I use it as my index in my array of rects (frames),

DrawImageClipped( x, y, WalkAnimation[image_index] ); Or whatever your draw code looks like.

also, once speed_index is greater than your max number of frames, set it to 0.0, so it will loop, giving you animation.

the image_speed can be 1.0 to 0.0 with lower values producing slower animations and 1.0 animating at your frame rate.

Code: Select all

if (speed_index > max_frames)
    speed_index = 0.0f;

speed_index += image_speed;
image_index = speed_index;
//Then set your image_index as the frame in your animation (array of rects)
As for actually putting the frame arrays together, I make sure my sprite sheets are nice and orderly ( like all 64x64 images lined up side by side ) and then use a for loop to set them up automatically.

If you want to have them done "for" you, then I think that's the easiest way. Just make a function that sets up the array of rects to what it should be

Code: Select all

for (int i =0; i<number_of_animations; i++)
{
    for (int r = 0; r<number_of_frames_per_animations; r++)
    {
        Player_anims[i][r].x = r*w;
        Player_anims[i][r].y = i*h;
        Player_anims[i][r].w = r*w + w;
        Player_anims[i][r].h = i*h + h;
    }
}
Something like that will set it up to where you can have Player_anims[r], where i is the animation, and r is its frames.
***Note that the code above assumes your images have one line per animation.

Then you can just remember which "i" index is which animation, or set up constants or enums for the numbers so you can reference with names.

I'm no programming whiz, but that's how I do it in my games, and it's worked with no problems so far, so help this helps.

Re: Re-visiting my Animation Class [Not Solved]

Posted: Thu May 12, 2011 10:46 pm
by bnpph
I don't fully understand your question, but here is a quick thing that might be what you're looking for:

Code: Select all

class AnimationManager {
  public:
    struct Animation {
      unsigned int numFrames;
      SDL_Rect* frames;
    };
  private:
    unsigned int animationStackPtr;
    unsigned int numAnimations;
    Animation* animations;
  public:
    Animation() : animations(NULL), animationStackPtr(0) {}
    Animation(unsigned int numAnimations) : {
    animationStackPtr(0)
      animations = new Animation[numAnimations];
    }
    ~Animation() {
      if(animations) {
        for(unsigned int i = 0; i < animationStackPtr; ++i)
          delete[] animations[i].frames;
        delete[] animations;
      }
    }
    
    Animation* addAnimation(unsigned int numFrames) {
      animations[animationStackPtr].numFrames = numFrames;
      animations[animationStackPtr].frames = new SDL_Rect[numFrames];
      return &animations[animationStackPtr];
    }
};
Have not tested or compiled.

Re: Re-visiting my Animation Class [Not Solved]

Posted: Fri May 13, 2011 5:46 am
by superLED
Many interesting solutions. I will test them out as soon as I get home!
I am sure all of your suggestions will come in handy. Thanks a lot!

I will post an update to tell you all how it worked out.

Re: Re-visiting my Animation Class [Not Solved]

Posted: Sun May 15, 2011 2:37 am
by MadPumpkin
I (personally) would go with LeonBlade's, it's closest to what I use. The others seem fine though, so which ever looks prettiest to you. I was going to post mine but changed my mind once I read LeonBlade's code.