requestAnimationFrame calling at more than 60FPS - javascript

I'm making a simple game and I'm having a problem where after minimizing the window for a few seconds, upon return the game runs at twice the framerate, and even more after that, adding 60 each time. My game loop looks like this:
function disp(){
update();
draw();
requestAnimationFrame(disp);
}
requestAnimationFrame(disp);
With both update and draw not including requestAnimationFrame. I have tried this on both firefox and chrome with the same results. Any ideas why this is happening? I've used this same method tons of times and this is the first time this has ever happened.
EDIT: You can find a fiddle of it at http://jsfiddle.net/5ttGs/
It's really simple so far as this kinda paused my progress. Click it a couple times and enjoy 10000+FPS gameplay

Fixed the problem with the help of cocco. Basically the onclick event called the disp function every time the canvas was clicked. Because the disp function had a requestAnimationFrame frame in it, it called it twice as much every second, resulting in the influx of frames. In order to fix I simply got rid of the disp in
canvas.addEventListener
function mouse_up() {
var matches = 0;
var overlap = 69;
mouse.up = false;
console.log("clicked", mouse.x,mouse.y);
disp();
}
You can find the result here: http://jsfiddle.net/5ttGs/

Related

How should I organize my update/draw logic when using requestAnimationFrame?

The JavaScript code for my HTML5 game has the following structure:
// <body onload="load()">
function load() {} // Load all images then call init()
function init() {} // Get all images ready for the game logic then call animate()
function animate() {} // Use requestAnimationFrame(), update() and drawing()
function update() {} // Update the game logic
function drawing() {} // Render the images on canvas
The issue lies inside animate(). I'm not finding any consistent sources around the web on how to organize requestAnimationFrame(), update() and drawing() in it.
I tried to elaborate it by myself, but the game did run in pratically any approach, like passing either animate(), update() or drawing() as an argument to requestAnimationFrame(), or having requestAnimationFrame() at either the beginning or the end of the function, or having any of these functions in any order, or one function inside another, etc.
That, however, doesn't mean anything is fine. Some of those arrangements result in issues that I'd find out only later, like when testing in a different computer or at a different frame rate. And then I have to go back to the code to try another approach.
So, how should I organize that? I'd appreciate if you can present me a proper algorithm, and even more if you have any good sources on teaching about it.
Use requestAnimationFrame to call animate repeatedly. animate calls update then draw. That's basically it. To have more control of time since you don't control the intervals exactly, it makes sense to pass the last time that animate was invoked. Maybe event the delta time that has passed since, makes more sense. Then you can use delta time to calculate distance given a speed and so on.
Here's an example of a game loop which is explained here:
var now,
dt = 0,
last = timestamp(),
step = 1/60;
function frame() {
now = timestamp();
dt = dt + Math.min(1, (now - last) / 1000);
while(dt > step) {
dt = dt - step;
update(step);
}
render(dt);
last = now;
requestAnimationFrame(frame);
}
requestAnimationFrame(frame);
There are many resources online. Here's a decent one for beginners https://www.sitepoint.com/quick-tip-game-loop-in-javascript/

Timer using frameRate and frame counter reliable?

I'm using p5js to program an animation with a timer countdown. I set my timer up to be updated each frame within an object that is being animated by the draw() function in sketch. Because of this, setInterval() will not work for what I'm trying to do.
I thought I could use the frameRate and a frame counter to decide if a second has passed:
this.updateTimer = function(){
this.framecounter++;
if(this.framecounter > frameRate()){
this.framecounter = 0;
//increment seconds
}
}
Is this reliable? I tested it against an actual timer and it seems to be about 1 second ahead after about 15 seconds. Is there a better way to do this by calling a function each frame? Thanks!
Why don't you just use the frameCount variable? More info is available in the reference.
You could also use the millis() function instead. Again, the reference is your best friend.
If you still can't get it working, please post a MCVE (or better yet, a CodePen or JSFiddle) that we can run to see the problem.

Javascript Timing for playing beeps

I am building a grid that will be playing sounds in HTML5/Javascript, and essentially I want it to keep repeating by looping through so I set:
window.setInterval(playMusic,INTERVAL);
This works all good and fine so far, but its when I try to add setTimeout events on each column:
function playMusic(){
for(var i=0;i<GRID_SIZE;i++){
setTimeout(playCol(i),INTERVAL/GRID_SIZE*i);
}
}
The reason I do it this way is so that from left to right it will play the sounds one after the other in increments. In the developer console I can see the individual timer events firing at the right times, but the sounds aren't being played. Then at the end of the interval all the sounds play at the same time. So there is something I'm not understanding about why each beep isn't playing one after the other like I want it to. Does setInterval stop the code from each timeout being run until the end of the interval? If so is there some work around for this where I can get the beeps to play at the right times?
You could make your playMusic a recursive function having your counter outside:
var i = 0;
function playMusic(){
if( i < GRID_SIZE ){
playCol(i);
i++;
setTimeout( playMusic, INTERVAL/GRID_SIZE );
}
}
Doing this way the playMusic() function will keep calling itself until the if condition is false. The i variable is updated and will be used to select a different sound for your playCol function.

Waiting for animations in a SetInterval gameloop

So my problem is I want to insert a custom animation but I don't want to ruin my gameloop.
My initial gameloop is stated here:
function init(){
if(!gameOver){
if(resetInterval>-1) clearInterval(resetInterval);
createBlock();
resetInterval = setInterval(moveDownCheck,gameSpeed);
}
}
My game is a tetris like game except instead of dropping tetriminos, I drop 2x1 blocks of different color. The moveDownCheck method checks if there are any blocks under my 2x1 block and then drops it by 1 row. This works fine until I have a block hanging without a block underneath since the 2x1 blocks are connected. I want to insert a drop animation that would take about a second and drop the hanging block by the same gameSpeed increment.
Here is my attempt that doesn't work:
function moveFallingDown(){
fbDownFlag = false;
clearInterval(resetInterval);
fbInterval = setInterval(function(){
fallingBlock.row++;
console.log("Dropped One Row");
},gameSpeed);
while(landscape[fallingBlock.row+1][fallingBlock.col]==0){
console.log("Waiting to Drop Falling Block");
}
clearInterval(fbInterval);
resetInterval = setInterval(moveDownCheck,gameSpeed);
}
Here I am attempting to wait for the function(){fallingBlock.row++;}, but my game just crashes and in the console "Dropped One Row" yet "Waiting to Drop Falling Block" will display thousands of times.
I guess I shouldn't be using a while loop here, but the only other solution I can think of would be a complete rework of my design, or nested setInterval methods which would just make my head hurt too much.
You can't do this with a while loop, you need to use a recursive function. window.setTimeout would work, however this seems like a good use case for requestAnimationFrame. Check it out here: https://developer.mozilla.org/en-US/docs/Web/API/window.requestAnimationFrame
You can use that to call your moveFallingDown method, and check how long has passed since the last animation frame to move your animation the right amount according to the game speed, by using the high precision timestamp passed to the requestAnimationFrame callback.
#Adrien Delessert's advice is correct but I'll just add that you're definitely confusing setTimeout and setInterval.
First of all you don't need a while loop.
setInterval IS a loop. So, if you wanted to use it you'd need to wrap (basically) the whole game in a method that moves the game forward (whatever that means) and pass that to setInterval.
However, what you're doing (and this is actually not a terrible approach) is to use it as a means to animate specific things. In that case you should have a recursive(ish) function that keeps calling setTimeout when it's done, if the conditions for another round of animation are met.
I haven't ever used requestAnimationFrame, but that does sound like a much more elegant approach to the problem.
The reason it's better is that it leverages the browser's own refresh timer (about 60 times per second) and will slot your animation frames in along with its own refresh.
So yes, you will listen for that callback and then react to it as necessary. If 60x per second is too fast, you'll need to put in a % based counter for how many of those frames you wish to actually react to.

How to tell what's causing slow HTML5 Canvas performance?

How can I tell if the canvas's slow performance is caused by the drawing itself, or the underlying logic that calculates what should be drawn and where?
The second part of my question is: how to calculate canvas fps? Here's how I did it, seems logical to me, but I can be absolutely wrong too. Is this the right way to do it?
var fps = 0;
setInterval(draw, 1000/30);
setInterval(checkFps, 1000);
function draw() {
//...
fps++;
}
function checkFps() {
$("#fps").html(fps);
fps = 0;
}
Edit:
I replaced the above with the following, according to Nathan's comments:
var lastTimeStamp = new Date().getTime();
function draw() {
//...
var now = new Date().getTime();
$("#fps").html(Math.floor(1000/(now - lastTimeStamp)));
lastTimeStamp = now;
}
So how's this one? You could also calculate only the difference in ms since the last update, performance differences can be seen that way too. By the way, I also did a side-by-side comparison of the two, and they usually moved pretty much together (a difference of 2 at most), however, the latter one had bigger spikes, when performance was extraordinarily low.
Your FPS code is definitely wrong
setInterval(checkFps, 1000);
No-one assures this function will be called exactly every second (it could be more than 1000ms, or less - but probably more), so
function checkFps() {
$("#fps").html(fps);
fps = 0;
}
is wrong (if fps is 32 at that moment it is possible that you have 32 frames in 1.5s (extreme case))
beter is to see what was the real time passes since the last update and calculate the realtimepassed / frames (I'm sure javascript has function to get the time, but I'm not sure if it will be accurate enough = ms or better)
fps is btw not a good name, it contains the number of frames (since last update), not the number of frames per second, so frames would be a better name.
In the same way
setInterval(draw, 1000/30);
is wrong, since you want to achieve a FPS of 30, but since the setInterval is not very accurate (and is probably going to wait longer than you say, you will end up with lower FPS even if the CPU is able to handle the load)
Webkit and Firebug both provide profiling tools to see where CPU cycles are being spent in your javascript code. I'd recommend starting there.
For the FPS calculation, I don't think your code is going to work, but I don't have any good recommendation :(
Reason being: Most (all?) browsers use a dedicated thread for running javascript and a different thread for running UI updates. If the Javascript thread is busy, the UI thread won't be triggered.
So, you can run some javascript looping code that'll "update" the UI 1000 times in succession (for instance, setting the color of some text) - but unless you add a setTimeout to allow the UI thread to paint the change, you won't see any changes until the 1000 iterations are finished.
That said, I don't know if you can assertively increment your fps counter at the end of the draw() routine. Sure, your javascript function has finished, but did the browser actually draw?
Check if you dont use some innerHTML method to debug your project. This can slow your project in a way you can't imagine, especially if you do some concatenation like this innerHTML += newDebugValues;
Or like desau said, profile your cpu usage with firebug or webkit inner debugger.

Categories

Resources