I have a mini game where user is required to click rapidly on a button in a given time (8 seconds). There is a countdown (to the mili seconds). While i was trying on an android touchscreen (using android table OS6 i think), i am experiencing the timer to slow down while rapidly clicking. Is there a way to avoid or improve the performance for this? This is the countdown timer which i assume could do an improvement? Not sure does GSAP helps to replace the setinterval in this matter?
function countDownNow(){
// var initial = 800;
var initial = 8000;
var count = initial;
var counter; //10 will run it every 100th of a second
function timer() {
if (count <= 0) {
console.log(done)
clearInterval(counter);
return;
}
count--;
displayCount(count);
}
function displayCount(count) {
var res = count / 100;
//document.getElementById("countdown").innerHTML = res.toPrecision(count.toString().length) ;
ctx.clearRect(0, 0, canvas.width, canvas.height);
ctx.fillStyle = '#fff';
ctx.font = '90px "Conv_DIN-Bold"';
var text_title = "first";
ctx.fillText(res.toPrecision(count.toString().length), 15, canvas.height / 2 + 35);
}
counter = setInterval(timer, 10);
displayCount(initial);
}
HTML
<!-- Skeleton html -->
<div id="countdown"></div>
<!-- this clickme button is the button where its being used for user to rapidly click it-->
<div class="clickme"></div>
As said in my answer to your last post, setIntervals should be avoided, especially when you have to use them for precise timing and especially when you're already using GSAP. There's no reason to use them if you're using GSAP.
For functionality like you have here there is no reason why it should ever perform poorly. The two biggest performance hits are 1) using a bunch of setIntervals and 2) having functions within functions.
When you have functions within functions they are created every time the function is ran. If those outer functions are called more than once, you are often times creating the inner functions more times than you need to. To avoid doing that, move the inner functions outside of the outer functions and use parameters to pass in variables if need be. (in terms of memory management, a minor improvement would be to move variables that don't change outside of the functions as well but that's much less important to do)
Another note is that the intervals that you are creating are all going to overwrite each other but you're not killing off the old ones. So you should kill off any that were created before since the output of them won't be seen (because it's covered by the new ones) anyway.
Altogether you get something like this: demo.
Related
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/
Somehow i did my research and found out javascript is single threaded !.
I've been trying to figure out , how to make animation via for loop in javascript.
This is what i've done so far.
I'm trying to draw an object on a canvas using javascript. It run the loop it doesn't go step by step. It's just run the loop and draw once instead of 10 times and it ignores the timeout function.
In a single instance , it drew (P/S. Ignore the multiple version cause i was testing it so i removed the context.clearRect(0, 0, context.canvas.width, context.canvas.height); :
JS:
// down button click
down.onclick = function() {
if (!imgLoaded) return;
flag=false;
setTimeout(function() {
for(var i = 0; i < 15 ; i++) {
posY += 10;
context.drawImage(img, posX, posY );
}}, 9);
// call next step
That's not the way setTimeout works. The way you wrote it, setTimeout calls its first parameter one time, after 9 ms, then loops with no delay.
You could use the setInterval function (don't forget to removeInterval after the 15th iteration) if you want to be called a regular interval.
Note that in both case (setTimeout, setInterval), given delay is only indicative.
What you might want to use is the Window.requestAnimationFrame() function, which is the usual way to do animation in the browser.
So, maybe total brainfart here. The syntax for setInterval() is pretty clear. Do something every x miliseconds. How is this best translated to using the requestAnimationFrame() ?
I have about 300 objects and each is supposed to perform an animation sequence at a certain interval (every 8, 6, 2, etc seconds)? How can I best accomplish this using requestAnimationFrame() which gets called ~60 times a second? There is probably an easy answer, I just, for the life of me, can't figure it out.
To force requestAnimationFrame to stick to a specific FPS you can use both at once!
var fps = 15;
function draw() {
setTimeout(function() {
requestAnimationFrame(draw);
// Drawing code goes here
}, 1000 / fps);
}
A little weird, but noth the most confusing thing in the world.
You can also use requestAnimationFrame not with FPS but with elapsed time in order to draw objects that need to be updated based on the time difference since the last call:
var time;
function draw() {
requestAnimationFrame(draw);
var now = new Date().getTime(),
dt = now - (time || now);
time = now;
// Drawing code goes here... for example updating an 'x' position:
this.x += 10 * dt; // Increase 'x' by 10 units per millisecond
}
These two snippets are from this fine article, which contains additional details.
Good question by the way! I don't think I've seen this answered on SO either (and I'm here way too much)
requestAnimationFrame is pretty low level, it just does what you already said: roughly gets called at 60fps (assuming the browser can keep up with that pace). So typically you would need to build something on top of that, much like a game engine that has a game loop.
In my game engine, I have this (paraphased/simplified here):
window.requestAnimationFrame(this._doFrame);
...
_doFrame: function(timestamp) {
var delta = timestamp - (this._lastTimestamp || timestamp);
for(var i = 0, len = this.elements.length; i < len; ++i) {
this.elements[i].update(delta);
}
this._lastTimestamp = timestamp;
// I used underscore.js's 'bindAll' to make _doFrame always
// get called against my game engine object
window.requestAnimationFrame(this._doFrame);
}
Then each element in my game engine knows how to update themselves. In your case each element that should update every 2, 6, 8 seconds needs to keep track of how much time has passed and update accordingly:
update: function(delta) {
this.elapsed += delta;
// has 8 seconds passed?
if(this.elapsed >= 8000) {
this.elapsed -= 8000; // reset the elapsed counter
this.doMyUpdate(); // whatever it should be
}
}
The Canvas API along with requestAnimationFrame are rather low level, they are the building blocks for things like animation and game engines. If possible I'd try to use an existing one like cocos2d-js or whatever else is out there these days.
I have two instances of setInterval. Each is triggering a different function ( these two functions are title quarterNoteFunc & eighthNoteFunc ) at repeated intervals. The interval for quarterNoteFunc is 600 milliseconds. The interval for eighthNoteFunc is 300 milliseconds. Both of these functions each trigger a different audio file at repeat intervals hence creating a basic music rhythm. The rhythm between the two function calls eventually "drifts" in Google Chrome making the rhythm between the two sounds dissolve. My question is:
It seems that even though browser based timing is garbage their should be a way to create some kind of "hard" timing reference so that the sounds are locked even if the "global" timing gets offset hence keeping the sounds in sync. I thought assigning the same variable milliseconds (code below) would inhibit this - but I was wrong.
The (abbreviated) code looks like this
milliseconds = 600;
quarterNote = setInterval(quarterNoteFunc, milliseconds);
eighthNote = setInterval(eighthNoteFunc, milliseconds/2);
Probably the best way to do this is to have a single, always active 1/8 note interval, then call the quarter-note every other tick:
// wrapped in a closure to allow for a private tickCount variable
// alternatively, you could use a more advanced object with start/stop methods, etc.
(function() {
var tickCount = 0,
tick = function() {
eighthNoteFunc();
if(tickCount %2 == 0) {
quarterNoteFunc();
}
tickCount++;
};
setInterval(tick, 300);
})();
This ensures that the methods are always called on the same tick. You can also expand this to support half notes (tickCount % 4 == 0) and whole notes (tickCount % 8 == 0).
This interested me, so I decided to create a fully-working sample (except, using animated backgrounds instead of audio): http://jsfiddle.net/SycBm/
This allows you to see the eighth-, quarter-, and half- notes ticking in sync, as well as start & stop the timer, and independently enable or disable the notes.
Enjoy!
As I understand it, usage of the JS requestAnimationFrame API is intended for cases where the framerate isn't in need of being controlled, but I have a use case where it's essential that a <canvas> only updates at a certain fps interval that may be anywhere between 1 and 25 (between 1 and 25 frames per second, that is). Can I then somehow still effectively use rAF to get at the optimizations it offers?
This question has similarities to mine, but the accepted answer there made close to zero sense to me in the context of that question.
I have two possible solutions for this. The first one involves using a while loop to halt the execution of the script for a specified delay before calling requestAnimationFrame from within the callback. In the example where I saw this, it effectively limited the fps of the animation, but it also seemed to slow down the entire tab. Is this still actually a good solution? The second alternative, as mentioned in the question I linked to above, calls requestAnimationFrame within a setInterval. To me that seems a bit convoluted, but it could be that's the best option?
Or is there a better alternative to accomplish this?
Yoshi's answer is probably the best code solution to this problem. But still I'll mark this answer as correct, because after some research I basically found that my question was invalid. requestAnimationFrame is really meant to keep frame rates as high as possible, and it optimizes for scenarios where animation is meant to be kept consistent and smooth.
Worth noting though is that you don't need requestAnimationFrame to get optimization (even though rAF was touted as a great performance booster) since browsers still optimize regular drawing of a <canvas>. For example, when a tab isn't focused, Chrome for one stops drawing its canvases.
So my conclusion was that this question was invalid. Hope this helps anyone who was wondering something similar to me.
This is just a proof of concept.
All we do is set our frames per second and intervals between each frame. In the drawing function we deduct our last frame’s execution time from the current time to check whether the time elapsed since the last frame is more than our interval (which is based on the fps) or not. If the condition evaluates to true, we set the time for our current frame which is going to be the “last frame execution time” in the next drawing call.
var Timer = function(callback, fps){
var now = 0;
var delta = 0;
var then = Date.now();
var frames = 0;
var oldtime = 0;
fps = 1000 / (this.fps || fps || 60);
return requestAnimationFrame(function loop(time){
requestAnimationFrame(loop);
now = Date.now();
delta = now - then;
if (delta > fps) {
// Update time stuffs
then = now - (delta % fps);
// Calculate the frames per second.
frames = 1000 / (time - oldtime)
oldtime = time;
// Call the callback-function and pass
// our current frame into it.
callback(frames);
}
});
};
Usage:
var set;
document.onclick = function(){
set = true;
};
Timer(function(fps){
if(set) this.fps = 30;
console.log(fps);
}, 5);
http://jsfiddle.net/ARTsinn/rPAeN/
What you can do, though I don't really know if this is really any better is:
render to an invisible context with requestAnimationFrame
update a visible context with setInterval using a fixed fps
Example:
<canvas id="canvas"></canvas>
<script type="text/javascript">
(function () {
var
ctxVisible = document.getElementById('canvas').getContext('2d'),
ctxHidden = document.createElement('canvas').getContext('2d');
// quick anim sample
(function () {
var x = 0, y = 75;
(function animLoop() {
// too lazy to use a polyfill here
webkitRequestAnimationFrame(animLoop);
ctxHidden.clearRect(0, 0, 300, 150);
ctxHidden.fillStyle = 'black';
ctxHidden.fillRect(x - 1, y - 1, 3, 3);
x += 1;
if (x > 300) {
x = 0;
}
}());
}());
// copy the hidden ctx to the visible ctx on a fixed interval (25 fps)
setInterval(function () {
ctxVisible.putImageData(ctxHidden.getImageData(0, 0, ctxHidden.canvas.width, ctxHidden.canvas.height), 0, 0);
}, 1000/40);
}());
</script>
Demo: http://jsfiddle.net/54vWN/