• Announcements

    • khawk

      Download the Game Design and Indie Game Marketing Freebook   07/19/17

      GameDev.net and CRC Press have teamed up to bring a free ebook of content curated from top titles published by CRC Press. The freebook, Practices of Game Design & Indie Game Marketing, includes chapters from The Art of Game Design: A Book of Lenses, A Practical Guide to Indie Game Marketing, and An Architectural Approach to Level Design. The GameDev.net FreeBook is relevant to game designers, developers, and those interested in learning more about the challenges in game development. We know game development can be a tough discipline and business, so we picked several chapters from CRC Press titles that we thought would be of interest to you, the GameDev.net audience, in your journey to design, develop, and market your next game. The free ebook is available through CRC Press by clicking here. The Curated Books The Art of Game Design: A Book of Lenses, Second Edition, by Jesse Schell Presents 100+ sets of questions, or different lenses, for viewing a game’s design, encompassing diverse fields such as psychology, architecture, music, film, software engineering, theme park design, mathematics, anthropology, and more. Written by one of the world's top game designers, this book describes the deepest and most fundamental principles of game design, demonstrating how tactics used in board, card, and athletic games also work in video games. It provides practical instruction on creating world-class games that will be played again and again. View it here. A Practical Guide to Indie Game Marketing, by Joel Dreskin Marketing is an essential but too frequently overlooked or minimized component of the release plan for indie games. A Practical Guide to Indie Game Marketing provides you with the tools needed to build visibility and sell your indie games. With special focus on those developers with small budgets and limited staff and resources, this book is packed with tangible recommendations and techniques that you can put to use immediately. As a seasoned professional of the indie game arena, author Joel Dreskin gives you insight into practical, real-world experiences of marketing numerous successful games and also provides stories of the failures. View it here. An Architectural Approach to Level Design This is one of the first books to integrate architectural and spatial design theory with the field of level design. The book presents architectural techniques and theories for level designers to use in their own work. It connects architecture and level design in different ways that address the practical elements of how designers construct space and the experiential elements of how and why humans interact with this space. Throughout the text, readers learn skills for spatial layout, evoking emotion through gamespaces, and creating better levels through architectural theory. View it here. Learn more and download the ebook by clicking here. Did you know? GameDev.net and CRC Press also recently teamed up to bring GDNet+ Members up to a 20% discount on all CRC Press books. Learn more about this and other benefits here.
Sign in to follow this  
Followers 0
capn_midnight

[web] JavaScript game loop

17 posts in this topic

I have a number of uses for a "game loop" in javascript, either for old Dynamic HTML stuff or new HTML5 stuff, be it games or business apps. I'm not happy with the performance of setInterval (or its retarded brother, setTimeout) and was wondering if y'all knew of a better way. Currently, I have something along the lines of:


function gameLoop()
{
// do the per-iteration stuff
}

var timer;
function init()
{
if(timer == null)
{
// do the one-time setup stuff
timer = setTimeout(gameLoop, [[1]]);
}
}

function stop()
{
if(timer != null)
{
clearTimeout(timer);
timer = null;
}
}




and then usually call init() via the page onload event: <body onload="init()">

setInterval currently accounts for most of my performance problems on the Moto Droid.
0

Share this post


Link to post
Share on other sites
You probably want to make the interval larger than 1 millisecond. With that short a space you may as well run it in a while loop -- it's going to destroy your performance. Try to figure out what framerate you would want the game to run and set the interval there (eg: 33 is about 30 fps).

FWIW, you might want to use setInterval instead of setTimeout. Using Timeout will vary your loop times slightly by waiting the interval after each loop iteration, whereas Interval will work from the previous loop execution.
0

Share this post


Link to post
Share on other sites
It looks like he's only using the 1ms timeout for the initialization. This way he can load resources in the background, avoiding hanging the browser.

I don't know of another way to throttle your app in javascript without setTimeout/setInterval. You could busy wait in your game loop if it were invoked via setTimeout, but that'd kill the battery.

EDIT:
Actually I'd recommend the opposite of what jolid said about using setInterval. I'd recommend using setTimeout at the end of each game loop iteration to reschedule. This way you can adjust the timeout duration dynamically to achieve your desired frame rate.
0

Share this post


Link to post
Share on other sites
Okay, further discussion time.

I've created a little bit of a performance test on this. The output format is "<min of all runs>, <last five runs>, <max of all runs>". The timing is setup so that I'm measuring as close to the "outside of my code" time as possible. So my timing code is essentially

set current_time to NOW()
calculate difference from last time
do output
set last_time to NOW()
loop

so the time covered between last_time and current_time is pretty much all setTimeout or setInterval's time.

When I run this in Google Chrome 6 beta, I get numbers like "1, 5,5,5,5,5, 6" for both setTimeout and setInterval.

Internet Explorer 8: "15, 15,15,16,16,16, 16", again on both setTimeout and setInterval.

Android Browser on the Motorola Droid: "0, 1,9,10,13,13, 40". Both loops are similar again, though there is a very noticeable lack of stability in the numbers, whereas Chrome and IE had settled into an fairly unvarying stream of numbers.

Anyway, the upshot of this is that HTML5 cannot yet be used for even 30FPS animation on Android Browser yet, as it frequently dips above the 33ms threshold, just to return to the next frame update, say nothing about how much processing can be done during that update.


(NOTE: The comparable order of magnitude between the IE and Android numbers is something I've noticed before. Yes, IE8 on a 2.33GHz Core 2 Duo machine often feels similar to Android Browser on a 550MHz Arm Cortex. These numbers aren't the total story, but I've experienced other situations where this has come up. Shameful, shameful, shameful)
0

Share this post


Link to post
Share on other sites
Unfortunately, I think you're out of luck on this one. No browser that I'm aware of has a way to let you force rendering to go through without finishing your current thread of execution, which as far as I know can only be done by using setTimeout or setInterval. If Android isn't getting back to you as fast as you'd like, your only recourse may be to bug Android's (and/or Android's browser's) developers on Google Groups.

Your best bet might actually be to create a benchmark of some kind that's actually meaningful, then get results of it posted to some tech blogs. Nothing gears up browser developers like seeing they're behind on a widely-publicized benchmark (IE's developers are excluded here, as nothing gears them up).
0

Share this post


Link to post
Share on other sites
When I saw the title of this topic I was wondering if my article on the Opera developers page would actually fit... and it turns out I wasn't wrong.

setTimeout() is really unreliable for timing purposes (since the browser will take the delay as a minimum wait, not an exact delay), you need to look for some other timer to rely upon. For example, you can use the current date - every time you create a new Date object, it'll contain the current date, down to the millisecond. You can compare its value with the time of the last frame to determine if you need to run a new frame or not. This method works reliable on every browser I tested, even Explorer (which is notorious for bad timing with such low rates). You'll still need setTimeout() to keep the game loop running (without resorting to hanging the browser with a busy loop), but you won't rely on it to do the timing anymore.

You may want to look at my article for this, here I explain in more detail how would this work:
Framerate control system for javascript

And yes, I know, there's some redundant code in there (return this, delete d)... That's what happens when I dare to write an article after three years of inactivity with javascript. In the end that extra code is no-op though, just get rid of that (assuming you know what you're doing) >_> Enjoy!
0

Share this post


Link to post
Share on other sites
This solves the consistency problem. The maximum throughput problem is probably as BeanDog suggested.

Question on a curious side note: for this sort of frame rate syncing, is there a case where processing N frames this update will take such a length of time to require M frames to be processed on the next update, where M is some number greater than N? It just came to mind, haven't had the time to suss it out yet, seems like it might be possible given a certain level of processing complexity.
0

Share this post


Link to post
Share on other sites
Yes, but at that point there isn't much that can be done. I'd suggest capping the amount of frames it can give (for example, modify the loop so it also stops after totalFrames reaches certain number, e.g. 4 frames). That'll reduce the effective framerate, but at least it'll prevent the game from locking up. How you want to do the capping is up to you, different games had different approaches to this.

Also, don't include graphics updating in this system. Read the value given by getFrames(), process the game logic frames, and only once you're done with them proceed to update the graphics with whatever ends up as the current state. Otherwise frameskipping won't work at all (or work completely badly), really.
0

Share this post


Link to post
Share on other sites
I've got nothing new to add, just wanted to say Sik's method is much better than the hacked-up setIntervals I've used and it's probably the best (most consistent) solution I've seen. [bookmarked]

Thanks for that!
0

Share this post


Link to post
Share on other sites
Of course, this is all assuming that the timing method is any good. Who knows how if each browser's implementation of the Date object is at all accurate.
0

Share this post


Link to post
Share on other sites
Quote:
Original post by capn_midnight
Of course, this is all assuming that the timing method is any good. Who knows how if each browser's implementation of the Date object is at all accurate.

Usually browsers just take the timestamp from the operating system, so if anything goes wrong, it's usually the operating system's fault. Of course, then there's embedded systems where the browser is part of the firmware itself, but in those cases either the hardware is too weak to do anything useful or it has a decent implementation.

Bear into mind that the worst that could happen is that you'll get a lower real framerate, but the logic framerate will still remain the same no matter what you try to do (well, frameskipping capping aside). The only way such a thing could break is if the browser was completely unable to retrieve the proper time of the day in the first place.
0

Share this post


Link to post
Share on other sites
I'm really impressed with Sik's algorithm, it looks like perfect solution to this problem. If anyone wants to see a demo of it implemented in a game engine, I wrote a simple code to test it out. You can find it here. This isn't a game at all, but it shows the frame rate control at work. Feel free to look through the source code if you're curious. In Firefox on my box the graphics start to lag at around 100 objects in the demo, but the motion and interactions remain smooth and on time. Very nice idea!
0

Share this post


Link to post
Share on other sites
[quote name='capn_midnight' timestamp='1281958174' post='579738']I'm not happy with the performance of setInterval (or its retarded brother, setTimeout) and was wondering if y'all knew of a better way.[/quote]

No you must either use setTimout or setInterval. I would actually recommend you to use setTimeout because setInterval will stack the function calls if the game logic takes longer time to execute than the interval..
I just wrote a quiet in depth article on gameloops for javascript HTML5 games. Read it all here: [url="http://jsteam.org/?p=6"]http://jsteam.org?p=6[/url]
You could use the class in the end of that article. I MIT licensed it.
0

Share this post


Link to post
Share on other sites
You want to use 'requestAnimFrame". It's supported on most browsers. I use a shim like this to fallback to setTimeout:

[code]window.requestAnimFrame = (function () {
return window.requestAnimFrame ||
window.webkitRequestAnimationFrame ||
window.mozRequestAnimationFrame ||
window.oRequestAnimationFrame ||
window.msRequestAnimationFrame ||
function (callback, element) {
window.setTimeout(callback, 1000.0 / 60.0);
};
})();[/code]

Here's a [url="http://paulirish.com/2011/requestanimationframe-for-smart-animating/"]blog post[/url] about it. EDIT: the sidebars of that blog are awesome
1

Share this post


Link to post
Share on other sites
I continue to be amazed that this post consistently ranks #1 for searches of "javascript game loop".

Anyway, typedef struct, thank you for your post. That is very interesting. Unfortunately, on iOS 5's Safari, it shows no performance increase, and in Chrome 15 on Windows XP it actually shows a slower performance, almost to the point of Internet Explorer levels. Maybe in the future this will be better, but for now, setInterval or setTimeout seems to be the fastest way.
0

Share this post


Link to post
Share on other sites
I've been spending some time on this, and I think I found a good game loop cycle, which is independent of platform speed...

[code]
// borrowed from above....
var requestAnimationFrame =(function () {
return window.requestAnimFrame ||
window.webkitRequestAnimationFrame ||
window.mozRequestAnimationFrame ||
window.oRequestAnimationFrame ||
window.msRequestAnimationFrame ||
function (callback, element) {
window.setTimeout(callback, 1000.0 /60.0);
};
})();

// get the 'canvas', and the 'oil on canvas'
var c = document.getElementById('c');
var oc = c.getContext('2d');

// the 'synthetic' or 'target' fps
var FPS = (1/60);

// how much REAL time passed between updates?
var accumulated = FPS;

// old time stamp
var old = new Date();

// main update loop
function loop() {

// loop this function again
requestAnimationFrame(loop);

// ge the new time stamp
var newDate = new Date();

// add the time that passed between updates
accumulated += ((newDate - old)/1000);

// assign the new time stamp
old = newDate;

// if the accumulated time is greter than our target fps
while(FPS < accumulated){
accumulated -= FPS;

// use the dt in positioning calculations...
// for example... x+=(speed*FPS);
Update(FPS);
}

// render the scene as fast as possible...
Render();
}

// onload()
requestAnimationFrame(loop);
[/code]


Without all the annoying remarks...
[code]

var requestAnimationFrame =(function () {
return window.requestAnimFrame ||
window.webkitRequestAnimationFrame ||
window.mozRequestAnimationFrame ||
window.oRequestAnimationFrame ||
window.msRequestAnimationFrame ||
function (callback, element) {
window.setTimeout(callback, 1000.0 /60.0);
};
})();

// get the 'canvas', and the 'oil on canvas'
var c = document.getElementById('c');
var oc = c.getContext('2d');
var FPS = (1/60);
var accumulated = FPS;
var old = new Date();

function loop() {
requestAnimationFrame(loop);
var newDate = new Date();
accumulated += ((newDate - old)/1000);
old = newDate;
while(FPS < accumulated){
accumulated -= FPS;
Update(FPS);
}
Render();
}
requestAnimationFrame(loop);[/code]
0

Share this post


Link to post
I guess if you really needed each time step, for physics or other calculations...

[code]

function loop() {
requestAnimationFrame(loop);
var newDate = new Date();
accumulated += ((newDate - old)/1000);
old = newDate;
while(FPS < accumulated){
accumulated -= FPS;
Update(FPS);
}
}
Render();
}
[/code]
0

Share this post


Link to post
If you don't need to time step through each pass, this is an alternative 'loop' function....

[code]

function loop() {
requestAnimationFrame(loop);
var newDate = new Date();
accumulated += ((newDate - old)/1000);
old = newDate;
if(FPS < accumulated){
var dt = Math.floor(accumulated/FPS)*FPS;
accumulated -= dt;
Update(dt);
}
Render();
}
[/code]
0

Share this post


Link to post
EDIT: I am now using this game loop:
[code]
// setInterval(GameLoop, 1);

var FPS = 50;
var dt = 1/FPS; // synthetic delta time
var last = Date.now()/1000;
var accrued = 0.0;
var ri = 0.0; // render interpolation

GameLoop:function(){
var now = Date.now()/1000;
accrued += (now-last);
CheckInput();
while(accrued > dt){
Update(dt);
accrued -= dt;
}
ri = (accrued/dt); // calculate render interpolation
Render(ri); // pass it to render moving images
last = now;
}[/code]
Let me know if you find any 'issues' with this :) I have been working on it for a couple [s]days[/s] weeks now, and like the results.

You can test out the game loop on my html5 test page...

[url="http://www.html5.bunzaga.com/"]http://www.html5.bunzaga.com[/url]

There is an 800x600 canvas with 1000 'targets' bouncing around the screen.

[s]Here is my updated game loop for html5 canvas. It works well for both 'fast' and 'slow' computers...[/s]
[code]
// setInterval(GameLoop, 1);
var old_time = Date.now();
var FPS = 1/60;
function GameLoop(){
var new_time = Date.now();
var dt = ((new_time - old_time)/1000);
while(dt > FPS){
Update(FPS);
dt -= FPS;
}
Update(dt);
Render();
old_time = new_time;
}[/code]
1

Share this post


Link to post
Share on other sites
[quote name='BUnzaga' timestamp='1322809570' post='4889702']
Here is my updated game loop for html5 canvas. It works well for both 'fast' and 'slow' computers...

[code]
// setInterval(GameLoop, 1);


var old_time = Date.now();
var FPS = 1/60;
function GameLoop(){
var new_time = Date.now();
var dt = ((new_time - old_time)/1000);
while(dt > FPS){
Update(FPS);
dt -= FPS;
}
Update(dt);
Render();
old_time = new_time;
}[/code]

Let me know if you find any 'issues' with this :) I have been working on it for a couple days now, and like the results.
[/quote]



Awesome BUnzaga!

Now lets see more man ;-)
1

Share this post


Link to post
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
Sign in to follow this  
Followers 0