Sdl Smooth Scrolling Tips?
#1
Posted 13 October 2009 - 07:55 PM
I recently added a scrolling message to my program, it's very simple, just displays a load of 32x32 graphics (about 50), and scrolls them on.
My problem, is that although I'm SDL_Delaying for the time it takes everything to draw minus 1000/desiredfps, i.e. it's all in time, every second or so the scrolling jitters (due to the time it takes everything to draw becoming larger than allowed).
It seems obvious that some other process is running is affecting my game. I have built it on windows at work and see exactly the same thing (I use linux at home).
I must be missing something major as I play games that don't do this.
Is my program REALLY inefficient? It doesn't do anything at this point!
Any ideas from you more experienced game coders?
#2
Posted 13 October 2009 - 08:00 PM
2. You might benefit from creating an average that you use when calculating your frame delta time, especially if you can't get access to a high resolution timer. Take the last 10 frames or so, and measure how long it took to process them. Divide by 10 and you have the delta time for one frame. Use that and it should reduce the effect of sudden speed changes.
Edited by dflemstr, 13 October 2009 - 08:01 PM.
#3
Posted 13 October 2009 - 08:40 PM
Consider . if you are double-buffering (say), then you can render off-screen for severeral units of time and then when it comes to showing a frame, you've got one queued up all ready to go. Likewise, rendering the offscreen objects in advance.
Or rendering to a virtual screen that is larger than your real screen, and shifting the visible window over and along it.
Depends on the platformn and how your API and hardware limit you etc, but maybe this will get your creativity going
jeff
#4
Posted 13 October 2009 - 09:18 PM
I am, in fact, blitting an entire screen image every refresh as well as double buffering but the resolution I'm at is 320x240 - I would have thought my pc could handle that!
During the game I'm just blitting one image (screen size) and several very small sprites.
Do you think it's worth bothering with only drawing differences? I don't...
Anyway, cheers for that, I really appreciate it :-)
#5
Posted 13 October 2009 - 11:08 PM
This gives me the movement delta.
int oldticks = SDL_GetTicks();
while(!done)
{
lag = (double)(SDL_GetTicks() - oldticks) / 1000.0;
oldticks = SDL_GetTicks();
double deltaX = speedXofSomeObject * lag;
object.X += deltaX;
}
You can place SDL_Delay() in the loop so you can limit the frames. You can calculate the value of the delay need to maintain a desired framerate.
Edited by dsh, 14 October 2009 - 10:13 AM.
#6
Posted 14 October 2009 - 12:40 AM
unsigned long Now;
short rate = 55; // frameage 1000/18
unsigned int timeleft(unsigned int x)
{
static unsigned int next_time = 0;
Now = SDL_GetTicks();
if ( next_time <= Now )
{
next_time = Now + x;
return( 0 );
}
return( next_time - Now );
}
// main loop
while( guy.turns )
{
draw();
SDL_Flip( Screen );
if ( doevents() )
guy.turns = 0;
SDL_Delay( timeleft( rate ));
}
Edited by Sphinxter, 14 October 2009 - 12:54 AM.
#7
Posted 14 October 2009 - 07:18 AM
loop: // this is where you actually would like the frame to show up erase() update() draw() // this is where it is shown wait()
you'll get small differences to draw times depending on how long the erase-update-draw takes. If, however you use double-buffering like:
loop: eraseDbuf() update() drawDbuf() wait() // this is where you actually would like the frame to show up flip() // this is where it is shown
the difference will be much smaller, because flipping is a fast operation.
EDIT: comments
Edited by B-ZaR, 14 October 2009 - 07:21 AM.
#8
Posted 14 October 2009 - 08:07 AM
Well, it seems that I'm doing everything correctly. Flipping, doubel buffering, waiting a small amount oftime dependent on the time it takes to draw a frame etc.
The only thing I havn't tried is skeezix's idea of buffering up extra frames in any remaining space.
I do find that scrolling with PC's is a little rubbish anyway and some googling seems to confirm that if I'm looking for that 'Arcade Perfect' scroll effect then I'm out of luck. I understand this has something to do with screen syncronisation (tearing) and I'm guessing all the other processes working in the background.
Will the Pandora suffer the same thing or will games have a higher priority (re: processes) and what about screen syncing?
#9
Posted 14 October 2009 - 08:13 AM
In short - make sure your text and buffer have the same bit-depth.
Edited by Unfathomable Depths, 14 October 2009 - 08:14 AM.
#10
Posted 14 October 2009 - 08:53 AM
SDL_DisplayFormat
which according to the comment:
/*
* This function takes a surface and copies it to a new surface of the
* pixel format and colors of the video framebuffer, suitable for fast
* blitting onto the display surface. It calls SDL_ConvertSurface()
*
* If you want to take advantage of hardware colorkey or alpha blit
* acceleration, you should set the colorkey and alpha value before
* calling this function.
*
* If the conversion fails or runs out of memory, it returns NULL
*/
#11
Posted 14 October 2009 - 09:14 AM
#12
Posted 14 October 2009 - 09:35 AM
I believe that if you could post your main loop's code that would allow us to help you more.
while(!exitProgram)
{
fps.start();
if(menu->screenMode == PlayingGame)
gameLoop();//this checks input and animates one frame
else
menuLoop();//this checks input and animates one frame
if(menu->screenMode == PlayingGame)
game->Draw(screen);
else
menu->Draw(screen);
SDL_Flip(screen);
diff = (1000 / updateFPS) - fps.GetTicks();
if( diff > 0 )
SDL_Delay( diff );
}
Edited: Because I pasted a load of crap by accident. fps class just records the number of ticks (GetTicks return the time passed since Start)
Edited by Miner49er, 14 October 2009 - 09:40 AM.
#13
Posted 14 October 2009 - 10:09 AM
I believe that if you could post your main loop's code that would allow us to help you more.while(!exitProgram) { fps.start(); if(menu->screenMode == PlayingGame) gameLoop();//this checks input and animates one frame else menuLoop();//this checks input and animates one frame if(menu->screenMode == PlayingGame) game->Draw(screen); else menu->Draw(screen); SDL_Flip(screen); diff = (1000 / updateFPS) - fps.GetTicks(); if( diff > 0 ) SDL_Delay( diff ); }
Edited: Because I pasted a load of crap by accident. fps class just records the number of ticks (GetTicks return the time passed since Start)
I don't see any problems here. Probably the frames take too long to draw. Did you check how much time does it take to draw one frame?
You may also check if you haven't got any float/int implicit conversions taking place. It's a longshot but it's easy to miss and causes strange errors.
Also, how do you store coordinates? They shouldn't be ints, the conversion to int should be just before drawing. Rounding can cause laggy movement.
Edited by dsh, 14 October 2009 - 10:14 AM.
#14
Posted 14 October 2009 - 10:35 AM
I believe that if you could post your main loop's code that would allow us to help you more.while(!exitProgram) { fps.start(); if(menu->screenMode == PlayingGame) gameLoop();//this checks input and animates one frame else menuLoop();//this checks input and animates one frame if(menu->screenMode == PlayingGame) game->Draw(screen); else menu->Draw(screen); SDL_Flip(screen); diff = (1000 / updateFPS) - fps.GetTicks(); if( diff > 0 ) SDL_Delay( diff ); }
Edited: Because I pasted a load of crap by accident. fps class just records the number of ticks (GetTicks return the time passed since Start)
I don't see any problems here. Probably the frames take too long to draw. Did you check how much time does it take to draw one frame?
You may also check if you haven't got any float/int implicit conversions taking place. It's a longshot but it's easy to miss and causes strange errors.
Also, how do you store coordinates? They shouldn't be ints, the conversion to int should be just before drawing. Rounding can cause laggy movement.
Hmmm, well as I explained before all menuLoop bit does is blit a background image and display about 50 16x16 images. So it's not doing a great deal.
Thing is, I seem to recall doing a scrolling message using AMOS basic about 20 years ago and getting PERFECT scrolling, no jitter, no worries. Now, I did have a fixed delay then as my brain hadn't figured out the variable-delay-dependant-on-draw-time bit but still... Of course my Amiga would've just had the AMOS process running, so no background threads/processes to cause jitter. This, I think, is the problem I'm encountering.
Also, the co-ords as ints comment: I'm using a 1 to 1 co-ord to pixel ratio, so I don't understand. I guess I could scale the scroller position up, move a fraction then scale down to draw...but I'm scrolling it along 1 pixel at a time right now, so I dont see the benefit.
#15
Posted 14 October 2009 - 10:55 AM
I believe that if you could post your main loop's code that would allow us to help you more.while(!exitProgram) { fps.start(); if(menu->screenMode == PlayingGame) gameLoop();//this checks input and animates one frame else menuLoop();//this checks input and animates one frame if(menu->screenMode == PlayingGame) game->Draw(screen); else menu->Draw(screen); SDL_Flip(screen); diff = (1000 / updateFPS) - fps.GetTicks(); if( diff > 0 ) SDL_Delay( diff ); }
Edited: Because I pasted a load of crap by accident. fps class just records the number of ticks (GetTicks return the time passed since Start)
I don't see any problems here. Probably the frames take too long to draw. Did you check how much time does it take to draw one frame?
You may also check if you haven't got any float/int implicit conversions taking place. It's a longshot but it's easy to miss and causes strange errors.
Also, how do you store coordinates? They shouldn't be ints, the conversion to int should be just before drawing. Rounding can cause laggy movement.
Hmmm, well as I explained before all menuLoop bit does is blit a background image and display about 50 16x16 images. So it's not doing a great deal.
Thing is, I seem to recall doing a scrolling message using AMOS basic about 20 years ago and getting PERFECT scrolling, no jitter, no worries. Now, I did have a fixed delay then as my brain hadn't figured out the variable-delay-dependant-on-draw-time bit but still... Of course my Amiga would've just had the AMOS process running, so no background threads/processes to cause jitter. This, I think, is the problem I'm encountering.
Also, the co-ords as ints comment: I'm using a 1 to 1 co-ord to pixel ratio, so I don't understand. I guess I could scale the scroller position up, move a fraction then scale down to draw...but I'm scrolling it along 1 pixel at a time right now, so I dont see the benefit.
If the time needed to draw the frame is low as you say then I highly doubt that any applications running in the background could cause that (if you're not running movie encoding or something very, very resource intensive). The priority and scheduling tricks are reserved for extremely low latency applications which do something hundreds of thousands times a second or so - that's when the system scheduler can cause jitter, not in your case. I had to use this tricks when I was doing RGB LED PWM modulation by LPT port. The modulation pulses where generated by the CPU...
Just check your CPU load graph.
Edited by dsh, 14 October 2009 - 10:56 AM.











