 Computer Science Canada Programming C, C++, Java, PHP, Ruby, Turing, VB   Username:   Password: Wiki Blog Search Turing Chat Room Members
Delay-Free Animation        Author Message
Insectoid  Posted: Wed Jun 12, 2013 10:57 pm   Post subject: Delay-Free Animation

Most of the projects that get posted here have at least one delay in them to attempt to regulate the game speed. This may work on your computer but as soon as you try to share it, your timing will be completely messed up due to the different clock speeds. This can be mitigated somewhat with Time.DelaySinceLast, but why not let your computer do something in that spare time instead of waiting? Why design your program around a static framerate when you could just let it run as fast as possible? Instead of waiting to draw the next frame, why not just draw more frames?

This is relatively easy to do, though it does take a little extra work. Most students will assign their objects a static speed- maybe 10 pixels per frame. We're going to do the same, except we'll measure our speed in pixels per second. In our game loop, we will calculate how much time has passed since our last frame and then decide how far our object should have moved in that time.

 Turing: var x : real := 50 var y : real := 50 var speed : int := 100 %speed in pixels per second

I'm sure you recognize X and Y, although usually they're integers. In this example, we'll be using reals because our objects can actually move less than a pixel per frame. Our speed in pixels per second is one hundred. It should take us about 4 seconds to move from the bottom of the standard output window to the top, regardless of how fast your computer is.

Now we need a way to decide how much time has elapsed between frames. Turing has a Time.Elapsed function that shows how long the program has been running. If we record the Time.Elapsed in one frame, and then the next frame record it again, we can subtract the first from the second and get the time in between.

 Turing: var timeAtLastFrame : int := 0 % this global variable records the time elapsed in the previous frame function timeSinceLast : int %this function returns the time elapsed since the last time this function was called.     var t : int := Time.Elapsed %here we get the time since the program started     var out : int := t - timeAtLastFrame %subtract the time at the last frame from the current time     timeSinceAtFrame := t %record the current time so that we have it for the next frame     result out end timeSinceLast

Now that we can calculate our time between frames, we can start moving things. In your bog-standard animations, you simply add your speed to your x or y variable: x := x + speed. We do the same thing here, but first we have to multiply the speed by the number of seconds since the last frame. Also, since our speed is in pixels per second and our time is in milliseconds, we need to divide it by one thousand. So to move up, our equation would look like 'y := y + speed * time_since_last_frame / 1000.0'.
 Turing: if keys (KEY_UP_ARROW) then         y += speed * t / 1000.0 %t is our time since the last frame     elsif keys (KEY_DOWN_ARROW) then         y -= speed * t / 1000.0     end if

Now all that's left to do is put it all together. I've added a variable delay so you can see what it would look like on a slower computer. Press 'w' to increase the delay by 10ms and 's' to decrease it. Use the arrow keys to move around. There's a timer at the top so you can see that the time it takes to move across the screen doesn't change, no matter the delay.
 Turing: %Delay-free animation View.Set ('offscreenonly') var x : real := 50 var y : real := 50 var speed : int := 100 %speed in pixels per second var _delay : int := 0 var _timeSinceLast : int := 0 var t : int var keys : array char of boolean function timeSinceLast : int     var t : int := Time.Elapsed     var out : int := t - _timeSinceLast     _timeSinceLast := t     result out end timeSinceLast loop     t := timeSinceLast     Input.KeyDown (keys)         if keys (KEY_UP_ARROW) then         y += speed * t / 1000.0     elsif keys (KEY_DOWN_ARROW) then         y -= speed * t / 1000.0     end if         if keys (KEY_LEFT_ARROW) then         x -= speed * t / 1000.0     elsif keys (KEY_RIGHT_ARROW) then         x += speed * t / 1000.0     end if     if keys ('w') then         _delay += 10     elsif keys ('s') and _delay > 0 then         _delay -= 10     end if     delay (_delay)     cls     locate (1, 1)     put Time.Elapsed/1000.0     Draw.FillOval (round (x), round (y), 10, 10, red)     View.Update end loop    Insectoid  Posted: Wed Jun 12, 2013 11:32 pm   Post subject: RE:Delay-Free Animation

You can also apply this to variable-velocity movement models, where the object accelerates instead of moving at a constant speed. In this case, we swap out our speed variable for an acceleration variable measured in pixels per second squared. We also gain X and Y velocity variables measured in pixels per second. This again takes a little more work- we need to account for time elapsed when calculating how much we've accelerated in this frame as well as how far we've moved. In this sample, you can press the spacebar to return the ball to the starting position in case you lose it.
 Turing: %Delay-free animation View.Set ('offscreenonly') var x : real := 50 var y : real := 50 var velX : real := 0 %velocity in pixels per second var velY : real := 0 var acceleration : int := 400 %acceleration in pixels per second var deceleration : int := 200 %deceleration in pixels per second, for when no keys are pressed. var _delay : int := 0 var _timeSinceLast : int := 0 var t : int var keys : array char of boolean function timeSinceLast : int %this hasn't changed     var t : int := Time.Elapsed     var out : int := t - _timeSinceLast     _timeSinceLast := t     result out end timeSinceLast loop     t := timeSinceLast     Input.KeyDown (keys)         if keys (KEY_UP_ARROW) then         velY += acceleration * t / 1000.0 %here we add our acceleration corrected for time to our velocity     elsif keys (KEY_DOWN_ARROW) then         velY -= acceleration * t / 1000.0     else %if no key is pressed, we slow down         if velY > 0 then             velY -= deceleration * t / 1000.0 %reduce velocity if it's positive, again corrected for time         elsif velY < 0 then             velY += deceleration * t / 1000.0 %increase velocity if it's negative         end if     end if         if keys (KEY_LEFT_ARROW) then %same thing for the X axis         velX -= acceleration * t / 1000.0     elsif keys (KEY_RIGHT_ARROW) then         velX += acceleration * t / 1000.0     else         if velX > 0 then             velX -= deceleration * t / 1000.0         elsif velX < 0 then             velX += deceleration * t / 1000.0         end if     end if         if keys ('w') then         _delay += 10     elsif keys ('s') and _delay > 0 then         _delay -= 10     end if         if keys (' ') then %this returns the ball to the starting position when the spacebar is pressed.         x := 50         y := 50         velX := 0         velY := 0     end if         %When decelaration is corrected for time, we often end up bouncing between very small positive and negative velocities, so the ball never stops.     %This corrects it. When the velocity is smaller than the smallest possible deceleration corrected for time, we set it to 0. Using some kinematic     %equations, we could also set the X and Y values to exactly where the ball should be in this time, but that's not important for this demonstration.     if velX < deceleration*t/1000 and velX > -deceleration*t/1000 then         velX := 0     end if     if velY < deceleration*t/1000  and velY > -deceleration*t/1000 then         velY := 0     end if         y += velY * t / 1000.0 %Finally, we add the velocity corrected for time to the X and Y values.     x += velX * t / 1000.0     delay (_delay)     cls     locate (1, 1)     put Time.Elapsed/1000.0     Draw.FillOval (round (x), round (y), 10, 10, red)     View.Update end loop Tony  Posted: Wed Jun 12, 2013 11:44 pm   Post subject: RE:Delay-Free Animation

Nice.

A caveat is that this assumes constant speed. Things get somewhat more complicated when one wants to animate say... a jump. (edit: that has already been addressed above)

The basic idea is still the same -- figure out where along the expected trajectory the objects should be at time t, and draw them there. All the relevant formulas are available from a standard high school physics textbook.

One has to be careful though then steps average/round intermediate calculations. This shouldn't be a problem when the entire jump's trajectory can be calculated ahead of time, but if it's done step by step (because maybe there's in-air movement/collision), then one ends up with things like Quake3 where the frame rate affects the height of the jump -- http://www.psycco.de/125fps/UpsetChaps%20Quake3%20Guide%20-%20Why%20Your%20Framerate%20Affects%20Jumping.htm Tony's programming blog. DWITE - a programming contest. Insectoid  Posted: Wed Jun 12, 2013 11:55 pm   Post subject: RE:Delay-Free Animation

I made sure only to round when actually drawing the object. All calculations are done on the raw floats, though there may be floating point errors involved.

Actually, I do round it off in deceleration, and this was causing an issue initially at high values of _delay as I mentioned in the comments in the code. I've already fixed that in my own code so the X & Y values are adjusted before setting velocity to 0. Display posts from previous: All Posts1 Day7 Days2 Weeks1 Month3 Months6 Months1 Year Oldest FirstNewest First         Page 1 of 1  [ 4 Posts ]
 Jump to:  Select a forum  CompSci.ca ------------ - Network News - General Discussion     General Forums   -----------------   - Hello World   - Featured Poll   - Contests     Contest Forums   -----------------   - DWITE   - [FP] Contest 2006/2008   - [FP] 2005/2006 Archive   - [FP] 2004/2005 Archive   - Off Topic     Lounges   ---------   - User Lounge   - VIP Lounge     Programming -------------- - General Programming     General Programming Forums   --------------------------------   - Functional Programming   - Logical Programming   - C     C   --   - C Help   - C Tutorials   - C Submissions   - C++     C++   ----   - C++ Help   - C++ Tutorials   - C++ Submissions   - Java     Java   -----   - Java Help   - Java Tutorials   - Java Submissions   - Ruby     Ruby   -----   - Ruby Help   - Ruby Tutorials   - Ruby Submissions   - Turing     Turing   --------   - Turing Help   - Turing Tutorials   - Turing Submissions   - PHP     PHP   ----   - PHP Help   - PHP Tutorials   - PHP Submissions   - Python     Python   --------   - Python Help   - Python Tutorials   - Python Submissions   - Visual Basic and Other Basics     VB   ---   - Visual Basic Help   - Visual Basic Tutorials   - Visual Basic Submissions     Education ----------- - Student Life   Graphics and Design ----------------------- - Web Design     Web Design Forums   ---------------------   - (X)HTML Help   - (X)HTML Tutorials   - Flash MX Help   - Flash MX Tutorials   - Graphics     Graphics Forums   ------------------   - Photoshop Tutorials   - The Showroom   - 2D Graphics   - 3D Graphics     Teams ------ - dTeam Public

 Style: Appalachia blueSilver eMJay subAppalachia subBlue subCanvas subEmjay subGrey subSilver subVereor Search: