Laggy movement (SDL) [SOLVED]

Started by
4 comments, last by Zakkeus 18 years, 4 months ago
I have been working out my new game but now I found a wierd problem. When I run program all is fine, but when the animation should move, it moves a 'little' laggy. I have other older code wich has been a base to this new and the old works fine. I can't figure out what the problem is even these two program sould work same way... I'm using 'time based moving' and the animation looks laggy and it won't respond to all movement controls instantly. Here is my code. It's a little big and the problem would be hard to find. All help is welcome! BTW, I think that in 'Timerdiff = SDL_GetTicks() - Timer;' function 'Timer' will made this laggy... I'm not sure about that.

// Code begins ///////////////////////////////////

#include "SDL.h"

using namespace std;

// The attributes of the window
const int SCREEN_WIDTH = 640;
const int SCREEN_HEIGHT = 480;
const int SCREEN_BPP = 32;

// The surface for screen
SDL_Surface *screen;

// 'color' will define the color wich is used in SDL_FillRect()
Uint32 color;

// Initialize SDL, images and so on...
void InitializeAll();

// Handle movement
void Movement();

// CLASSES ///////////////////////////////////////

// Information about players spaceship
class Player
{
    private:
            // Temporary surface to images
            SDL_Surface *Temp;
      
    public:
           // Main surfaces for images
           SDL_Surface *Ship;
           SDL_Surface *LFlame; 
           SDL_Surface *RFlame;
           SDL_Surface *DFlame;
             
           // Coordinates of ship and flame images, contain place.x and place.y
           SDL_Rect ShipPlace;
           SDL_Rect LFlamePlace;
           SDL_Rect RFLmaePlace;
           SDL_Rect DFlamePlace;
               
           // Initialize all Ships images
           void InitShipImages();
             
           // Initialize ship images places
           void InitShipPlaces();
};

// Set up class 
Player player;

void Player::InitShipImages()
{
    
    // Load the images to temporary surfaces and convert it to DisplayFormat and delete temp
    Temp = SDL_LoadBMP("Images/Ship/ship.bmp");                             // Ship 
    Ship = SDL_DisplayFormat(Temp);
    SDL_FreeSurface(Temp);
    
    Temp = SDL_LoadBMP("Images/Ship/flameleft.bmp");                        // Flame Left
    LFlame = SDL_DisplayFormat(Temp);
    SDL_FreeSurface(Temp);
    
    Temp= SDL_LoadBMP("Images/Ship/flameright.bmp");                        // Flame Right
    RFlame = SDL_DisplayFormat(Temp);
    SDL_FreeSurface(Temp);
    
    Temp = SDL_LoadBMP("Images/Ship/flamedown.bmp");                        // Flame Down
	DFlame = SDL_DisplayFormat(Temp); 
    SDL_FreeSurface(Temp);
}

void Player::InitShipPlaces()
{
    // Where the ship is (center of screen)
    ShipPlace.x = 302;
    ShipPlace.y = 231;
     
    // Where the Left Flame is
    LFlamePlace.x = ShipPlace.x-11;
    LFlamePlace.y = ShipPlace.x+5;
     
    // Right Flame
    RFLmaePlace.x = ShipPlace.x+35;
    RFLmaePlace.y = ShipPlace.y+5;
     
    // And Flame Down
    DFlamePlace.x = ShipPlace.x+11;
    DFlamePlace.y = ShipPlace.y+17;
}

class Level
{
    private:
            // Temporary surface for Level 1
            SDL_Surface *Temp_Level1;
              
    public:
           // Main surface for Level 1
           SDL_Surface *Level1;
             
           // Coordinates to Level 1 in screen, includes x and y.
           SDL_Rect PlaceLevel1;
             
           // Coordinates to pick target part of Level 1, includes x, y, w and h.
           SDL_Rect PartOfLevel1;
             
           // Initialize images of maps
           void InitLevelImages();
             
           // Initialize coordinates of maps
           void InitLevelPlaces();
};

// Set up class
Level level;

void Level::InitLevelImages()
{
     // Load the map image to temporary surface
     Temp_Level1 = SDL_LoadBMP("Images/Levels/Taso3.11.bmp");
     
     // Load temporary surface to main surface and delete temporary
     Level1 = SDL_DisplayFormat(Temp_Level1);
     SDL_FreeSurface(Temp_Level1);
}

void Level::InitLevelPlaces()
{
     // Place of map on the screen (left upper corner)
     PlaceLevel1.x = 0;
     PlaceLevel1.y = 0;
     
     // What place we blit to screen (works like starting place)
     PartOfLevel1.x = 200;
     PartOfLevel1.y = 200;
     PartOfLevel1.w = 640;
     PartOfLevel1.h = 480;
}

class TimeMovement
{
    private:
           // Key states
           Uint8 *Keystate;
           
           // Time handling
           float Timerdiff; // Used to determine the time elapsed
           float SecsPerFrame; // Used to hold the value for how many seconds have elapsed between frames
           
           // Movement
           struct DesiredDistance // Desired distance to move in a second, includes ships and levels x and y
           {
                // Ships
                float sx;
                float sy;
                
                // Levels
                float lx;
                float ly;
           };
           
           struct MovementValue // Value to move by each frame for Ship and Level, includes x and y
           {
                // Ship 
                float sx;
                float sy;
                
                // Level
                float lx;
                float ly;
           };
           
           // Set up classes
           DesiredDistance ddistance;
           MovementValue movementv;
    
    public:
           float Timer; // Used to check the current time
           
           // Key to game loop
           bool IsRunning;
           
           // Init DesiredDistance
           void InitDDistance();
           
           // Handles moving
           void Movement();
           
};

// Set up class
TimeMovement timo;

void TimeMovement::InitDDistance()
{
    // Init DesiredDistances
    ddistance.sx = 0;
    ddistance.sy = 0;
    
    ddistance.lx = 0;
    ddistance.ly = 0;
    
    movementv.sx = 0;
    movementv.sy = 0;
    }

void TimeMovement::Movement()
{
    // Check if user quits
    SDL_Event event;
    while(SDL_PollEvent(&event))
    {
         // If Quit
         if (event.type == SDL_QUIT)
         timo.IsRunning = false;
              
         switch(event.type)
         {
              case SDL_KEYDOWN:
              {
                   if(event.key.keysym.sym == SDLK_ESCAPE)
                   IsRunning = false;
              }	         
              break;
         }
    }
        
        
    // Here begins movement code
     
    // Get key states
    Keystate = SDL_GetKeyState(NULL);
    
    // If the pressed key is UP
    if(Keystate[SDLK_UP])
    {
              timo.ddistance.sy -= 15.57;
    }
    
    // If the pressed key is DOWN
    if(Keystate[SDLK_DOWN])
    {
              timo.ddistance.sy += 15.57;
    }
    
    // If the key was LEFT
    if(Keystate[SDLK_LEFT])
    {
         
              timo.ddistance.sx -= 8.2;
    }
    
    // If the key was RIGHT
    if(Keystate[SDLK_RIGHT])
    {
         
              timo.ddistance.sx += 8.2;
    }
    
    // This code will use Time based moving
     
    // Determine how many seconds elapset, GetTime() -> Now
    Timerdiff = SDL_GetTicks() - Timer;
    
    /* Function uses milliseconds so convert to seconds
    by dividing 1000 */
    SecsPerFrame = (float)(Timerdiff/1000.0);
    
    // Compute the movement value to Ship and Level, x and y
    movementv.sx = (float) (ddistance.sx*SecsPerFrame);            // Ships x
    movementv.sy = (float) (ddistance.sy*SecsPerFrame);            // Ships y
    
    movementv.lx = (float) (ddistance.lx*SecsPerFrame);            // Levels x
    movementv.ly = (float) (ddistance.ly*SecsPerFrame);            // Levels y
    
    // Now add MovementValue to original coordinations, Ship&Level 
    player.ShipPlace.x += (Sint16) movementv.sx;                   // Ship x
    player.ShipPlace.y += (Sint16) movementv.sy;                   // Ship y
    
    level.PartOfLevel1.x += (Sint16) movementv.lx;                 // Level x
    level.PartOfLevel1.y += (Sint16) movementv.ly;                 // Level y
}


// END OF CLASSES ////////////////////////////////

// MAIN PROGRAM BEGINS ///////////////////////////

int main(int argc, char *argv[])
{   
    // Initialize game
    InitializeAll();
    
    // Give a moment
    SDL_Delay(500);
    
    // Game loop starts here
    while(timo.IsRunning == true)
    {    
         // Get time
         timo.Timer = SDL_GetTicks(); 
         
         // Clear the screen
         SDL_FillRect(screen, NULL, color); 
         
         // Draw player to screen surface
         SDL_BlitSurface(player.Ship, NULL, screen, &player.ShipPlace);
         
         // Flip to screen
         SDL_Flip(screen);
         
         // Check movement
         timo.Movement(); 
    }
    
    return 0;
}
      
// OTHER PROGRAMS ////////////////////////////////

void InitializeAll()
{
    // Initialize SDL (Video and Timer)
    if(SDL_Init(SDL_INIT_VIDEO|SDL_INIT_TIMER) == -1)
    {
         fprintf(stderr, "Failed to initialize SDL: %s\n", SDL_GetError());
    }
	
	// Initialize screen with HWSURFACE and DOUBLEBUF
	screen = SDL_SetVideoMode(SCREEN_WIDTH, SCREEN_HEIGHT, SCREEN_BPP, SDL_HWSURFACE|SDL_DOUBLEBUF);
	
	 //Set the window caption
    SDL_WM_SetCaption( "Battle Lander", NULL );
    
    //Initialize images and places
    player.InitShipImages();
    player.InitShipPlaces();
    
    level.InitLevelImages();
    level.InitLevelPlaces();
    
    // Define the SDL_FIllRect color (black)
    color = SDL_MapRGB(screen->format, 0, 0, 0);
    
    // Set game on
    timo.IsRunning = true;
}



[Edited by - Zakkeus on December 20, 2005 3:27:13 PM]
Advertisement
When you say 'laggy' what do you mean? Jerky movemnt? When you press a key to move it takes a couple frames to respond? What happens if you make in non-frame-rate-independent? Does the 'laggyness' go away then?

Also, it might be easier if you provide less code in the future. We probrablly don't need to see your functions that initiate values.
Yeah, I think jerky would be the best word. It just moves slow, then faster and sometimes jumps around. It doesn't move smoothy.

It takes a while when it respond to the key pressing. Maybe a couble of frames. It stays still or keeps going to the way where it was going while pressing couple of seconds. And it doesn't slow it's speed smoothly (it should!) but stops suddenly and then change direction.

The jerky moving disappear if I put it to no_time_based_moving.

Oh, sorry about that ammount of code. I promise that I will reduce the code in future!

[Edited by - Zakkeus on December 17, 2005 6:55:50 PM]
Zakk, I tried to compile your code (and I created dummy images) and I only get a window blinked up and stderr.txt says there was a seg-fault. That aside I'd like to guess as to what the problem is. Your code goes something like this:
(Distance = speed*time)

speed = speed + SPEED_X (that is, timo.ddistance.sx += 8.2;)
Distance to move = DeltaTime * speed

So I guess what I'm saying is you're mixing up your speed and your distance...as far as I can make out, the further you are from the original point on the map, the faster you'll move because you're multiplying your delta time by how far you've moved instead of a constant speed.

This could probably be fixed by using constant speeds.
const int SPEED_X = 8.2 // this will probably be WAY WAY WAY too fast..maybe divide by 100if(Keystate[SDLK_RIGHT]){  timo.ddistance.sx += SPEED_X * Timerdiff;}if(Keystate[SDLK_LEFT]){  timo.ddistance.sx -= SPEED_X * Timerdiff;}// then your code that moves the ship


I might be totally off the mark though; just a suggestion!
It only takes one mistake to wake up dead the next morning.
Thx, Frequency but that didn't help...

I think I haven't mixed up time and distance. Here is a web page where I get this idea. I hope it will help a little.

Movement
Heh, I found my mistake. The thing wich solved my problem was that I used this code:

// Now add MovementValue to original coordinations, Ship&Level     player.ShipPlace.x += (Sint16) movementv.sx;                   // Ship x    player.ShipPlace.y += (Sint16) movementv.sy;                   // Ship y


But 'the right way' was something like this:
// Now add MovementValue to original coordinations, Ship&Level     x += (Sint16) movementv.sx;                   // Ship x    y += (Sint16) movementv.sy;                   // Ship y   player.ShipPlace.x = (Sint16) x;   player.ShipPlace.y = (Sint16) y;


I don't know the reason why is should be like this, but this helped me...

This topic is closed to new replies.

Advertisement