How to solve different FPS in requestAnimationFrame on different browsers? - javascript

How to solve different FPS in requestAnimationFrame on different browsers?
I am making a 3D game using THREE.js that uses requestAnimationFrame and it is fast on Google Chrome 15.
However, it is really slow on Firefox 6 and really really slow (slower than Firefox) on IE9.
This is really a big problem and I am wondering if there is a solution to that.
Thanks.

The common thing to do is to create a deltaTime (dt) variable which is then be used as a parameter for every animation/update cycle.
Code is only for visualizing the problem/solution.
// ...
timer: function(){
var now = new Date().getTime(); // get current time
this.controls.dt = now - this.controls.time; // calculate time since last call
this.controls.time = now; // update the current application time
this.controls.frame++; // also we have a new frame
return this.controls.dt ;
}
for any call to the render function you then pass dt
// we call the update function with every request frame
update: function(){
var dt = this.timer();
_.each(this.activeViews, function(item){ item.update(dt); }); // this is underscore.js syntax
}
item.update(dt) looks like that
//...
var x = this.position.get(x);
x = x + (10*dt); // meaning: x increases 10 units every ms.
this.position.x = x;

As far as I know there's no way to really fix this, other than making your code less resource intensive.
Chrome seems to be the fastest browser, but usually FF is not far behind, but IE is still slow. Depending on the rendering methods, canvas, svg or webGL, it's also very dependent on your local hardware as it uses the clientside for most things, and complicated webGL renderings need a powerful GPU to achieve good framerates.
There are ways to measure the framerate on the fly, and change your animations accordingly.
Here's a very simple example that measures framerate.
function step(timestamp) {
var time2 = new Date;
var fps = 1000 / (time2 - time);
time = time2;
document.getElementById('test').innerHTML = fps;
window.requestAnimationFrame(step);
}
var time = new Date(), i = 0;
window.requestAnimationFrame(step);
<div id="test"></div>
This is just an instant measure that's not that accurate, you'd probably want something that measures over some time to get a more correct framerate for the browser being used.
Also note the timestamp argument, which in requestAnimationFrame is high-res timestamp with a minimal precision of 1 milliseconds, that can also be used to deterine the speed of the animation, and any browser lag.

On some browsers requestAnimationFrame works something like
setTimeout(callback, 1000 / (16 + N)
where N is time required for your code to execute. Which means it caps your FPS at 62Hz but if your code works slowly, it will cap at something way lower. It basically tries to make a 16ms gap between every gap. Of course, this is not true for all browsers and will probably change in the future anyway but it still may give you an idea how it works.
Even if it was implemented the same in every browser, there are many factors which affect the performance of your code and etc. You can never be sure your code will be running at a constant frequency.

The Crafty framework does something that's a bit different, but might work for some cases -- the number of game ticks per draws is not constant. Rather, it notices when the framerate is falling behind some ideal target, and will cycle through multiple game ticks before performing the draw step. You can see the step function on github.
This works well so long as the game would be running smoothly. But if you try something more processor intensive, it can tend to exacerbate the situation, as it will prioritize game logic over animation.
In any case, it'll only work if the game logic and render logic are somewhat decoupled. (If they were completely decoupled you might be able to put them in completely separate loops.)

As adeneo mentioned, the requestAnimationFrame callback is sent a timestamp argument. Here is a solution to measure the delta between requestAnimationFrame events using that timestamp argument instead of creating a separate variable using the Date() function (which performance.now() may be a better solution anyhow).
This solution also includes a Start/Stop option to show why I am using a separate function to initialize the previousTimestamp at each start, and why I am setting a reqID value.
var reqID, previousTimestamp, output;
const raf = window.requestAnimationFrame || window.mozRequestAnimationFrame ||
window.webkitRequestAnimationFrame || window.msRequestAnimationFrame;
const caf = window.cancelAnimationFrame || window.mozCancelAnimationFrame;
// This is run first to set the previousTimestamp variable with an initial value, and then call the rafLoop function.
const startStop = () => {
if ($('#start-stop').prop('checked')) {
reqID = raf(timestamp => {
previousTimestamp = timestamp;
reqID = raf(rafLoop);
});
}
else caf(reqID);
};
const rafLoop = timestamp => {
animation(timestamp - previousTimestamp);
previousTimestamp = timestamp;
reqID = raf(rafLoop);
};
// Create animation function based on delta timestamp between animation frames
const animation = millisesonds => {
output.html(millisesonds);
};
$(document).ready(() => {
output = $('#output');
$('#start-stop').change(startStop);
$('#start-stop').prop('checked', true).trigger('change');
});
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>requestAnimationFrame</title>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
</head>
<body>
<label for="start-stop">Start/Stop: </label><input class="switch" type="checkbox" id="start-stop"><br>
<div id="output"></div>
</body>
See also https://codepen.io/sassano/pen/wvgxxMp for another sample with animation from which this snippet was derived.

Related

Making a clock that takes 2560ms to complete a revolution in JavaScript

I'm trying to make a clock for a Libet task - a cognitive task used by psychologists. By convention these clocks take 2560 ms to complete a revolution. Mine seems to be running quite a lot slower and I can figure out why.
I have made an example of the issue here: https://jsfiddle.net/Sumoza/re4v7Lcj/8/
On each iteration of a setInterval with a 1ms delay, I increase the angle of rotation of the hand by (Math.PI*2)/2560, i.e. 1/2560th of a circle in radians. So, incrementing one of these each ms should complete the circle in that number of ms. As you can see from the clock, this runs a fair bit slower. Can anyone shed any light as to why. Interestingly, *10 seems to look a lot closer to what I want - but that doesn't make much sense to me so I'm wary of the fix. Relevant JS from the fiddle below. Thanks for any help.
var time = 0;
var rad_tick = (Math.PI*2)/2560; //radians per tick: last number is ms per revolution
// Draw Clock
const clock = document.getElementById('clock')
const clock_ctx = clock.getContext('2d')
clock_ctx.translate(clock.width/2, clock.height/2);
radius = (clock.height/2) * 0.7;
function drawClock() {
clock_ctx.clearRect(-clock.width/2, -clock.height/2, clock.width, clock.height);
clock.style.backgroundColor = 'transparent';
clock_ctx.beginPath();
clock_ctx.arc(0, 0, radius, 0 , 2 * Math.PI);
clock_ctx.stroke();
}
drawClock();
// Draw Hand
const hand = document.getElementById('hand')
const hand_ctx = hand.getContext('2d')
hand_ctx.translate(hand.width/2, hand.height/2);
function drawHand(time){
hand_ctx.clearRect(-hand.width/2, -hand.height/2, hand.width, hand.height);
hand_ctx.beginPath();
hand_ctx.moveTo(0,0);
hand_ctx.rotate(time);
hand_ctx.lineTo(0, -radius*0.9);
hand_ctx.stroke();
hand_ctx.rotate(-time);
}
function drawTime(){
time+=rad_tick;//*10
drawHand(time)
}
var intervalId = setInterval(drawTime, 1);
Try this
var starttime = new Date().getTime();
function drawTime() {
var elapsed = new Date().getTime() - starttime;
var time = elapsed % 2560;
time = time * rad_tick;
console.log(elapsed + "->" + time);
drawHand(time)
}
Base things on the current time, and don't depend on setInterval to fire at the exact time you set it to fire. If there are things in-queue at the time that setInterval is supposed to fire, it will do those things in-queue first and only then run the function you've wired to setIterval (causing the delays you see --which build up more and more over time). Learn about the event loop and requestAnimationFrame.
Instead, get the time (freshly) prior to doing something, and calculate how much time has passed since the start time. Base your animations on these calculations. This way, even if there are slight delays, your last action will always sync things to the way they're supposed to look right now.
When you do it this way, you might lose some frames (skipping things the engine didn't have time to do), but it will likely complete much closer to the expected completion time.
The bottom line is, if you tell the browser to do more than it can do in a particular amount of time, there will be delays. However, you can skip frames of an animation to make things complete much closer to the expected completion time.
You ask setInterval to call your callback every 1ms, but does it actually call it every 1ms?
Try this code:
let cnt = 0;
setInterval(() => cnt++, 1);
setTimeout(() => { console.log(cnt); }, 1000);
For me, it prints something between 230 and 235. So looks like the actual (average) minimum interval for me is a bit over 4ms.
Adding on to Stig, since javascript isn't super fast when it comes to these things, it won't be super accurate. Using something like getTime() will allow proper timing. How about you call getTime in your drawTime function, so that around every millisecond, it will check the actual time and use that value.

Javascript keydown timing

I am working on a very time-sensitive application that uses key presses for user input. As I am talking milliseconds here, I went ahead and tried a version like this:
function start() {
//stim.style.display = "block";
rt_start = new Date().getTime();
response_allowed = 1;
}
function end() {
var t = rt_end - rt_start;
//stim.style.display = "none";
log.innerHTML = t;
i++;
if (i < iterations) {
setTimeout('start();', 1000);
}
}
var rt_start;
var rt_end;
var iterations = 100;
var i = 0;
var response_allowed = 0;
var stim;
var log;
$(document).ready(function() {
document.onkeydown = function(e) {
if (response_allowed == 1) {
rt_end = new Date().getTime();
response_allowed = 0;
end();
}
};
stim = document.getElementById('stim');
log = document.getElementById('log');
start();
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<div id="log"></div>
<img src="https://www.gravatar.com/avatar/cfefd93404e6b0eb3cde02b4b6df4e2b?s=128&d=identicon&r=PG&f=1" id="stim" />
And it works fine, usually sub-5ms timers (just holding down a key). But as soon as I modify the code to display the image (uncommenting the two lines), this slows down a lot to about 30ms.
Can someone point me into the direction why exactly this is the case and how to possibly avoid this additional delay?
Thanks
I would recommend using a DOMHighResTimeStamp where available (with a polyfill for browsers that don't provide it).
It's a high-resolution timestamp (designed with accurate measurement in mind) to be used (e.g.) with the Navigation Timing and Web Performance APIs (search for this in the Mozilla Developer Network, as I can't share more than two links within a single post).
The quick way to get a DOMHighResTimeStamp - much like you do with var ts = new Date().getTime(); to get a regular millisecond timestamp - is:
var ts = performance.now();
As I said above, take a look at the Web Performance API at MDN. It will be very helpful if your application is really time-sensitive.
EDIT:
About your snippet, it seems to me that if you hold a key down, you will be always limited to the resolution of the keydown event (which fires continuously, but not every milissecond). You can easily see this behavior if you press a character key down (continuously) with a text editor and check for how many times per second the character is written. This, I guess, is controlled via an OS setting.
You are also limited to the "drift" associated with setTimeout/setInterval. You see, setTimeout queues something for execution after a given delay, but it does not guarantee timely execution. It's a "best effort" scenario and, if the browser is busy doing something, it will drift significantly. Meaning: if you use a setTimeout to re-enable a response_allowed variable after 1 second, you can expect it to re-enable it after "about" (but not exactly) 1 second.

HTML5 Canvas game loop delta time calculations

I'm new to game development. Currently I'm doing a game for js13kgames contest, so the game should be small and that's why I don't use any of modern popular frameworks.
While developing my infinite game loop I found several articles and pieces of advice to implement it. Right now it looks like this:
self.gameLoop = function () {
self.dt = 0;
var now;
var lastTime = timestamp();
var fpsmeter = new FPSMeter({decimals: 0, graph: true, theme: 'dark', left: '5px'});
function frame () {
fpsmeter.tickStart();
now = window.performance.now();
// first variant - delta is increasing..
self.dt = self.dt + Math.min(1, (now-lastTime)/1000);
// second variant - delta is stable..
self.dt = (now - lastTime)/16;
self.dt = (self.dt > 10) ? 10 : self.dt;
self.clearRect();
self.createWeapons();
self.createTargets();
self.update('weapons');
self.render('weapons');
self.update('targets');
self.render('targets');
self.ticks++;
lastTime = now;
fpsmeter.tick();
requestAnimationFrame(frame);
}
requestAnimationFrame(frame);
};
So the problem is in self.dt I've eventually found out that first variant is not suitable for my game because it increases forever and the speed of weapons is increasing with it as well (e.g. this.position.x += (Math.cos(this.angle) * this.speed) * self.dt;..
Second variant looks more suitable, but does it correspond to this kind of loop (http://codeincomplete.com/posts/2013/12/4/javascript_game_foundations_the_game_loop/)?
Here' an implementation of an HTML5 rendering system using a fixed time step with a variable rendering time:
http://jsbin.com/ditad/10/edit?js,output
It's based on this article:
http://gameprogrammingpatterns.com/game-loop.html
Here is the game loop:
//Set the frame rate
var fps = 60,
//Get the start time
start = Date.now(),
//Set the frame duration in milliseconds
frameDuration = 1000 / fps,
//Initialize the lag offset
lag = 0;
//Start the game loop
gameLoop();
function gameLoop() {
requestAnimationFrame(gameLoop, canvas);
//Calcuate the time that has elapsed since the last frame
var current = Date.now(),
elapsed = current - start;
start = current;
//Add the elapsed time to the lag counter
lag += elapsed;
//Update the frame if the lag counter is greater than or
//equal to the frame duration
while (lag >= frameDuration){
//Update the logic
update();
//Reduce the lag counter by the frame duration
lag -= frameDuration;
}
//Calculate the lag offset and use it to render the sprites
var lagOffset = lag / frameDuration;
render(lagOffset);
}
The render function calls a render method on each sprite, with a reference to the lagOffset
function render(lagOffset) {
ctx.clearRect(0, 0, canvas.width, canvas.height);
sprites.forEach(function(sprite){
ctx.save();
//Call the sprite's `render` method and feed it the
//canvas context and lagOffset
sprite.render(ctx, lagOffset);
ctx.restore();
});
}
Here's the sprite's render method that uses the lag offset to interpolate the sprite's render position on the canvas.
o.render = function(ctx, lagOffset) {
//Use the `lagOffset` and previous x/y positions to
//calculate the render positions
o.renderX = (o.x - o.oldX) * lagOffset + o.oldX;
o.renderY = (o.y - o.oldY) * lagOffset + o.oldY;
//Render the sprite
ctx.strokeStyle = o.strokeStyle;
ctx.lineWidth = o.lineWidth;
ctx.fillStyle = o.fillStyle;
ctx.translate(
o.renderX + (o.width / 2),
o.renderY + (o.height / 2)
);
ctx.beginPath();
ctx.rect(-o.width / 2, -o.height / 2, o.width, o.height);
ctx.stroke();
ctx.fill();
//Capture the sprite's current positions to use as
//the previous position on the next frame
o.oldX = o.x;
o.oldY = o.y;
};
The important part is this bit of code that uses the lagOffset and the difference in the sprite's rendered position between frames to figure out its new current canvas position:
o.renderX = (o.x - o.oldX) * lagOffset + o.oldX;
o.renderY = (o.y - o.oldY) * lagOffset + o.oldY;
Notice that the oldX and oldY values are being re-calculated each frame at the end of the method, so that they can be used in the next frame to help figure out the difference.
o.oldX = o.x;
o.oldY = o.y;
I'm actually not sure if this interpolation is completely correct or if this is best way to do it. If anyone out there reading this knows that it's wrong, please let us know :)
The modern version of requestAnimationFrame now sends in a timestamp that you can use to calculate elapsed time. When your desired time interval has elapsed you can do your update, create and render tasks.
Here's example code:
var lastTime;
var requiredElapsed = 1000 / 10; // desired interval is 10fps
requestAnimationFrame(loop);
function loop(now) {
requestAnimationFrame(loop);
if (!lastTime) { lastTime = now; }
var elapsed = now - lastTime;
if (elapsed > requiredElapsed) {
// do stuff
lastTime = now;
}
}
This isn't really an answer to your question, and without knowing more about the particular game I can't say for sure if it will help you, but do you really need to know dt (and FPS)?
In my limited forays into JS game development I've found that often you don't really need to to calculate any kind of dt as you can usually come up with a sensible default value based on your expected frame rate, and make anything time-based (such as weapon reloading) simply work based on the number of ticks (i.e. a bow might take 60 ticks to reload (~1 second # ~60FPS)).
I usually use window.setTimeout() rather than window.requestAnimationFrame(), which I've found generally provides a more stable frame rate which will allow you to define a sensible default to use in place of dt. On the down-side the game will be more of a resource hog and less performant on slower machines (or if the user has a lot of other things running), but depending on your use case those may not be real concerns.
Now this is purely anecdotal advice so you should take it with a pinch of salt, but it has served me pretty well in the past. It all depends on whether you mind the game running more slowly on older/less powerful machines, and how efficient your game loop is. If it's something simple that doesn't need to display real times you might be able to do away with dt completely.
At some point you will want to think about decoupling your physics from your rendering. Otherwise your players could have inconsistent physics. For example, someone with a beefy machine getting 300fps will have very sped up physics compared to someone chugging along at 30fps. This could manifest in the first player cruising around in a mario-like scrolling game at super speed and the other player crawling at half speed (if you did all your testing at 60fps). A way to fix that is to introduce delta time steps. The idea is that you find the time between each frame and use that as part of your physics calculations. It keeps the gameplay consistent regardless of frame rate. Here is a good article to get you started: http://gafferongames.com/game-physics/fix-your-timestep/
requestAnimationFrame will not fix this inconsistency, but it is still a good thing to use sometimes as it has battery saving advantages. Here is a source for more info http://www.chandlerprall.com/2012/06/requestanimationframe-is-not-your-logics-friend/
I did not check the logic of the math in your code .. however here what works for me:
GameBox = function()
{
this.lastFrameTime = Date.now();
this.currentFrameTime = Date.now();
this.timeElapsed = 0;
this.updateInterval = 2000; //in ms
}
GameBox.prototype.gameLoop = function()
{
window.requestAnimationFrame(this.gameLoop.bind(this));
this.lastFrameTime = this.currentFrameTime;
this.currentFrameTime = Date.now();
this.timeElapsed += this.currentFrameTime - this.lastFrameTime ;
if(this.timeElapsed >= this.updateInterval)
{
this.timeElapsed = 0;
this.update(); //modify data which is used to render
}
this.render();
}
This implementation is idenpendant from the CPU-speed(ticks). Hope you can make use of it!
A great solution to your game engine would be to think in objects and entities. You can think of everything in your world as objects and entities. Then you want to make a game object manager that will have a list of all your game objects. Then you want to make a common communication method in the engine so game objects can make event triggers. The entities in your game for example a player would not need to inherent from anything to get the ability to render to the screen or have collision detection. You would simple make common methods in the entity that the game engine is looking for. Then let the game engine handle the entity as it would like. Entities in your game can be created or destroyed at anytime in the game so you should not hard-code any entities at all in the game loop.
You will want other objects in your game engine to respond to event triggers that the engine has received. This can be done using methods in the entity that the game engine will check to see if the method is available and if it is would pass the events to the entity. Do not hard code any of your game logic into the engine it messes up portability and limits your ability to expand on the game later on.
The problem with your code is first your calling different objects render and updates not in the correct order. You need to call ALL your updates then call ALL your renders in that order. Another is your method of hard coding objects into the loop is going to give you a lot of problems, when you want one of the objects to no longer be in the game or if you want to add more objects into the game later on.
Your game objects will have an update() and a render() your game engine will look for that function in the object/entity and call it every frame. You can get very fancy and make the engine work in a way to check if the game object/entity has the functions prior to calling them. for example maybe you want an object that has an update() but never renders anything to the screen. You could make the game object functions optional by making the engine check prior to calling them. Its also good practice to have an init() function for all game objects. When the game engine starts up the scene and creates the objects it will start by calling the game objects init() when first creating the object then every frame calling update() that way you can have a function that you only run one time on creation and another that runs every frame.
delta time is not really needed as window.requestAnimationFrame(frame); will give you ~60fps. So if you're keeping track of the frame count you can tell how much time has passed. Different objects in your game can then, (based off of a set point in the game and what the frame count was) determine how long its been doing something based off its new frame count.
window.requestAnimationFrame = window.requestAnimationFrame || function(callback){window.setTimeout(callback,16)};
gameEngine = function () {
this.frameCount=0;
self=this;
this.update = function(){
//loop over your objects and run each objects update function
}
this.render = function(){
//loop over your objects and run each objects render function
}
this.frame = function() {
self.update();
self.render();
self.frameCount++;
window.requestAnimationFrame(frame);
}
this.frame();
};
I have created a full game engine located at https://github.com/Patrick-W-McMahon/Jinx-Engine/ if you review the code at https://github.com/Patrick-W-McMahon/Jinx-Engine/blob/master/JinxEngine.js you will see a fully functional game engine built 100% in javascript. It includes event handlers and permits action calls between objects that are passed into the engine using the event call stack. check out some of the examples https://github.com/Patrick-W-McMahon/Jinx-Engine/tree/master/examples where you will see how it works. The engine can run around 100,000 objects all being rendered and executed per frame at a rate of 60fps. This was tested on a core i5. different hardware may vary. mouse and keyboard events are built into the engine. objects passed into the engine just need to listen for the event passed by the engine. Scene management and multi scene support is currently being built in for more complex games. The engine also supports high pixel density screens.
Reviewing my source code should get you on the track for building a more fully functional game engine.
I would also like to point out that you should have requestAnimationFrame() called when you're ready to repaint and not prior (aka at the end of the game loop). One good example why you should not call requestAnimationFrame() at the beginning of the loop is if you're using a canvas buffer. If you call requestAnimationFrame() at the beginning, then begin to draw to the canvas buffer you can end up having it draw half of the new frame with the other half being the old frame. This will happen on every frame depending on the time it takes to finish the buffer in relation to the repaint cycle (60fps). But at the same time you would end up overlapping each frame so the buffer will get more messed up as it loops over its self. This is why you should only call requestAnimationFrame() when the buffer is fully ready to draw to the canvas. by having the requestAnimationFrame() at the end you can have it skip a repaint if the buffer is not ready to draw and so every repaint is drawn as it is expected. The position of requestAnimationFrame() in the game loop has a big difference.

Javascript - Can't Adjust FrameRate - requestanimationframe

I start the loop
function gameLoop(){
update();
draw();
requestAnimFrame(gameLoop);
}
var requestAnimFrame = window.requestAnimationFrame ||
window.webkitRequestAnimationFrame ||
window.mozRequestAnimationFrame ||
window.oRequestAnimationFrame ||
window.msRequestAnimationFrame ||
function(callback) {
window.setTimeout(callback, 1000 / 1);
};
I can't adjust the frame rate. It is always really fast. Why can't I change it to 1 frame a second. I want to do this just for testing purposes.
Do I have to clear the canvas each time? It seems to work good without clearing it.
Thanks.
Here is a link to a fiddle for the complete code:
complete code
Thanks
rAF is locked to monitor's sync, typically 60 Hz, so we can't adjust the FPS for it in itself (browser may reduce FPS when tab is inactive or on batteries).
Also, what you are trying to change is the fallback for the poly-fill; that is: if rAF is not supported in the browser it will instead use setTimeout. However, most browsers nowadays do support rAF (even un-prefixed) so the setTimeout will never be used.
You can do two things:
Replace rAF in your loop by using setTimeout directly (when testing)
Example:
var FPS = 1;
function testLoop() {
... ordinary code
setTimeout(testLoop, 1000/FPS);
}
Throttle rAF by using a counter:
Example:
var framesToSkip = 60,
counter = 0;
function loop() {
if (counter < framesToSkip) {
counter++;
requestAnimationFrame(loop);
return;
}
/// do regular stuff
counter = 0;
requestAnimationFrame(loop);
}
MODIFIED FIDDLE HERE
There are most likely better ways to implement throttling, but I am trying to just show the basic principle. This will still run at full speed, 60 FPS, but your code will do minimal of operations and only when the counter has reached its count will it execute the main code.
You do not need to clear the canvas each time if what you draw next will cover previously drawn content, or if you want to keep it of course. You can also clear a portion to optimize further, if needed.
A bit late to the party, but here's how to get the benefit of RAF while also controlling frames/second.
Note: requestAnimationFrame now has a better way of doing things than by using the code pattern in my original 3 year old original answer ... see my update below for the new and improved way.
[Update: requestAnimationFrame now has a better way of throttling]
The new version of requestAnimationFrame now automatically sends in a current timestamp that you can use to throttle your code execution.
Here is example code to execute your code every 1000ms:
var nextTime=0;
var delay=1000;
function gameLoop(currentTime){
if(currentTime<nextTime){requestAnimationFrame(gameLoop); return;}
nextTime=currentTime+delay;
// do stuff every 1000ms
requestAnimationFrame(looper);
}
}
You should look at this article which gives a proper treatment of the subject.
http://creativejs.com/resources/requestanimationframe/
var fps = 15;
function draw() {
setTimeout(function() {
requestAnimFrame(draw);
// Drawing code goes here
}, 1000 / fps);
}
Here is the code I think you want, but in the original article it said used requestAnimationFrame, but here I am using requestAnimFrame. I think maybe it changed and you're supposed to use requestAnimFrame now. requestAnimationFrame did not work for me while requestAnimFrame did.
The way browsers and javascript work makes it difficult to set up a fixed frame rate. Say you want to do something every one second, like updating and drawing. One way of doing that could be to call window.setTimeout() with a setting of one second. But the problem is that this is not that reliable, even if you configure a callback every second you can't be sure all callbacks will be in time. A high processor load, for example, could make the callbacks arrive much later than they should. And even if the callbacks would be on time, you have no control of when the actual drawing to the screen will happen.
A better way of handling it is to accept the fact that you can't get a very precise timing of your calls, and instead, whenever you get a call, you calculate how much time has passed and act according to that. This means you'll let the system decide the frame rate, and you just take care of updating your animation or game depending on how much time that has passed.
requestAnimationFrame is a newer functionality supported by most browsers by now that is especially useful for games. It will be called every time the browser is ready to draw, which is good. Then you will know that the updates and drawing you are doing will happen right before the actual frame is drawn to screen.
Here's an example on how you could update your gameLoop to take the time difference into account.
var lastTimestamp = +new Date;
function gameLoop(timestamp) {
var now = +new Date;
var dt = now - lastTimestamp;
// dt is the amount of time in ms that has passed since last call.
// update takes this time difference (in seconds) and can then perform its
// updates based on time passed.
update(dt / 1000);
draw();
lastTimestamp = now;
requestAnimationFrame(gameLoop);
}
That's how requestAnimationFrame works. If you want a specific framerate, use setTimeout only.
Usually you would take a parameter, which is the current time. Compare it to the last frame's time to find out how far along the animation should move.
Quite handy js library if you need to control Framrate in javascript
https://github.com/aaronGoshine/Javascript-OnEnterFrame-Event-Manager/blob/master/index.html
requestAnimationFrame will run with the maximum achievable frame rate (up to 60 fps). This is because it will always give you the next animation frame.
The parameter you adjusted is only for the polyfill, which will be active if your browser has no implementation of requestAnimationFrame.
If you want to try painting at one second for testing purposes, try setInterval instead.

Moving elements with javascript

What are the best practices for moving elements with javascript?
Do you use timeouts or intervals?
Is it bad to have timed events for 10 milliseconds, or will it be precise?
Do you move pixel by pixel, or a certain fraction of the total distance?
If you use intervals, how do you stop the interval when the element is in position?
The last two times I've seen motion in javascript have been with jQuery and Raphael.js, neither of which I can understand the source code of. Are there some good tutorials or code examples anywhere? Is there a simple explanation of the methods jQuery uses?
There is a recent function called requestAnimationFrame which runs a function as soon as possible. This is a good practice since it has been made for animation purposes.
The way it works in terms of coding is the same as setTimeout, e.g. when the function finishes you call requestAnimationFrame.
In the function, you fetch the current time to see how the object should be positioned at that time.
You can cancel a pending function it with cancelRequestAnimationFrame, passing the return value of requestAnimationFrame.
Currently this is not cross-browser and the functions are vendor-prefixed, e.g. webkitRequestAnimationFrame for Chrome.
E.g.: http://jsfiddle.net/pimvdb/G2ThU/1/.
var div = document.getElementById('div');
var animation;
function move() {
var time = Math.round((new Date()).getTime() / 10) % 200;
div.style.left = time + 'px';
animation = requestAnimationFrame(move);
}
document.getElementById("start").onclick = function() {
animation = requestAnimationFrame(move);
}
document.getElementById("stop").onclick = function() {
cancelRequestAnimationFrame(animation);
}
Here you can find a good Javascript Animation tutorial:
http://www.schillmania.com/content/projects/javascript-animation-1
But what you said is right. Jquery Animate uses setTimeout, moving the object based in calculations of duration, position and easing.
Intervals are preferable, I believe, because you only set it once in the code rather than once per frame. It only needs to read the code once and reuse it several times, rather than reading it every time it is created.
10ms is a bit short. The computer can natively support intervals of about 16ms, then more precise timers can be used for faster intervals, however these are very power-consuming. IE9 supports both, depending on the computer's power settings, but ideally you shouldn't need anything faster than 50ms (20 FPS).
I like to move a fraction of the total distance, based on the time that has passed since the animation started. This way, no matter what the speed of the computer and browser, the animation will always take the exact same amount of time. Guaranteed.
Something like:
interval = setInterval(function() {
// do stuff
if( /*animation ended*/) clearInterval(interval);
},time);
jQuery is easy for some, but personally I find nothing beats writing it yourself in plain, old JS. Much easier to understand what's going on exactly, rather than relying on some framework to get it right for you.

Categories