html5 game with canvas, performance problems on firefox (4) - javascript

currently i work on a little js/canvas game called "tunnel 2" (i'm pretty sure there's a well known year old version of this, but i know of none). you can try the game here. also, i'd recommend chrome.
so, i developed in google chrome, and it works fine, even on my crappy old machine. i get around ~30 fps. on my coworkers notebook it yields >100fps. so far, so good. safari seems to work well too.
next i tried it on firefox 4 beta 10 ... and i only get ~10 fps. but surely ff4 isn't that slow, right?
i started to investigate. here's my main loop:
// starts the game loop
this.run = function () {
this.draw();
var
t = this,
timeLastTurn,
timeThisTurn = (new Date()).getTime()-1;
var loop = function () {
timeLastTurn = timeThisTurn;
timeThisTurn = (new Date()).getTime();
// dt is the time difference between this turn and the last turn
var dt = timeThisTurn - timeLastTurn;
// player movement etc
t.turn(dt);
// draw game state
var res = t.draw();
// if there's no collision, game over
if (!res.collision)
t.setState(2);
// actually, there's a browser dependent minimum timeout that
// may vary. but even if it's more than 10ms - we don't care.
// game should run at the same speed (though not as smooth)
if (gameState == 1)
timer = window.setTimeout(loop, 5);
// just debug output
debug = dt;
}
// start the main loop
loop();
}
what i observed:
unsurprisingly, this.draw(); is by far the most expensive function, but it takes only some milliseconds (around 5, actually), on chrome ... and also on firefox. nowhere near the >100ms it would take for meager 10fps! the whole loop() call takes not much more either, on firefox it takes less than 10ms!
the difference can be seen if you investigate dt. it should be around time-loop()-takes+5ms timeout (or whatever the browser minimum timeout value is).
but on ff4 the value is closer to 180ms, aka the next timeout event fires in 170ms instead of 5ms! if you play a little longer, it goes up to ~800ms for a single frame (gc, for sure), then it's back to 180ms.
does anybody have an idea what the culprit could be?
is the GC to blame? on the one hand i don't think i create too many short lived variables, and hey, 150ms every time!? but of course it could be. is there an easy way to check this? the chrome profiler logs gc times (around 0.10%), but the firebug profiler doesn't.
also interesting: the game runs faster (~5fps) with firebug enabled.
add. info: using setInterval instead of setTimeout shouldn't and doesn't change anything.

I can confirm it's not working on FF 3.6.13 OS X.
While I was developing Snake JS I found a difference in setInterval behavior. You should really have a look at this:
var timer = setInterval(fn, 500)
// ...
timer = setInterval(fn, 500)
// Since I didn't use clearInterval() I now have two timers running in FF.
I see you're not using setInterval, but maybe it's something similar with setTimeout?

I have had major issues with some higher end canvas applications I've built and used when having to deal with firefox 6 and under. There are many issues that involve performance and just poorly or completely unsupported canvas capabilities in firefox. They did make a huge update in firefox 7 that improves many of the issues that you are probably noticing. It's kind of annoying, i need to support down to ff4 on a huge facebook canvas-based app that doesnt quite work that great in 6 and lower. I've done so many things to try and hack around the performance related issues and it's really difficult to find solutions for most things.

Related

How should i change the listener position in web audio

I am having troubles trying to update the context.listener's position (each requestAnimationFrame) in an application using Web Audio. I have made a test environment here with some variations but none of them seems to really work.
This is what i assume the correct approach is:
listener.positionX.value = pos.x;
listener.positionY.value = pos.y;
listener.positionZ.value = pos.z;
The issue i am having is that the sound is being completely distorted, and turning the source volume down does not help. (this may very well be a bug in Chrome OSX, since i don't remember having any issues when i made something similar before, which i ran on Chrome Windows)
I also tried doing this (these 2 lines should be exactly the same btw), but that didn't help either:
listener.positionX.setValueAtTime(pos.x, 0);
listener.positionX.setValueAtTime(pos.x, context.currentTime);
Then i tried the old and deprecated command to do this, and that sounds way better but still has slight distortion:
listener.setPosition(pos.x, pos.y, pos.z);
The one that seems to work best is to do a linear ramp:
listener.positionX.linearRampToValueAtTime(pos.x, context.currentTime + 0.1);
But doing a new ramp on every frame is not really the correct approach, since ongoing ramps are cancelled and i think it takes the value before the cancelled ramp as the starting value for the new ramp. Also: when i then NOT update the value (i added that as an option in that codepen), it seems to jump back to a previous value, which leads me to think that that is maybe also the cause for the major distortion i hear when doing the ver first approach (setting the value by positionX.value = pos.x)
Am i doing something wrong, or am i overlooking something? How should i correctly set the listener's position on every frame?
Using the .value setter and setPosition is supposed to instantly move the listener to that position. This will cause glitches. (Not all browsers have implemented this behavior so some will smoothly move somehow from the old to the new position.)
A linear ramp (or other automation) is the correct way to move from one location to the next.
I didn't hear any artifacts with Chrome 71 on a macbook using the built-in speakers. Perhaps I would if I used headphones?

Raphael: Gradual animation slowdown with simple infinite animation

This question is similar in spirit to this other question, asked two years ago: Why does Raphael's framerate slow down on this code?
I'm using Raphael 2.1.0 in Chromium 25 in the following way:
<html>
<head>
<title>Drawfun</title>
<style>
* {
margin: 0;
padding: 0;
}
</style>
</head>
<body>
<script src="raphael.js"></script>
<script>
var paper = Raphael(10, 50, 320, 200);
var anim = Raphael.animation({transform: "R360"}, 500).repeat(Infinity);
var rect = paper.rect(50, 40, 10, 20);
rect.attr("fill", "#f00");
rect.attr("stroke", "#fff");
rect.animate(anim);
</script>
</body>
</html>
Initially, the rectangle spins smoothly, as one would expect. After a minute or two, the rotation is running at ~15 FPS. After five or eight minutes, the animation is running at ~5 FPS.
Chrome CPU profiles indicate that as the animation becomes more choppy, the script is spending less and less time in (program) and more and more time in repush and eve.listeners.
The Chrome task manager doesn't indicate that there's a memory leak, either in the JS memory pool or in Chrome's, but does reveal that the page consumes more and more CPU over time.
When running that page in a recent version of Firefox, the animation becomes choppy much, much more quickly. These results have been verified on Linux and Windows, so it's not an OS issue :).
Does anyone have any insight into what might be wrong with either my code or Raphael's internals?
Okay, I know this isn't exactly the answer that anyone wants to hear (and is a debatable cop-out), but from the look of Raphael, and the reading of the comments above, I can't help but think that this is a garbage collection issue, and is the reason for the varying results across everyone's browsers. From a quick glance over the Raphael source, it looks like quite a bit of vars are declared or implemented in the process of animating a frame, on a per frame basis. I know for a fact that at least in Chrome's V8 engine, each var is declared in a trackable method and put on the heap, the delay in the framerate reduction only further indicates that the garbage collector is kicking into high mode to free up chunks of declared vars that are no longer in use. I would bet good money that if you were to move a lot of the declarations in the Raphael script into a higher scope (maybe even global, gasp~!), specifically during the animation sequences you will find a very much improved frame-rate over the course of the script.
I ran into this problem on a custom implementation of an adaptation to webgl, basically i was making webgl commands work without webgl enabled. The rasterizer of the pipeline I built had a very similiar problem as this, basically it would draw the frames starting at 68fps, but by the end of the test, would be down to 13fps or lower, and at 98% processor use. It wasn't until I cleaned up every single declaration that created new memory allocations out of the pipeline scope (and did a few more well researched speed up tricks having to do with variable lookups) that I was finally able to keep up and produce a well written rasterizer that could pump about 3-5MB/s of pixels to the screen at a time while keeping a 50-60fps rate.
Again, not sure if this is the answer you want or need, but I think it is the correct one. :( Sorry I couldn't help any more than that. Good luck :)

box2d what's the point of world.ClearForces()?

I'm using box2dweb version 2.1.a.3 (javascript, ported from flash), to create game. Some examples that I've got from Google used:
setInterval(
function(){
world.Step(1/60 , 10, 10)
world.ClearForces()
}
,1000/60)
I tried to remove the line world.ClearForces() but things behaved the same. I wonder what function ClearForces() does? What trouble can I get if I remove it like that ? Thanks!
I can't say for sure about the Flash and Javascript versions, but the ClearForces function was originally necessary in early versions of Box2D. Back then if you did ApplyForce to move an object, that force would remain in effect indefinitely, but now you need to do ApplyForce every time step if you want a continuous force. So effectively, the engine is calling this ClearForces for you every step. If you can take it out without changing anything you might as well.

Properly handling timing for HTML5 canvas engine

I'm working on a multiple projectile simulator for a college project and I'm wondering how to best setup timing in JavaScript rendering to a HTML5 canvas
I'm using an Euler integrator setup for physics and accuracy is very important for this project. The rendering is very bare bones
My question is how to best setup the timing for all this.
Right now I have:
The physics and other logic running in a function that loops using setTimeout() with a fixed time step
The rendering in another function that loops using a requestAnimationFrame() call (flexible time step)
These two loops run sort of simultaneously (I know JavaScript doesn't really support threads without Web Workers) but I don't want the rendering (currently running at a much higher FPS than needed) to be unnecessarily 'stealing' CPU cycles from the physics simulation, if you see what I mean.
Given that physics accuracy is most important here how would you recommend setting up the timing system? (Maybe using Web Workers would be useful here but I havent seen this used in other engines)
Thanks!
I'd suggest that you don't try to 'multithread' unless you're actually doing it, and even then, I wouldn't necessarily recommend it.
The best way to keep everything in synch is to have a single thread of execution. A single setTimeout loop of about 33ms seems to work ok for my games.
Also, in my experience at least, setTimeout offers a much more aesthetic experience than setInterval or requestAnimationFrame. With setInterval, Javascript tries to hard to 'catch up' when frames are delivered late, which makes animation frames inconsistent. With requestAnimationFrame, frames are skipped to ensure a smooth running game, which actually makes things harder, because your users aren't entirely sure their view is up to date at any given second.
One way would be to set an interval for processing physics, and once per x frames, render everything.
var physicsTime;
var renderFrequency;
var frameCount;
setInterval(function(){updateStuff()},physicsTime);
then in updateStuff()
function updateStuff(){
frameCount ++;
if (frameCount >= renderFrequency){
frameCount -= renderFrequency;
render();
}
physics();
}

Rendering and jaggering

I have a html 5 canvas using the 2d context. I am able to get up to 120 frames per second, but the rendering can be jagged, where the animation just jumps. I would like to know any ideas what may be causing it, especially with such a high (but pointless) frame rate? What are known ways or smoothing out animation as well?
The only thing that does come to mind, is the actual drawing is not being accounted for. So while the updating and drawing functions can be run quickly, the painting onto the canvas is stacked later. Which would then imply that I am not geting a true frames per second.
Although, I can get 120 frames per seconds that really means nothing. Because I am using setTimeout, I have not guarantees that the time will be constant, thus, when it does jagger, that is because the frame rate, for a moment, has dropped significantly.
However, there is an alternative in the works, that I managed to found. I'm a bit surprised how hard this was to find.
http://paulirish.com/2011/requestanimationframe-for-smart-animating/
https://developer.mozilla.org/en/DOM/window.mozRequestAnimationFrame
http://dev.chromium.org/developers/design-documents/requestanimationframe-implementation
From what I can understand, the function allows the browser to optimise for animations. In theory, this should give a more consistent frame rate, which should give smoother animations.
It is also quite interesting to compare how Chrome, Safari, Opera and Firefox draw. I mainly test on Chrome 14 dev and Mozilla Aurora 6.0a, and they way draw look very different. Chrome seems to be able to draw directly. Firefox seems to be piping the pixels, as if it's sending them one by one to be drawn.
Which leads me to Opera
http://www.scribd.com/doc/58835981/122/Double-Buffering-with-Canvas
http://www.felinesoft.com/blog/index.php/2010/09/accelerated-game-programming-with-html5-and-canvas/
turns out Webkit-based browsers and Gecko-based browsers use double buffers internally, that is, it collects all the drawing functions together and then draws them on the return of the function thread. If you have a main loop function, like update, it won't draw until that has returned. Opera, just draws them as the drawing functions are called, but it's not hard to implement double buffering. This is, supposably, another method of smoothing out the animation.
There is also another experimental feature that may help as well
http://badassjs.com/post/4064873160/webgl-2d-an-implementation-of-the-2d-canvas-context-in

Categories