My HTML5/JavaScript game (for the windows store) is lagging constantly! I have used barely any resources and I have used gsap for animating the bullets and mines. For example: http://203.81.207.90/default.html in Chrome enabling everything under rendering shows the lag immediately (the background and mines lag the most).
the problem is the tiny interval (10ms) used in most setInterval()'s.
increasing the interval should help and since javascript is a single threaded language, using lots of timers basically queue's them (performance issue) try using less timers by putting multiple functions in single timers
That's not lag. It's the browser trying to scroll when you press the right arrow key. Put e.preventDefault() at the start of your keydown handler.
Related
From my tests, and from searching to find out more about the problem, my best guess is that css animations may be using a different physical clock from the one used to stream audio. If so perhaps the answer to this is that it can't be done, but am asking in case I am missing anything.
It is for my online metronome here.
It is able to plays notes reasonably accurately in response to an event listener for the css animationiteration event. The eventlistener is set up using e.g.
x.addEventListener("animationstart",playSoundBall2);
See here.
However if I try to synchronize the bounce with the sample precise timing of the AudioContext method that's when I run into problems.
What I do is to use the first css callback just to record the audio context time for the css elapsed time of 0. Then I play the notes using the likes of:
oscillator.start(desired_start_time);
You can try it out with the option on the page: "Schedule notes in advance for sample-precise timing of the audio" on the page here.
You can check how much it drifts by switching on "Add debug info to extra info" on the same page.
On my development machine it works fine with Firefox. But on Edge and Chrome it drifts away from the bounce. And not in a steady way. Can be fine for several minutes and then the bounce starts to slow down relative to the audio stream.
It is not a problem with browser activity - if I move the browser around and try to interrupt the animation the worst that happens is that it may drop notes and if the browser isn't active it is liable to drop notes. But the ones it plays are exactly in time.
My best guess so far, is that it might be that the browser is using the system time, while the audiocontext play method is scheduling it at a precise point in a continuous audio stream. Those may well be using different hardware clocks, from online searches for the problem.
Firefox may for some reason be using the same hardware clock, maybe just on my development machine.
If this is correct, it rather looks as if there is no way to guarantee to precisely synchronize html audio played using AudioContext with css animations.
If that is so I would also think you probably can't guarantee to synchronize it with any javascript animations as it would depend on which clocks the browser uses for the animations, and how that relates to whatever clock is used for streaming audio.
But can this really be the case? What do animators do who need to synchronize sound with animations for long periods of time? Or do they only ever synchronize them for a few minutes at a time?
I wouldn't have noticed if it weren't that the metronome naturally is used for long periods at a time. It can get so bad that the click is several seconds out from the bounce after just two or three minutes.
At other times - well while writing this I've had the metronome going for ten minutes in my Windows 10 app and it has drifted, but only by 20-30 ms relative to the bounce. So it is very irregular, so you can't hope to solve this by adding in some fixed speed up or slow down to get them in time with each other.
I am writing this just in case there is a way to do this in javascript, anything I'm missing. I'm also interested to know if it makes any difference if I use other methods of animation. I can't see how one could use the audio context clock directly for animation as you can only schedule notes in the audio stream, can't schedule a callback at a particular exact time in the future according to the audio stream.
I simply want to restart a canvas on a website. I do not want to reload the page, so the restart has to be done dynamically. Problem : after few restarts the animation gets slower and the memory increases.
Actually i face a more complex situation : I use a javascript framework to load pages, MeteorJS with IronRouter. Changing the URL only changes the DOM (nodes are removed) but the 'page' is not really left. So i thought that coming back to my page with the canvas can be assimilated to a dynamic canvas restart, since i have no solution to that too.
That is why i describe the problem from two points of view (same problem on both) :
first a simple page where a button asks the canvas to restart
then applying the solution to MeteorJS with IronRouter and try to come back on my page many times.
Note : my canvas content is some WebGL (in ThreeJS).
1. Deleting and re-initializing canvas dynamically.
In this case i face those two problems :
animation not smooth
memory increase. To be precise :
(source: hostingpics.net)
Page loaded, playing with canvas / 2. Restarting the canvas 30-40 times (i did not stop restarting so i do not know why the increase is not linear) / 3. Playing with canvas / 4. Closing the tab (reloading the page only frees a small fraction of what has been mobilized)
Few questions on SO yet asked how to solve those issues, but reproducing the solutions partially solves the problem. I have read two main things :
the canvas-related parts (nodes, variables, functions) have to be cleaned from the DOM (That is something Meteor does. But in this first part it stays relevant and yet is not enough to prevent the issues).
if requestAnimationFrame has been called, it needs to get assigned to a variable so cancelAnimationFrame(variable) can stop it. That indeed seems to prevent the frame rate drop. While memory stays high, at least the movements remain fluent.
With those solutions the memory problem still happens.
Here is an example : http://codepen.io/Astrak/pen/RNYLxd
2. In MeteorJS : i cannot get this partial solution work.
Here is what i wrote in my app, with id=requestAnimationFrame(myAnimation) declared globaly :
Template.myTemplate.destroyed=function(){
cancelAnimationFrame(id);
document.body.removeChild(document.querySelector('canvas'));//useful in Meteor ?
};
Despite those instructions, my animation gets slow much quicker with MeteorJS than in the previous example : it becomes unusable after 3-4 page change. And same memory problem.
Thanks for every comment and answer and happy coding :)
Related questions :
Performance drop on multiple restart of scene from threejs
Performance drops when trying to reset whole scene with Three.js
How do we handle webgl context lost event in Three.js
Pause, resume and restart Canvas animations with JS
How can I restart my function?
JavaScript restart canvas script
For memory problem, I'd recommend Chrome's javascript profiler - you can compare snapshots before and after canvas is reloaded and see which objects are not freed from memory.
Problem usually comes from event handlers and/or using closures. If you, for example, hook a function to window object's onresize event, all objects referenced in this function will stay in memory as long as window exists. So always remove event handlers from global objects if you want to refresh page content without actually refreshing the browser session.
Similar with closures. They will create link between function's scope and referenced variables preventing GC to collect them. Check this https://www.meteor.com/blog/2013/08/13/an-interesting-kind-of-javascript-memory-leak
Im developing an app for android devices, and found that samsung galaxy S4 specifically, has extremely poor performance when app/web page uses canvas.
Odd thing is, that its not always the case.
I have tested 2 sample apps.
http://ie.microsoft.com/testdrive/Performance/FishIETank/Default.html
and
http://ie.microsoft.com/testdrive/Graphics/TouchEffects/Default.html
the first one works fine, and outperforms my Nokia (which is dual core) and is expected. However, the other demo, is almost completely unresponsive and framerate is close to 1, where as all other devices render it fine.
Since the first app runs well and the other one doesnt, it beggs the question, why ?
First one has no event listeners, where as the other one has touch listeners. Could touchmove be the cause instead of canvas...or is that demo using some canvas features that the other one isnt, and thus has poor performance.
I have read lots of topics about this issue, and none seem to have answer. Most are many months old...so i thought ill make a new topic.
Is there any way to solve the canvas issue on Samsung S4 ... and potentially other android devices running 4.2.x.
If any StackOverflow users here has S4, can you test both demos and confirm my observations?
I strongly suspect this is not a Canvas specific issue, but a requestAnimationFrame issue. The first animation does not attempt to use requestAnimationFrame, but the second does, in this file on line 206.
Android Browser on firmwares <= 4.2 does not support requestAnimationFrame, and instead uses setTimeout, dividing one second by specified frame rate in Hz, which executes renders in the normal event loop.
setTimeout does not execute at the exact time in milliseconds requested, but enqueues the event in the loop at the time specified. If the event loop is hung by other javascript on the page, or the single-core device decides something else is more important, the runtime is very vulnerable to de-prioritization without the requestAnimationFrame API, and the callbacks enqueued using setTimeout will stutter and bunch. More on setTimeout resolution and timing.
Unfortunately, you are at the mercy of the event queue if you are (1) going with this Canvas-based approach and (2) on a platform that does not support requestAnimationFrame. Here is the reference table for what browsers support the feature.
Cheers!
How can I control the rendering loop frame rate in KineticJS? The docs for Kinetic.Animation show a frame rate being passed to the render callback, and Kinetic.Tween seems to have no frame rate logic, but I don't see anyway to force, say, a 30fps when 60fps is possible.
Loads of context for the curious follows, but the question is that simple. If anyone reads on, other advice is welcome. If you already know the answer, don't waste your time reading on!
I'm developing a music app that combines some DOM-based GUI controls (current iteration using jQuery Mobile) and Canvas-based GUI controls (using KineticJS). The latter involve some animation. Because the animated elements are triggered by music playback, I'm using Kinetic.Tween to avoid the complexity of remembering how long a given note has been playing (which Kinetic.Animation would require doing).
This approach works great at 60fps in Chrome (on a fast machine) but is just slow enough on iOS 6.1 Safari (iPad 2) that manipulating controls while animations are happening gets a little janky. I'm not using WebGL (unless KineticJS or Chrome does this by default for canvas?), and that's not an option when I package for native UIWebView.
As I'm getting beyond prototype into wanting to make more committed tech decisions, I see the following options, in order of perceived goodness:
Figure out how to cap the frame rate. Because my animations heavily use alpha fades but do not involve motion, I believe I could get away with 20-30fps and look fine. Could also scale this up on faster devices.
Don't respond immediately to touch inputs, but add them to a queue which I poll at a constant interval and only use the freshest for things like touchmove. This has no impact on my non-interactive animated elements, but tackles the problem from the other direction, trying to reduce the load of user interaction. This would require making Kinetic controls static and manually tracking touch coordinates (not terrible effort if it actually helped).
Rewrite DOM-based GUI to canvas-based (KineticJS); rewrite WebAudio-based engine to HTML5 audio; leverage CocoonJS or Ejecta for GPU-acceleration. This means having to hand-code stuff like file choosers and nav menus and such (bad). Losing WebAudio is pretty serious as it eliminates features like DSP effects and very fine-grained, low-latency timing (which is working just fine on an iPad 2).
Rewrite the app to separate DOM based GUI and WebAudio from Canvas-based elements, leverage CocoonJS. I'm not sure if/how well this works out, but the fact that CocoonJS passes JavaScript code as strings between the 2 components makes me very skittish about how solid this idea is. It's probably doable, but best case I'm very tied to CocoonJS moving forwards. I don't like architecting this way, but maybe it's not as bad as it sounds?
Make animations less juicy. This is least good not because of its design impact but because, as it is, I'm only animating ~20 simple shapes at any time in my central view component, however they include transparency and span an area ~1000x300. Other components like sliders are similarly bare-bones. In other words, it's not very juicy right now.
Overcome severe allergy to Objective-C; forget about the browser, Android, and that other mobile OS. Have a fast app that performs natively and has shiny Apple-approved widgets. My biggest problem with this approach is not wanting to be stuck in Objective-C reality for years, skillset-wise. I just don't like it.
Buy an iPad 3 or later. Since I already am pretending Android doesn't exist (I don't have any devices to test), why not pretend no one still has iPad 2? I think this is passing the buck -- if I can get acceptable performance on iPad 2, I will feel confident about the app's performance as I add more features.
I may be overlooking options or otherwise naive about how to tackle this. Some would say what I'm trying to build is just silly. But it's working pretty well just not ready for prime time on the iPad 2.
Yes, you can control the Kinetic.Animation framerate
The Kinetic.Animation sends in a frame object which has a frame.time property.
That .time is a running timer that you can use to throttle your animation speed.
Here's an example that throttles the Kinetic.Animation: http://jsfiddle.net/m1erickson/Hn3cC/
var lastTime;
var frameDelay=1000;
var loop = new Kinetic.Animation(function(frame) {
var time = frame.time
if(!lastTime){lastTime=time;}
var elapsed = time-lastTime;
if(elapsed>=frameDelay){
// frameDelay has expired, so animate stuff now
// set lastTime for the next loop
lastTime=time;
}
}, layer);
loop.start();
Working from #markE's suggestions, I tried a few things and found a solution. It's ultimately not rocket science, but sharing what I figured out:
First, tried the hack of doubling Tween durations and targets, using a timer to stop them at 50%. This kinda sorta worked but was hard to get to look good and was pretty error prone in coding bogus targets like negative opacity or height or whatnot.
Second, having read the source to Tween and looked at docs again for Animation, decided I could locally use Animation instances instead of Tween instances, and allow the closure scope to hang onto the relevant note properties. Eventually got this working smoothly and finally realized a big Duh! which is that throttling the frame rate of several independently animating things does not in any way throttle the overall frame rate.
Lastly, decided to give my component a render() method that calls itself in a loop with requestAnimationFrame, exits immediately if called before my clamp time, and inside render() I update all objects in the Kinetic canvas and call layer.drawScene(). Because there is now only one animation, this drops frame rate to whatever I need and the app is fast on iPad 2 (looks exactly the same to my eyes too).
So Kinetic is still helping for its higher level canvas API, and so far my other control widgets are still easy code using Kinetic to handle user input and dragging, now performing much better as the big beast component is not eating up the CPU.
The short answer to my original question is that no, you can't lock the overall frame rate for very complex animations, but as Mark said, you can for anything that fits in a single Animation instance.
Note that I could have still used Animation without giving it a layer or explicitly calling any draw() methods, but since I'd still have to write all the logic to determine individual element's current visual state, there was no gain to doing this. What would be very useful would be if Tween could accept a parameter to not automatically render. This would simplify code like mine, as I could shorthand the animation on individual objects but still choose when to actually do the heavy lifting of rendering everything. Seeing how much this whole exercise gained in performance on the iPad 2, might be worth adding this option to the framework.
I've seen a couple of questions asking about this, but they're all over three years old and usually end by saying theres not much of a way around it yet, so im wondering if anything's changed.
I'm currently working on a game that draws onto a canvas using an interval that happens 60 times a second. It works great on my iphone and PC, which has a faily decent graphics card, but I'm now trying it on a Thinkcentre with intel i3 graphics, and I notice some huge screen tearing:
http://s21.postimg.org/h6c42hic7/tear.jpg - it's a little harder to notice as a still.
I was just wondering if there's any way to reduce that, or to easily enable vertical sync. If there isnt, is there somethingthat I could do in my windows 8 app port of the game?
Are you using requestAnimationFrame (RAF)? RAF will v-sync but setTimeout/setInterval will not.
http://msdn.microsoft.com/library/windows/apps/hh920765
Also, since 30fps is adequate for your users to see smooth motion, how about splitting your 60fps into 2 alternating parts:
"calculate/update" during one frame (no drawing)
and then do all the drawing in the next frame.
And, get to know Chrome's Timeline tool. This great little tool lets you analyze your code to discover where your code is taking the most time. Then refactor that part of your code for high performance.
[ Addition: More useful details about requestAnimationFrame ]
Canvas does not paint directly to the display screen. Instead, canvas "renders" to a temporary offscreen buffer. “Rendering” means the process of executing canvas commands to draw on the offscreen buffer. This offscreen buffer will be quickly drawn to the actual display screen when the next screen refresh occurs.
Tearing occurs when the offscreen rendering process is only partially complete when the offscreen buffer is drawn on the actual display screen during refresh.
setInterval does not attempt to coordinate rendering with screen refresh. So, using setInterval to control animation frames will occasionally produce tearing .
requestAnimationFrame (RAF) attempts to fix tearing by generating frames only between screen refreshes (a process called vertical synching). The typical display refreshes about 60 times per second (that’s every 16 milliseconds).
With requestAnimationFrame (RAF):
If the current frame is not fully rendered before the next refresh,
RAF will delay the painting of the current frame until the next screen refresh.
This delay reduces tearing.
So for you, RAF will likely help your tearing problem, but it also introduces another problem.
You must decide how to handle your physics processing:
Keep it in a separate process—like setInterval.
Move it into requestAnimationFrame.
Move it into web-workers (the work is done on a background thread separate from the UI thread).
Keep physics in a separate setInterval.
This is a bit like riding 2 trains with 1 leg on each—very difficult! You must be sure that all aspects of the physics are always in a valid state because you never know when RAF will read the physics to do rendering. You will probably have to create a “buffer” of your physics variables so they always are in a valid state.
Move physics into RAF:
If you can both calculate physics and render within the 16ms between refreshes, this solution is ideal. If not, your frame may be delayed until the next refresh cycle. This results in 30fps which is not terrible since the eye still perceives lucid motion at 30fps. Worst case is that the delay sometimes occurs and sometimes not—then your animation may appear jerky. So the key here is to spread the calculations as evenly as possible between refresh cycles.
Move physics into web workers
Javascript is single-threaded. Both the UI and calculations must run on this single thread. But you can use web workers which run physics on a separate thread. This frees up the UI thread to concentrate on rendering and painting. But you must coordinate the background physics with the foreground UI.
Good luck with your game :)