Ever experience sudden frame rate drop or frame boost on your game, having sudden lag spikes and performance issues, did it affect the game play tremendously like it slowed down or made everything faster. It is either you really code awfully or your game is so affected with the FPS rate changes from various browsers and the user’s machine capability.
This is where time based coding takes place. By default, most of us amateurs went and started with frame based not knowing what it really is. When we say frame based the code and/or animation is dependent solely on how fast the FPS was set to, with a steady code, reducing the FPS rate will slow down the game and increasing it will hasten it. Time based coding can manage this quite well since everything can be dependent on time so frame rate doesn’t affect it that much. This problem is not only for games but for any development.
Code:
Let’s get started, I will discuss this with the sense of OOP approach where there is only a centralized loop function called to handle everything. I will not be actually using setInterval but the usual onEnterFrame event function.
This code is assumed to be part of a class, most cases shall be used in the main engine class but can also be used inside other classes too as long as it is correctly structured. This also assumes that the buffer movieclip is already instantiated.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | static var frameSpd:Number; var frameTime:Number; var buffer:MovieClip; function startEngine() { // some more codes here buffer.onEnterFrame = Delegate.create( this, loop ); // some more codes here } function loop() { frameTime = ( getTimer() - frameTime ) / 1000; _root.fpstxt = Math.round( 10 / frameTime ) / 10 +'fps\n '+ frameTime*1000 +'ms'; frameSpd = frameTime / 0.030; frameSpd = Math.min( 2.5, frameSpd ); var t:Number = getTimer(); // more and more codes are called from here frameTime = getTimer(); _root.fpstxt += '\n'+ ( frameTime - t ) + 'ms'; } |
Lines 1: made frameSpd a static variable so it can be easily accessed from any other location or class.
Line 11 & 19: frameTime is the time difference from when the loop was last called and ended.
Line 12 & 20: returns the frame’s FPS, last frame’s difference speed and actionscript process time.
Line 13: frameSpd is a variable that determines as a multiplier based on frameTime and the default FPS rate setting (in this case I use 30 as the movie’s FPS so 30/1000 = 0.030)
Line 14: makes a tolerance on how slow the frame rate has been and how much frameSpd has to catch up.
Implementations:
I’ll write some possible implementations in a pseudo code way using AS2 syntax and assuming that Engine is the name of the class where loop is located.
For basic movements, something like this on you movement function:
1 2 3 4 5 6 7 8 9 | var spd:Number = this.speed * Engine.frameSpd; // going left if ( dirx < 0 ) { _pos.x -= spd; // going right } else if ( dirx > 0 ) { _pos.x += spd; } // more and more code possible here |
Having gravity or other accelerating factor is quite tricky but not really too complex, something like this on your affect gravity functions:
1 2 3 4 5 6 7 | // store the var locally to improve lookup speed since it is used more than once var frameSpd:Number = Engine.frameSpd // apply gravity or any factor with acceleration jumpspeed += Engine.gravity * frameSpd; // apply the speed var spd:Number = jumpspeed * frameSpd; _pos.y += spd; |
And my favorite, handling animation speed (this one is for characters usually)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | var frameSkip:Number = Main.round( 4 * Engine.frameSpd ) + 1; // see what current frame I am on switch( _cframe ) { case 1: // stand and idle if ( _ccframe + frameSkip > 100 ) _ccframe = ( _ccframe + frameSkip) % 100 else _ccframe += frameSkip; break; case 3: // run if ( _ccframe + frameSkip > 80 ) _ccframe = ( _ccframe + frameSkip) % 80 else _ccframe += frameSkip; break; case 5: // jump if ( _ccframe + frameSkip > 65 ) _ccframe = ( _ccframe + frameSkip ) % 65 + 25; else _ccframe += frameSkip; break; case 7: // double jump if ( _ccframe + frameSkip > 50 ) { _ccframe = ( _ccframe + frameSkip ) % 50 + 25; _cframe = 5; } else _ccframe += frameSkip; break; default: break; } |
_cframe is the current animation frame of the character and _ccframe acts like a play head for the animation itself. If you have questions about this, my animation controller is discussed well enough on this post.
So basically having time based coding is a really powerful feature, you can even force multiply the frameSpd to a certain speed either on purposely speeding up your game or making it slow motion (matrix style). From the loop code from the top most edit it with this:
1 | frameSpd = Math.min( 2.5, frameSpd ) * forceSpd; |
Just make sure frameSpd maintains a tolerable value; having 10 would make it intensely fast and 0.1 would make it gruesomely slow. By default it has value of 1, 2 to make it twice and 0.5 to make half the speed, same goes if you’ll use a forceSpd.





•
20 Oct 08 at 6:34 pm
I don’t get it. What are you doing on line 13?
frameSpd = frameTime / 0.030;
Let’s say frameTime is 1 ( 1 sec ). If you divide it by 0.03 you will get 30 sec? Right? Is that what it should be ?
20 Oct 08 at 8:49 pm
If your frameTime is 1 then that would mean that it took 1 sec for the next frame to be called again (an incredible frame rate drop of 1 fps). So you get 33.33 frameSpd and have to adjust all speeds 33.33x faster to catch up everything. But the next line (14) limits that amount of catching up to 2.5, so any frameTime slower than 0.075 sec (75ms) would no longer be tolerable.
It’s set to 0.030 because the swf is set to 33fps by default.
33/1000 = 0.030 (well its 0.033 actually)
So normally frameSpd would be 1 when runtime fps is the same with the default fps.
21 Oct 08 at 2:31 am
Yeah, I get it
I wrote everything on a paper and also made a lot of traces in the code you wrote to see different situations and results
Good job Jayc. I really like your posts in FGL too
. Keep going !
21 Oct 08 at 2:57 am
Thanks plamen,
well now that I reviewed it, the default FPS is actually 30 making 30/1000=0.03. Lol (updated the post now)