In my game engine, there are objects that need to be updated periodically. For example, a scene can be lowering its alpha, so I set an interval that does it. Also, the camera sometimes needs to jiggle a bit, which requires interpolation on the rotation property.
I see that there are two ways of dealing with these problems:
Have an update() method that calls all other object's update methods. The objects track time since they were last updated and act accordingly.
Do a setInterval for each object's update method.
What is the best solution, and why?
setInterval does not keep to a clock, it just sequences events as they come in. Browsers tend to keep at least some minor amount of time between events. So if you have 10 events that all need to fire after 100ms you'll likely see the last event fire well into the 200ms. (This is easy enough to test).
Having only one event (and calling update on all objects) is in this sense better than having each object set it's own interval. There may be other considerations though but for at least this reason option 2 is unfeasible.
Here is some more about setInterval How do browsers determine what time setInterval should use?
The best way I have found out to make a good update() function and keeping a good framerate and less load is as following.
Have a single update() method which draws your frame, by looping some sort of queue/schedule of all drawable object his own update() function which are added to this update event queue/ schedule. (eventlistener)
This way you don't have to loop all objects which are not scheduled for a redraw/update (like menu buttons or crosshairs). And you don't have an over abundance of intervals running for all drawable objects.
I recommend using the update() method over the setInterval.
Also, I would guess that the timing on the several setintervals running would be unreliable.
Another possibility, depending on what other things are happening in your game, using a bunch of separate intervals could introduce race conditions in the counting and comparing of scoring, etc
The proposed algorithms proposed are not exclusive to the related method. That is, you can use setInteval to call all the update methods, or you can have each object update itself by repeatedly calling setTimeout.
More to the point is that a single timer is less overhead than multiple timers (of either type). This really matters when you have lots of timers. On the other hand, only one timer may not suit because some objects might need to be updated more frequently than others, or to a different schedule, so just try to minimise them.
An advantage with setTimeout is that the interval to the next call can be adjusted to meet specific scheduling requirements, e.g. if one is delayed you can skip the next one or make it sooner. setInterval will slowly drift relative to a consistent clock and one–of adjustments are more difficult.
On the other hand, setInteval only needs to be called once so you don't have to keep calling the timer. You may end up with a combination.
Related
If I animate changes in the DOM from JS (e.g. changing the value of a node's textContent from 1 to 500), would it be better to use requestAnimationFrame or requestAnimationFrame within a requestIdleCallback?
If you want to animate some code, then use only requestAnimationFrame, if you want to perform an action only when the browser has nothing else to do anymore, then use requestIdleCallback.
To simplify things, let's consider that both requestAnimationFrame and requestIdleCallback are setTimeout calls, with variables timeout arguments.
requestAnimationFrame would then be setTimeout(fn, time_until_next_screen_refresh). fn will be called right before the page is painted to the screen. This is currently the best timer we have to make animations since it ensures we'll only do the visual modifications only once per actual frame, at the speed of what the monitor is able to render, thus at every frame, if our code is fast enough.
requestIdleCallback would be setTimeout(fn, time_until_idle). fn will be called as soon as the browser has nothing more to do. This can be right away, or in a few event loops iterations.
So while both have a similar API, they provide completely different features, and the only viable one for doing an animation is requestAnimationFrame, since requestIdleCallback has basically no link whatsoever with the rendering.
I have animation that happens on dragmove.
However I don't want to waste cycles doing more calculations than I have to.
Essentially I want the dragmove events to only redraw at a reasonable animation rate.
In other words dragmove events come in as fast as they can however I only want to execute code as often as needed for smoothness for user.
So far the only solution I have come up with is to have a separate animation loop that does the redraw and ondragmove just sets the variables I need. Is there a more elegant way of doing this?
Think about it this way. The 30 FPS is your limitation. The events will go on their own time regardless your limitations.
So your idea is not that "un-elegant". I would say, it's the only way to go.
When ever you get a motion event, store it locally, if you already have it stored, override the old data(This is the ignoring part). From your 30 FPS loop, sample the motion event, if you got anything, than execute and destroy it.
This is about it. Pretty much your own words.
I'm doing some animation with Canvas now, and will be preparing a system for the artists to use to make interactive animations. I'll be using my own timeline as the scenes will be created from some declarative non-js input. My question is: what's the right way to handle the per frame callback and time measurement? In audio (my real-time background), the rule is that there should be only only one master callback method called by the audio system, and any other objects register with it somehow. And all time calculations are done by counting sample ticks of this callback so there is one and only one true clock source (no asking the system clock for anything, just count samples). I assumed this is what I should do in my canvas app but I'm seeing examples in books and sites where multiple objects use requestAnimationFrame, and then check the frame rate by using date objects to measure elapsed time. Am I off base in thinking one master callback is still the most elegant way to go? And can I rely on measuring time in frame ticks assuming I'm getting really 60fps if using requestAnimationFrame?
Your instinct is valid...route all your animation through one requestAnimationFrame loop to keep your animations well coordinated.
The current version of requestAnimationFrame in modern browsers automatically receives a highly accurate timestamp parameter based on the performance object. That timestamp is accurate to 1/1000th of a millisecond.
You cannot rely on counting the number of calls ("ticks") to the animation loop. The loop will be deferred if the prior loop's animation code has not completed or if the system is busy. Therefore, you are not guaranteed 60fps. You are guaranteed the browsers best efforts to get you 60fps.
Bottom line: requestAnimationFrame is not guarenteed to be called at 60fps intervals so you are left with 2 basic animation alternatives:
Use the timestamp to calculate an elaped time and position your objects based on elapsed time.
Increment a counter with each call to the animation loop and postion your objects based on the counter.
Currently, I am rendering WebGL content using requestAnimationFrame which runs at (ideally) 60 FPS. I'm also concurrently scheduling an "update" process, which handles AI, physics, and so on using setTimeout. I use the latter because I only really need to update objects roughly 30 times per second, and it's not really part of the draw sequence; it seemed like a good idea to save the remaining CPU for actual render passes, since most of my animations are fairly hardware intensive.
My question is one of best practices. setTimeout and setInterval are not particularly kind to battery life and CPU consumption, especially when the browser is not in focus. On the other hand, using requestAnimationFrame (or tying the updates directly into the existing render phase) will potentially enforce far more updates every second than are strictly necessary, and may stop updating altogether when the browser is not in focus or at other times the browser deems unnecessary for "animation".
What is the best course of action for updating, but not rendering content?
setTimeout and setInterval are not particularly kind to battery life and CPU consumption
Let's be honest: Neither is requestAnimationFrame. The difference is that RAF automatically turns off when you leave the tab. That behavior can be emulated with setTimeout if you use the Page Visibility API, though, so in reality the power consumption problems between the two are about on par if used intelligently.
Beyond that, though, setTimeout\Interval is perfectly appropriate for use in your case. The only thing that you may want to be aware of is that you'll be hard pressed to get it perfectly in sync with the render loop. You'll have cases where you may draw one too many times before your animation update hits, which can lead to minor stuttering. If you're rendering at 60hz and updating at 30hz it shouldn't be a big issue, but you'll want to be aware of it.
If staying perfectly in sync with the render loop is important to you, you could simply have a if(framecount % 2) { updateLogic(); } at the top of your RAF callback, which effectively limits your updates to 30hz (every other frame) and it's always in sync with the draw.
I am using setInterval(foo,ms) to carry out an animation. I really don't want to post all the code for the animation here as it spans multiple files. It's basically a bunch of images falling. Every second I call ctx.drawImage(img,...) while updating the coordinates to simulate gravity.
I have divided the canvas into two sections, one animation on the left and one on the right. When one of them is activated the frame rate is stable at 30 fps. If, however, I activate both of them, the performance plummets. This has nothing to do with overloading my computer, as I can cut the complexity of each animation by a factor of 10 and the problem persists. My guess is the setIntervals are interfering with each other.
My question is whether it is safe to execute more than one setInterval calls. Thanks
You can have many setIntervals() without issue but be aware that JS is fundamentally single-threaded (per-page). Multiple "Concurrent" threads are actually handled by jumping one thread about the code.
What this means is that timing won't be consistent - especially if one of the methods takes a considerable length of time to run.
As the others say, you can have as much as possible. Nevertheless, you should have as few as necessary for good performance. Maybe you can find a way to use only one intervala for both animations.
There might be a problem though if you use global variables. This could have an influence on the animations (maybe even on the performance, depends on what you use them for).
I would advise using setTimeout it could avoid performance issuse.
Take a look at this question setTimeout or setInterval?
It does a great Job of explaining the difference between the two and why you should you generally use setTimeout.
My question is whether it is safe to execute more than one setInterval calls
Short answer: yes, absolutely.
Yes its safe to have multiple setIntervals running.. There's no underlying performance issue with using setIntervals.. profile your own code, you'll almost certainly find the problem there.