I have a function that gets called with setInterval() like this:
canvasInterval = setInterval(updateCGoL, (1000/this.frameRate)|0);
I am allowing the user to specify the frames per second (with limitations, only non-NaN values after parseInt() as Math.max(Math.min( user input , 30), 1)). Even if it runs at 30 frames per second I am pretty sure it is completing its work before the next frame. My questions though are:
What happens if it does not finish its work within the amount of time
I gave it?
Is there a way to test if it did not finish its work before the next
frame if this is a problem?
Edit: (Copy / pasted from comments) If the limit of my function is 20 frames per second (to compute) but I have setInterval running at 30 frames per second will it instead run at 20? (As opposed to two functions running at the same time)
Javascript is single-threaded, so your calls to set interval will be added to a queue. They will execute sequentially, but if your functions take longer than your actual interval you will work beyond the expected finish time of your setInterval calls.
Use requestAnimationFrame instead..This will not hog your cpu.
In simple words,setInterval does not have the ability to interact with our cpu and unnecessarily it ends up making queues of your calls and wasting a lot of cpu cycles
RequestAnimationFrame works smartly and allows you to manipulate the frame rate without burdening yor browser.
I just answered a similar question.
LINK-->Replace setinterval by RAF
It has all the links a begineer should follow!!!
Instead of clearing the interval use cancelAnimationFrame
Just a snippet on how you should approach things.Definately a better solution.
// This makes sure that there is a method to request a callback to update the graphics for next frame
requestAnimationFrame =
window.requestAnimationFrame || // According to the standard
window.mozRequestAnimationFrame || // For mozilla
window.webkitRequestAnimationFrame || // For webkit
window.msRequestAnimationFrame || // For ie
function (f) { window.setTimeout(function () { f(Date.now()); }, 1000/60); }; // If everthing else fails
var cancelAnimationFrame = window.cancelAnimationFrame || window.mozCancelAnimationFrame;//for cancellation
// some code here
var progress = 0
function doSomething(){
if (progress != 100){
// do some thing here
var myAnimation = requestAnimationFrame(doSomething)
}else{
// dont use clearInterval(interval) instead when you know that animation is completed,use cancelAnimationFrame().
window.cancelAnimationFrame(myAnimation);
}
I don't know about what's your frameRate. If it is entered by user, do some validation there. so you have better value.
Better try this
var timeRate = this.frameRate? 1000/parseInt(this.frameRate) : 0;
canvasInterval = setInterval(updateCGoL, timeRate);
Related
How to get a better animation, dinamically, even when browser is busy or idle, for different devices which have different hardware capacity.
I have tried many ways and still cannot find the right way to make the game to display a better animation.
This is what i tried:
var now;
var then = Date.now();
var delta;
window.gamedraw = function(){
now = Date.now();
delta = now - then;
if(delta > 18){
then = now - (delta % 18);
game_update();
}
}
window.gameloop = setInterval(window.gamedraw,1);
18 is the interval value to update the game, but when browser is busy this interval is not good, and it needs to lower. How to get a better animation dinamically, even when browser is idle or busy ?
I suppose that the interval value is the problem, because if interval is lower then game animation is very fast, if this value is 18 then game animation is good but not when browser is busy, and I do not have idea how to change it dinamically.
To get a smooth animation, you must :
• Synchronise on the screen.
• Compute the time elapsed within your game.
• Animate only using this game time.
Synchronizing with the screen is done by using requestAnimationFrame (rAF).
When you write :
requestAnimationFrame( myCalbBack ) ;
You are registering myCalbBack to be called once, the next time the screen is available to draw on.
( If you know about double buffering (canvas are always double-buffered), this time is the next time the GPU will swap the draw buffer with the display buffer. )
If, on the other hand, you don't use rAF but a interval/timeout to schedule the draws, what will happen is that the draws won't get actually displayed until next display refresh. Which might happen (on a 60Hz display) any time from right now to 16.6 ms later.
Below with a 20ms interval and a 16 ms screen, you can see that the images actually displayed will be alternatively 16ms away OR 2*16ms away - never 20, for sure-. You just can't know, from the interval callback, when the actual draw will show. Since both rAF and Intervals are not 100% accurate, you can even have a 3 frames delta.
So now that you are on sync with the screen, here's a bad news : the requestAnimationFrame does not tick exactly regularly. For various reasons the elapsed time in between two frames might change of 1ms or 2, or even more. So if you are using a fixed movement each frame, you'll move by the same distance during a different time : the speed is always changing.
(expl : +10 px on each rAF,
16.6 display -->> rAF time of 14, 15, 16 or 17 ms
--> the apparent speed varies from 0.58 to 0.71 px/ms. )
Answer is to measure time... And use it !
Hopefully requestAnimationFrame provides you the current time so you don't even have to use Date.now(). Secondary benefit is that this time will be very accurate on Browsers having an accurate timer (Chrome desktop).
The code below shows how you could know the time elapsed since last frame, and compute an application time :
function animate(time) {
// register to be called again on next frame.
requestAnimationFrame(animate);
// compute time elapsed since last frame.
var dt = time-lastTime;
if (dt<10) return;
if (dt >100) dt=16; // consider only 1 frame elapsed if unfocused.
lastTime=time;
applicationTime+=dt;
//
update(dt);
draw();
}
var lastTime = 0;
var applicationTime = 0;
requestAnimationFrame(animate);
Now last step is to always use time inside all you formulas. So instead of doing
x += xSpeed ;
you'll have to do :
x += dt * xSpeed ;
And now not only the small variations in between frames will be taken into account, but your game will run at the same apparent speed whatever the device's screen (20Hz, 50Hz, 60 Hz, ...).
I did a small demo where you can choose both the sync and if using fixed time, you'll be able to judge of the differences :
http://jsbin.com/wesaremune/1/
You should use requestAnimationFrame instead of setInterval.
Read this article or this one.
The latter one is in fact exactly discussing your approach (with the delta time), and then introduces the animation frame as a more reliable alternative.
The first article is really a great resource. For starters, with your interval of 18 ms you're apparently aiming for something close to 60 fps. This is in fact the default for requestAnimationFrame, so you don't need to write anything special:
function gamedraw() {
requestAnimationFrame(gamedraw); //self-reference
game_update(); //your update logic, propably needs to handle time intervals internally
}
gamedraw(); //this starts the animation
If you want to set the update interval explicitly, you can do so by wrapping the requestAnimationFrame inside a setInterval, like this:
var interval = 18;
function gamedraw() {
setTimeout(function() {
requestAnimationFrame(gamedraw);
game_update(); //must handle time difference internally
}, interval);
}
gamedraw();
Note that the game_update() function must keep track of when it was last called in order to e.g. move everything twice as far as normal in case a frame had to be skipped.
Actually, this means you could (and probably should) refactor your game_update() function to take the time that has actually passed as an argument instead of determining that internally. (There's no functional difference, it just is better, clearer code IMO because it doesn't hide the timing magic.)
var time;
function gamedraw() {
requestAnimationFrame(gamedraw);
var now = new Date().getTime(),
dt = now - (time || now);
time = now; //reset the timer
game_update(dt); //update with explicit and variable time step
}
gamedraw();
(Here I dropped the explicit frames again.)
Still, I urge you to read the first article because it also deals with cross-browser issues that I haven't gotten into here.
You should use requestAnimationFrame. It will queue up a callback to run on the next time the browser renders a frame. To achieve constant updating, call the update function recursively.
var update = function(){
//Do stuff
requestAnimationFrame(update)
}
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.
In fact, when I use
setTimeout(a(),60);
setTimeout(a(),120);
setTimeout(a(),180);
setTimeout(a(),240);
It is supposed to be 60ms gap between calling's of a functions.
But it isnt, especially when it is fired during page loading or animating elements. In fact that gap gets even 2x longer when browser 'has hard work to do'. In some cases it can be visible easly.
The point of question is - is there any other way to synchronize events or functions in time in javascript?
The timing in setTimeout(a(),60) in simple terms translates to I will run this function no earlier than 60ms, but if I get busy it could be later than that.
Therefore, setTimeout does not promise when the execution will take place, only that it will take place sometime after the given time in milliseconds.
So to answer your question, no there is no way to guarantee execution time with setTimeout but you can load your script after the DOM has loaded so that JavaScript is not busy anymore loading other things. In jQuery you can use the $(document).ready() function for that purpose.
Read this article by John Resig for more information about timing in JavaScript: http://ejohn.org/blog/how-javascript-timers-work/
Try this:
setTimeout(a,60);
setTimeout(a,120);
setTimeout(a,180);
setTimeout(a,240);
Note that the function doesn't have the ()s.
In your particular case, setInterval() might work:
var count = 0, interval = setInterval(function() {
count += 1;
if (count > 4) {
clearInterval(interval);
} else {
a();
}
}, 60);
Note that jQuery has a built-in animation feature that uses the different, better approach of simply treating an animation as a function of time and frequently checking the clock, so an unexpected delay would simply make the animation a bit less smooth.
If a game is running at 177FPS or 22FPS, how is the player movements calculated? I'm trying to do this in Javascript:
setInterval(update, 0);
function update() {
player_x++;
}
Problem is if the player will be move faster/slower according to the frame rate. How would I solve this?
I highly recommend using requestAnimationFrame when available (which will get you the best frame rate possible in modern browsers) and setTimeout when not. Then base your players position on the time since the animation started:
// Anonymous function used to make variables declared inside it not global
// This avoids conflicts in case variables with the same names are used
// in other scripts
(function(){
// This checks for the requestAnimationFrame in each browser and store the first
// it finds into requestAnimationFrame. If none are found it uses setTimeout
// Attempting 60 frames per second.
// It's taken from Paul Irish's blog: http://paulirish.com/2011/requestanimationframe-for-smart-animating/
// and you can use it as is
var requestAnimationFrame = (function(){
return window.requestAnimationFrame ||
window.webkitRequestAnimationFrame ||
window.mozRequestAnimationFrame ||
window.oRequestAnimationFrame ||
window.msRequestAnimationFrame ||
function(callback){
setTimeout(function(){ callback((new Date).getTime()); }, 1000/60);
};
})();
var speed = 60; // pixels per second
// This is used so that we only divide by 1000 once instead of every frame
var calc = speed/1000;
// Store the current time in start_time
var start_time = (new Date).getTime();
// This function is self invoking. It is wrapped in parenthesis and called immediately
// time is passed in by requestAnimationFrame
(function draw(time){
// Calculate the new x position based on the current time
var pos = (time - start_time)*calc;
// Update the player's position
// In my JSFiddle I update the style.left of a div
player_x = pos;
// Now that this frame is done request another frame.
// draw will be called again before that frame is rendered
requestAnimationFrame(draw);
})();
})();
JSFiddle
Try using a timer function instead, so that the player moves based on time and not changes in frames...
The distance is equal to speed (constant) and time. Depending on the framerate (in Hz) the time t = 1 / framerate will vary.
To put this into code: measure the time between subsequent frames and use that time to calculate the distance.
Sometimes a better idea is to have a background thread (in JavaScript you can use setInterval() as suggested by CezarisLT and use constant time. However in practice you still need to measure the time between subsequent invocations because setInterval() is not guaranteed to run exactly at scheduled time (long running functions, high CPU usage).
BTW your code is overly verbose and won't compile:
setInterval(update, 0)
function update() {
player_x++;
}
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.