Jump to content
  • Advertisement
Sign in to follow this  
Jiroh

[SDL] Animation not working

This topic is 3790 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

Hi all, I've recently started following the Lazyfoo tutorials and there are a couple different ones I tried to combine. I tried to animate the stick figure from tutorial 20 and place it on the scrolling background of tutorial 21. All that's happening is the whole sprite sheet is being shown rather than the animated frames. I don't know how to fix this. Please let me know if you can help. This is what the code looks like:
/* -- Include the precompiled libraries -- */
    #ifdef WIN32
    #pragma comment(lib, "SDL.lib")
    #pragma comment(lib, "SDLmain.lib")	
	#pragma comment(lib, "SDL_image.lib")
    #endif 
//The headers
#include "SDL.h"
#include "SDL_image.h"
#include <string>

//Screen attributes
const int SCREEN_WIDTH = 640;
const int SCREEN_HEIGHT = 480;
const int SCREEN_BPP = 32;

//The frame rate
const int FRAMES_PER_SECOND = 20;

//The foo dimensions
const int FOO_WIDTH = 64;
const int FOO_HEIGHT = 205;

//The direction status of the stick figure
const int FOO_RIGHT = 0;
const int FOO_LEFT = 1;

//The dimensions of the level
const int LEVEL_WIDTH = 1280;
const int LEVEL_HEIGHT = 960;

//The surfaces
SDL_Surface *foo = NULL;
SDL_Surface *background = NULL;
SDL_Surface *screen = NULL;

//The event structure
SDL_Event event;

//The areas of the sprite sheet
SDL_Rect clipsRight[ 4 ];
SDL_Rect clipsLeft[ 4 ];

//The camera
SDL_Rect camera = { 0, 0, SCREEN_WIDTH, SCREEN_HEIGHT };

//The foo
class Foo
{
    private:
    //The X and Y offsets of the foo
    int x, y;
    
    //The velocity of the foo
    int xVel, yVel;
    
	//Its current frame
    int frame;
    
    //Its animation status
    int status;

    public:
    //Initializes the variables
    Foo();
    
    //Takes key presses and adjusts the foo's velocity
    void handle_input();
    
    //Moves the foo
    void move();
    
    //Shows the foo on the screen
    void show();
    
    //Sets the camera over the foo
    void set_camera();
};

//The timer
class Timer
{
    private:
    //The clock time when the timer started
    int startTicks;
    
    //The ticks stored when the timer was paused
    int pausedTicks;
    
    //The timer status
    bool paused;
    bool started;
    
    public:
    //Initializes variables
    Timer();
    
    //The various clock actions
    void start();
    void stop();
    void pause();
    void unpause();
    
    //Gets the timer's time
    int get_ticks();
    
    //Checks the status of the timer
    bool is_started();
    bool is_paused();    
};

SDL_Surface *load_image( std::string filename ) 
{
    //The image that's loaded
    SDL_Surface* loadedImage = NULL;
    
    //The optimized surface that will be used
    SDL_Surface* optimizedImage = NULL;
    
    //Load the image
    loadedImage = IMG_Load( filename.c_str() );
    
    //If the image loaded
    if( loadedImage != NULL )
    {
        //Create an optimized surface
        optimizedImage = SDL_DisplayFormat( loadedImage );
        
        //Free the old surface
        SDL_FreeSurface( loadedImage );
        
        //If the surface was optimized
        if( optimizedImage != NULL )
        {
            //Color key surface
            SDL_SetColorKey( optimizedImage, SDL_SRCCOLORKEY, SDL_MapRGB( optimizedImage->format, 0, 0xFF, 0xFF ) );
        }
    }
    
    //Return the optimized surface
    return optimizedImage;
}

void apply_surface( int x, int y, SDL_Surface* source, SDL_Surface* destination, SDL_Rect* clip = NULL )
{
    //Holds offsets
    SDL_Rect offset;
    
    //Get offsets
    offset.x = x;
    offset.y = y;
    
    //Blit
    SDL_BlitSurface( source, clip, destination, &offset );
}

void set_clips()
{
    //Clip the sprites
    clipsRight[ 0 ].x = 0;
    clipsRight[ 0 ].y = 0;
    clipsRight[ 0 ].w = FOO_WIDTH;
    clipsRight[ 0 ].h = FOO_HEIGHT;
    
    clipsRight[ 1 ].x = FOO_WIDTH;
    clipsRight[ 1 ].y = 0;
    clipsRight[ 1 ].w = FOO_WIDTH;
    clipsRight[ 1 ].h = FOO_HEIGHT;
    
    clipsRight[ 2 ].x = FOO_WIDTH * 2;
    clipsRight[ 2 ].y = 0;
    clipsRight[ 2 ].w = FOO_WIDTH;
    clipsRight[ 2 ].h = FOO_HEIGHT;
    
    clipsRight[ 3 ].x = FOO_WIDTH * 3;
    clipsRight[ 3 ].y = 0;
    clipsRight[ 3 ].w = FOO_WIDTH;
    clipsRight[ 3 ].h = FOO_HEIGHT;
    
    clipsLeft[ 0 ].x = 0;
    clipsLeft[ 0 ].y = FOO_HEIGHT;
    clipsLeft[ 0 ].w = FOO_WIDTH;
    clipsLeft[ 0 ].h = FOO_HEIGHT;
    
    clipsLeft[ 1 ].x = FOO_WIDTH;
    clipsLeft[ 1 ].y = FOO_HEIGHT;
    clipsLeft[ 1 ].w = FOO_WIDTH;
    clipsLeft[ 1 ].h = FOO_HEIGHT;
    
    clipsLeft[ 2 ].x = FOO_WIDTH * 2;
    clipsLeft[ 2 ].y = FOO_HEIGHT;
    clipsLeft[ 2 ].w = FOO_WIDTH;
    clipsLeft[ 2 ].h = FOO_HEIGHT;
    
    clipsLeft[ 3 ].x = FOO_WIDTH * 3;
    clipsLeft[ 3 ].y = FOO_HEIGHT;
    clipsLeft[ 3 ].w = FOO_WIDTH;
    clipsLeft[ 3 ].h = FOO_HEIGHT;
}



bool init()
{
    //Initialize all SDL subsystems
    if( SDL_Init( SDL_INIT_EVERYTHING ) == -1 )
    {
        return false;    
    }
    
    //Set up the screen
    screen = SDL_SetVideoMode( SCREEN_WIDTH, SCREEN_HEIGHT, SCREEN_BPP, SDL_SWSURFACE );
    
    //If there was an error in setting up the screen
    if( screen == NULL )
    {
        return false;    
    }
    
    //Set the window caption
    SDL_WM_SetCaption( "Move the Foo", NULL );
    
    //If everything initialized fine
    return true;
}

bool load_files()
{
    //Load the foo image
    foo = load_image( "foo.png" );
    
    //Load the background
    background = load_image( "bg.png" );
    
    //If there was a problem in loading the foo
    if( foo == NULL )
    {
        return false;    
    }
    
    //If there was a problem in loading the background
    if( background == NULL )
    {
        return false;    
    }
    
    //If everything loaded fine
    return true;
}

void clean_up()
{
    //Free the surfaces
    SDL_FreeSurface( foo );
    SDL_FreeSurface( background );
    
    //Quit SDL
    SDL_Quit();
}

Foo::Foo()
{
    //Initialize the offsets
    x = 0;
    y = 0;
    
    //Initialize the velocity
    xVel = 0;
    yVel = 0;

	//Initialize animation variables
    frame = 0;
    status = FOO_RIGHT;
}

void Foo::handle_input()
{
    //If a key was pressed
    if( event.type == SDL_KEYDOWN )
    {
        //Adjust the velocity
        switch( event.key.keysym.sym )
        {
            case SDLK_UP: yVel -= FOO_HEIGHT / 2; break;
            case SDLK_DOWN: yVel += FOO_HEIGHT / 2; break;
            case SDLK_LEFT: xVel -= FOO_WIDTH / 2; break;
            case SDLK_RIGHT: xVel += FOO_WIDTH / 2; break;    
        }
    }
    //If a key was released
    else if( event.type == SDL_KEYUP )
    {
        //Adjust the velocity
        switch( event.key.keysym.sym )
        {
            case SDLK_UP: yVel += FOO_HEIGHT / 2; break;
            case SDLK_DOWN: yVel -= FOO_HEIGHT / 2; break;
            case SDLK_LEFT: xVel += FOO_WIDTH / 2; break;
            case SDLK_RIGHT: xVel -= FOO_WIDTH / 2; break;    
        }        
    }
}

void Foo::move()
{
    //Move the foo left or right
    x += xVel;
    
    //If the foo went too far to the left or right
    if( ( x < 0 ) || ( x + FOO_WIDTH > LEVEL_WIDTH ) )
    {
        //move back
        x -= xVel;    
    }
    
    //Move the foo up or down
    y += yVel;
    
    //If the foo went too far up or down
    if( ( y < 0 ) || ( y + FOO_HEIGHT > LEVEL_HEIGHT ) )
    {
        //move back
        y -= yVel;    
    }    
}

void Foo::show()
{    
	 //If Foo is moving left
    if( xVel < 0 )
    {
        //Set the animation to left
        status = FOO_LEFT;
        
        //Move to the next frame in the animation
        frame++;
    }
    //If Foo is moving right
    else if( xVel > 0 )
    {
        //Set the animation to right
        status = FOO_RIGHT;
        
        //Move to the next frame in the animation
        frame++;
    }
    //If Foo standing
    else
    {
        //Restart the animation
        frame = 0;    
    }
    
    //Loop the animation
    if( frame >= 4 )
    {
        frame = 0;
    }
    //Show the foo
    //apply_surface( x - camera.x, y - camera.y, foo, screen );
	if( status == FOO_RIGHT )
    {
       //apply_surface( x, SCREEN_HEIGHT - FOO_HEIGHT, foo, screen, &clipsRight[ frame ] );
		apply_surface( x - camera.x, y - camera.y, foo, screen );
	}
    else if( status == FOO_LEFT )
    {
       //apply_surface( x, SCREEN_HEIGHT - FOO_HEIGHT, foo, screen ); //, &clipsLeft[ frame ] );
      apply_surface( x - camera.x, y - camera.y, foo, screen, &clipsLeft[ frame ] );
	
	}
}

void Foo::set_camera()
{
    //Center the camera over the foo
    camera.x = ( x + FOO_WIDTH / 2 ) - SCREEN_WIDTH / 2;
    camera.y = ( y + FOO_HEIGHT / 2 ) - SCREEN_HEIGHT / 2;
    
    //Keep the camera in bounds.
    if( camera.x < 0 )
    {
        camera.x = 0;    
    }
    if( camera.y < 0 )
    {
        camera.y = 0;    
    }
    if( camera.x > LEVEL_WIDTH - camera.w )
    {
        camera.x = LEVEL_WIDTH - camera.w;    
    }
    if( camera.y > LEVEL_HEIGHT - camera.h )
    {
        camera.y = LEVEL_HEIGHT - camera.h;    
    }    
}

Timer::Timer()
{
    //Initialize the variables
    startTicks = 0;
    pausedTicks = 0;
    paused = false;
    started = false;    
}

void Timer::start()
{
    //Start the timer
    started = true;
    
    //Unpause the timer
    paused = false;
    
    //Get the current clock time
    startTicks = SDL_GetTicks();    
}

void Timer::stop()
{
    //Stop the timer
    started = false;
    
    //Unpause the timer
    paused = false;    
}

void Timer::pause()
{
    //If the timer is running and isn't already paused
    if( ( started == true ) && ( paused == false ) )
    {
        //Pause the timer
        paused = true;
    
        //Calculate the paused ticks
        pausedTicks = SDL_GetTicks() - startTicks;
    }
}

void Timer::unpause()
{
    //If the timer is paused
    if( paused == true )
    {
        //Unpause the timer
        paused = false;
    
        //Reset the starting ticks
        startTicks = SDL_GetTicks() - pausedTicks;
        
        //Reset the paused ticks
        pausedTicks = 0;
    }
}

int Timer::get_ticks()
{
    //If the timer is running
    if( started == true )
    {
        //If the timer is paused
        if( paused == true )
        {
            //Return the number of ticks when the timer was paused
            return pausedTicks;
        }
        else
        {
            //Return the current time minus the start time
            return SDL_GetTicks() - startTicks;
        }    
    }
    
    //If the timer isn't running
    return 0;    
}

bool Timer::is_started()
{
    return started;    
}

bool Timer::is_paused()
{
    return paused;    
}

int main( int argc, char* args[] )
{
    //Quit flag
    bool quit = false;
    
    //The foo
    Foo myFoo;
    
    //The frame rate regulator
    Timer fps;
    
    //Initialize
    if( init() == false )
    {
        return 1;
    }
    
    //Load the files
    if( load_files() == false )
    {
        return 1;
    }
    
    //While the user hasn't quit
    while( quit == false )
    {
        //Start the frame timer
        fps.start();
        
        //While there's events to handle
        while( SDL_PollEvent( &event ) )
        {
            //Handle events for the foo
            myFoo.handle_input();
            
            //If the user has Xed out the window
            if( event.type == SDL_QUIT )
            {
                //Quit the program
                quit = true;
            }
        }
        
        //Move the foo
        myFoo.move();
        
        //Set the camera
        myFoo.set_camera();
        
        //Show the background
        apply_surface( 0, 0, background, screen, &camera );
        
        //Show the foo on the screen
        myFoo.show();
        
        //Update the screen
        if( SDL_Flip( screen ) == -1 )
        {
            return 1;    
        }
        
        //Cap the frame rate
        if( fps.get_ticks() < 1000 / FRAMES_PER_SECOND )
        {
            SDL_Delay( ( 1000 / FRAMES_PER_SECOND ) - fps.get_ticks() );
        }
    }
        
    //Clean up
    clean_up();
    
    return 0;    
}

Share this post


Link to post
Share on other sites
Advertisement
You are indeed blitting the entire surface. The second argument to SDL_Blit will define a source surface rect to blit. Your apply_surface function actually provides an interface to this. In fact, you seem to have used that interface in your code but commented it out. Take a look at the last argument to apply_surface in the code you commented out.

Share this post


Link to post
Share on other sites
I found my errors. First, I wrote out the set_clips() function but did not include it in main(). Second, for my two calls to apply_surface (one for left, one for right) I had to use “x - camera.x”.

Seems like Foo::set_camera() tries to center the view on the guy, but I was ignoring the camera position when drawing the guy.

So the code changed to
[source = cpp]
//Show the foo

if( status == FOO_RIGHT )
{
apply_surface( x - camera.x, SCREEN_HEIGHT - FOO_HEIGHT, foo, screen, &clipsRight[ frame ] );


}
else if( status == FOO_LEFT )
{
apply_surface( x - camera.x, SCREEN_HEIGHT - FOO_HEIGHT, foo, screen, &clipsLeft[ frame ] );

}

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

Participate in the game development conversation and more when you create an account on GameDev.net!

Sign me up!