Jump to content

Questions about requestAnimationFrame ?


vmars316

Recommended Posts

Hello & Thanks ,

From topic : http://w3schools.invisionzone.com/index.php?showtopic=55453#entry304554

I have lots of questions about requestAnimationFrame

 

So I decided to make this question a separate issue :

 

The code size is trimmed way down from the actual running game ,

to make it easy to follow .

 

Here is the updated function to start and stop animation :

var myGameArea = {
start: function() {
thrower.moveMe = false;
// interval = setInterval(updateGameArea, 5);
gid = requestAnimationFrame(updateGameArea);
},
clear: function() {
ctx.clearRect(0, 0, canvas.width, canvas.height);
},
stop: function() {
// clearInterval(this.interval);
cancelAnimationFrame(gid);
console.log('stop: function cancelAnimationFrame GID');
}
}

 

 

How come the 'stop' function doesn't work ?

<div id="buttons" class="center" align="center">
<button type="button" onclick="myGameArea.start()" ontouchstart="myGameArea.start()">Start</button>
<button type="button" onclick="myGameArea.stop()" ontouchstart="myGameArea.stop()">Stop</button>
</div>

 

And here is the game loop :

function updateGameArea() {
setTimeout(function() {
myGameArea.clear();
targetImgsCnt = 0;
if (idTag == "truth01" && truth01.visible) {
truth01.update();
}
targetImgsCnt = 1;
if (idTag == "lies01" && lies01.visible) {
lies01.update();
}
targetImgsCnt = 2;
if (thrower.visible) {
if (thrower.moveMe) {
thrower.update();
}
ctx.drawImage(targetImgs[targetImgsCnt], thrower.x, thrower.y, thrower.width, thrower.height);
thisIdTag = thrower.idTag;
visible = this.visible;
tripsMax = this.tripsMax;
tripsCnt = this.tripsCnt;
directionX = this.directionX;
thisx = this.x;
}
requestAnimationFrame(updateGameArea);
}, 1000 / framesPerSecond);
}
Also :
var gid;
var framesPerSecond = 17;

 

Here are my ?s :
How come the 'stop' function doesn't work ?
Why is it so slow ? I have tried several speeds , but always , soooo slow .
And this really puzzles me : I can increase the speed by simply clicking
the 'start' button repeatedly .
:) Though , I suppose I could add another 'start' button
and call it 'Increase Speed' button :)

 

I would rather use the methods (timestamp & performance.now) here :

and here :

But I can't piece it all together , to make it work .

I would like some help with this also .

 

Thanks

Edited by vmars316
Link to comment
Share on other sites

What's that call to setTimeout doing in updateGameArea? You're telling the browser that you want to run your function right before the browser is going to repaint the page, but the only thing that function does is schedule some code to run later. Why not run that code immediately, right before the browser updates the page? That's when you should be updating things on the page, when the browser is ready to show them. You use the timestamp passed to the callback function to figure out how much you need to move everything.

 

How come the 'stop' function doesn't work ?

Because it only cancels the very first frame, which already happened long before you press that button. You re-schedule the animation frame callback in the other function, but you don't save the ID for that to stop it.

 

 

Basically, you need to stop using setTimeout and setInterval, and rely only on requestAnimationFrame and the timestamp that gets passed to the callback to figure out how much everything needs to move.

Link to comment
Share on other sites

Like I said, you should use the timestamp that's passed as a parameter to your function.

function updateGameArea(timestampIsInHere) {
  console.log(timestampIsInHere);

It's an argument that's passed into your function by the browser. You can give it whatever name you want.

 

You should not use setTimeout or setInterval while using requestAnimationFrame, because requestAnimationFrame is intended to substitute those functions.

 

The concept of "frames per second" no longer exists when you use requestAnimationFrame. Each time the function is called you are given a timestamp telling you the current time with microsecond precision. You have to use that timestamp to determine how much to change the values in your program.

Link to comment
Share on other sites

Thanks All ,
Ah , finally , I get it .
I misread
var start = null;
var element = document.getElementById("SomeElementYouWantToAnimate");
element.style.position = 'absolute';
function step(timestamp) {
if (!start) start = timestamp;
var progress = timestamp - start;
element.style.left = Math.min(progress/10, 200) + "px";
if (progress < 2000) {
window.requestAnimationFrame(step);
}
}
window.requestAnimationFrame(step);

 

And thought I must use 'timestamp' in some way ,
until I started tinkering with the code above ,
turning it into this :
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
</head>
<body>
<canvas id="canvas" width="400" height="200" style="background-color:#992D2D"></canvas>
<br>
<button id="start_Me" onmouseup="startMe()" ontouchend="startMe()">Click to Start Me</button>
<br><br>
<button id="stop_Me" onmouseup="stopMe()" ontouchend="stopMe()">Click to Stop Me</button>
<script>
//
var gid;
var loopCount = 0;
var lastTimestamp = 0;
var LoopDuration = 0;
var durationAverage = 0;
//
var start = null;
var element = document.getElementById("stop_Me");
element.style.position = 'absolute';
function step(timestamp) {
if (loopCount < 1) {durationAverage =0; LoopDuration = 0;}
if (!start) start = timestamp;
var progress = timestamp - start;
element.style.left = Math.min(progress/10, 400) + "px";
// if (progress < 2000) {
loopCount += 1; // = loopCount + 1;
LoopDuration = timestamp - lastTimestamp;
if (loopCount < 11) {
console.log("LoopDuration = " + LoopDuration) ;
durationAverage = durationAverage + LoopDuration
}
lastTimestamp = timestamp;
if (loopCount > 399) {
stopMe();
window.location.reload();
}
gid = window.requestAnimationFrame(step);
// }
}
//window.requestAnimationFrame(step);
function startMe() {
gid = window.requestAnimationFrame(step);
console.log('start: gid = window.requestAnimationFrame(step);')
}
function stopMe() {
cancelAnimationFrame(gid);
console.log('stop: function cancelAnimationFrame gid');
console.log("durationsTotal = " + durationAverage) ;
durationAverage = durationAverage / 10.0;
console.log("durationAverage = " + durationAverage) ;
}
</script>
</body>
</html>

 

 

This works as intended , except for the 1st loopDuration
which reports as '2454857.5550000095' .
I am curious why that happens .
It seems that loopDuration runs between 16.xxx to 32.xxx .
Also , there is a 1 ==> 2 second delay
for this to happen :
window.location.reload();
Another anomaly (to me) is that when I run code online :
It runs fine except that when it encounters
if (loopCount > 399) {
stopMe();
window.location.reload();
}
It goes into a loop .
And I have to use TaskManager to shut it down .
Thanks
Link to comment
Share on other sites

That's because lastTimestamp starts off as 0.

 

You should have this at the beginning of your function:

function step(timestamp) {
  if(lastTimestamp == 0) {
    lastTimestamp = timestamp;
  }

This makes sure that on the first frame the delta time is zero so nothing changes.

Link to comment
Share on other sites

If you want to stop the loop, just don't call requestAnimationFrame().

if (loopCount > 399) { 
   window.location.reload();
} else {
  // Only called if loopCount < 400
  gid = window.requestAnimationFrame(step);
}
Link to comment
Share on other sites

Foxy Mod ,

Ah , much better :

liesandcowpies.com/javascript/measureTimestamp.html

 

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<!--
-->
</head>
<body>
<canvas id="canvas" width="400" height="200" style="background-color:#992D2D"></canvas>
<br>
<button id="start_Me" onmouseup="startMe()" ontouchend="startMe()">Click to Start Me</button>
<br><br>
<button id="stop_Me" onmouseup="stopMe()" ontouchend="stopMe()">Click to Stop Me</button>
<br><br>
<p id="traceMsg"></p>
<script>
//
var gid;
var loopCount = 0;
var lastTimestamp = 0;
var loopDuration = 0;
var durationSums = 0;
var durationAverage = 0;
var oneTraceLine = '';
//
var start = null;
var element = document.getElementById("stop_Me");
element.style.position = 'absolute';
function step(timestamp) {
if (lastTimestamp == 0) {
lastTimestamp = timestamp;
}
if (!start) start = timestamp;
var progress = timestamp - start;
element.style.left = Math.min(progress / 10, 400) + "px";
loopCount += 1;
loopDuration = timestamp - lastTimestamp;
if (loopCount < 12) {
writeTraceLog("loopCount = " + loopCount + " , loopDuration = " + loopDuration);
durationSums = durationSums + loopDuration
}
lastTimestamp = timestamp;
if (loopCount > 399) {
stopMe();
} else {
// Only called if loopCount < 400
gid = window.requestAnimationFrame(step);
}
}
//window.requestAnimationFrame(step);
function startMe() {
gid = window.requestAnimationFrame(step);
writeTraceLog('start: gid = window.requestAnimationFrame(step);')
}
function stopMe() {
cancelAnimationFrame(gid);
writeTraceLog('stop: function cancelAnimationFrame gid');
writeTraceLog("durationSums = " + durationSums);
durationAverage = durationSums / 10;
writeTraceLog("durationAverage = " + durationAverage);
// window.location.reload();
}
function writeTraceLog(oneTraceLine){
document.getElementById("traceMsg").innerHTML += (oneTraceLine + "<br>");
}
</script>
</body>
</html>

 

 

Thank You very much !

Link to comment
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
×
×
  • Create New...