Smooth scrolling in 2D
BlitzPlus Forums/BlitzPlus Programming/Smooth scrolling in 2D
| ||
Hello! I am trying to create a 2D racing game, in Blitz 2D. To get the idea of movement, it scrolls tiles across the screen from top to bottom. The problem is the scrolling is not really smooth. I know this is a well known problem, getting the frame rate right and the scrolling smooth without relying on some monitor refresh rate. In a single-screen game I used the following solution to make sure a character moved say 40 times a second: I know how long each frame should take: 1/40th of a second. So I measure how long it actually takes, and from these two figures I compute a correction_factor, to get from the actual to the desired duration. Now, normally the player moves every single frame. So I would (theoretically) count the frames (adding 1 to this framecounter each frame), and the player would move if the count reaches 1 (and the framecounter is reset to 0). To get the correct animation speed however, I do not simply add 1 every frame, but instead I add 1.0 * correction_factor. Notice that of course I am using floats here as otherwise the small differences would be lost. I also take care not to reset the frames counter to 0, but instead to frames_counter-1.0, so as to keep the remainder. So I use this method in my racing game. However... when I link my scroller's location to the location of the player (to get a scrolling screen when the player moves) it can be seen that movement is not really smooth. What happens is that most of the time, the player is "allowed" to move in every single frame, but sometimes, the player is not allowed to move (due to "correction", the player has to skip a turn) and this is seen in the scrolling as a slight delay. Here's the code that says whether the player may move: AItime = AItime + correct(g_fpsc,1.0) If (AItime>=1.0) Then player_move() AItime = AItime - 1.0 DebugLog(">>>>>>> ACTION!") Else DebugLog("wait...") End If ("AItime" counts the frames, "g_fpsc" is an object that computes the corrected value of the value that is passed in the function. So instead of counting 1 frame, the program counts, say, 0.9 frames if the game has to be slowed down.) I also print some debug info to show the effect: >>>>>>> ACTION! >>>>>>> ACTION! >>>>>>> ACTION! >>>>>>> ACTION! >>>>>>> ACTION! >>>>>>> ACTION! >>>>>>> ACTION! >>>>>>> ACTION! >>>>>>> ACTION! >>>>>>> ACTION! >>>>>>> ACTION! >>>>>>> ACTION! wait... >>>>>>> ACTION! >>>>>>> ACTION! >>>>>>> ACTION! >>>>>>> ACTION! >>>>>>> ACTION! >>>>>>> ACTION! >>>>>>> ACTION! >>>>>>> ACTION! >>>>>>> ACTION! >>>>>>> ACTION! >>>>>>> ACTION! >>>>>>> ACTION! wait... And so on. Writing this all down it seems quite obvious that this would result in jerky scrolling, as whenever it says "wait" in the debuglog, at that moment the car does not move. Does anyone have ideas or experience in creating smooth scrolling in Blitz 2D, or comments on what I am doing here? The above method I got through advice in another post if I remember correctly, but it could be that I applied it differently. A thing that I could try is to use the "correction" method to change the amount by which the car moves (also suggested earlier by others). Right now I use integer amounts, but changing this to floats I could apply the correction factor to the car's speed. Maybe that still results in jerky scrolling, as in the end, movement is by whole pixels, but maybe the problem will be smaller. |
| ||
Try Delta Time, http://www.blitzcoder.com/cgi-bin/articles/show_article.pl?f=gamemorduun03212002.html |
| ||
Yes, so what I am doing now is Morduun's method, instead that I didn't apply it to the speed of the car, but instead to the movement "turns" the car is assigned. Thanks for the link, it is a very clear description by Morduun. So I will try to use his method the way it was meant to be used (I don't know why I did not do that in the first place, maybe because it involves adjusting every speed or timing value used in the game and I thought I could avoid this "extra processing"). Thinking some more about it, using it on the speed of the objects will probably give better results especially with higher resolutions, as in that case the possible amount of variation is bigger; the speed could for instance be changed from 6 pixels to 5 pixels in a given frame, and this would not be very noticable in scrolling. Do you use Delta Time in your Alpha Breed game? |
| ||
Or just tell the user to set their DirectX refresh rate to 60fps using the DXDiag override option (every PC monitor in the world must be able to display 60fps so it's a safe rate) and set your game to 60fps. It's a trick I learned off of Simon Smith and it works a *treat*. |
| ||
Hi, Here is my method. Sorry, I can't comment it because my english is not very good. But for my next game, I'll allow the player to chose the normal timming, or setting himself the monitor refresh at 60hz ( for the best smooth, like console-games ). AppTitle "Test" ;///////////////////////////////////////////////////////////////////////// Const ResolutionX%=640;X Const ResolutionY%=480;Y Const FPS#=60;images par secondes du jeu ;///////////////////////////////////////////////////////////////////////// Graphics ResolutionX,ResolutionY,16 ;***************************************************** ;***************************************************** ;Routine pour gerer le nombre d'image par secondes ** ;***************************************************** Type Frame_Rate ;***************** Field TargetFPS# ;***************** Field FPS# ;***************** Field TicksPerSecond# ;***************** Field CurrentTicks# ;***************** Field FrameDelay# ;***************** Field SpeedFactor# ;***************** Field AccumTicks# ;***************** End Type ;***************** Global Target_FPS#=FPS# ;***************** Global FL.Frame_Rate=New Frame_rate ;***************** Frame_Limit_Init(Target_FPS) ;***************** ;***************************************************** ;***************************************************** ;image Image=CreateImage(64,64) ;variable ImageX#=0;X ImageY#=32;Y Acceleration#=0;acceleration AccelerationBis%=0;acceleration bis ;///////////////////////////////////////////////////////////////////////// ;***************** ;* boucle du jeu * ;***************** SetBuffer BackBuffer() While Not KeyDown(1);tant que "echappe" n'a pas ete presse ;****************************************************** ;Routine pour gerer le nombre d'image par secondes *** ;****************************************************** Gosub Set_Speed_Factor; *** ;****************************************************** ClsColor 255,0,255 Cls;efface le tampon ;FL\SpeedFactor=1;a utiliser si rafraichissement moniteur=60hz ;acceleration If AccelerationBis=1 ImageX=(ImageX-(4*FL\SpeedFactor));gauche If AccelerationBis=2 ImageX=(ImageX+(4*FL\SpeedFactor));droite ;dessine l'image DrawBlock Image,ImageX,ImageY ;textes Text 00,100,"ImageX "+ImageX Text 00,110,"ImageY "+ImageY Text 00,120,"AccelerationBis "+AccelerationBis ;mise a jour AccelerationBis=0 ;///////////////////////////////////////////////////////////////////////// Flip;basculement des tampons ;///////////////////////////////////////////////////////////////////////// ;controleur If KeyDown(203) AccelerationBis=1;gauche If KeyDown(205) AccelerationBis=2;droite ;///////////////////////////////////////////////////////////////////////// Wend End ;************************************************************************************** ;************************************************************************************** ;Routine pour gerer le nombre d'image par secondes *********************************** ;************************************************************************************** .Set_Speed_Factor ;** ;** FL\CurrentTicks=MilliSecs() ;** FL\SpeedFactor=(FL\CurrentTicks-FL\FrameDelay)/(FL\TicksPerSecond/FL\TargetFPS) ;** If FL\SpeedFactor<0 FL\SpeedFactor=0;ne doit pas etre negatif ;** If FL\SpeedFactor>1 FL\SpeedFactor=1;ne permet pas au jeu de saccader ;** FL\FPS=FL\TargetFPS/FL\SpeedFactor ;** FL\FrameDelay=FL\CurrentTicks ;** Return ;** Function Frame_Limit_Init(target_FPS) ;** FL\TargetFPS=target_FPS ;** FL\TicksPerSecond=1000 ;** FL\FrameDelay=MilliSecs() ;** End Function ;** ;************************************************************************************** ;************************************************************************************** |
| ||
What's that about tampons? |
| ||
What's that about tampons? French word for "plug", apparently. :) |
| ||
"Tampon"=buffer :) |
| ||
Thanks Réno. That looks similar to the "Delta Time" method. I will look at it some more. OK, maybe I'd better just open up Blitz and put his in my game. I am *so* lazy. Let's do it! |
| ||
I have added Delta Time to change the speed of the car, and now I do get quite smooth scrolling! Yippie. Thanks for pointing this out again. |