See the introduction post for context.
In general, game development begins with the game loop. If you come from the business world of software development, this will be strange. You don’t rely on events. Phil Haack once asked me “why a loop?”, to which I responded “uh…”. However, a much better answer would have been this one on stackoverflow.
Okay, so we should use a master loop. If our runtime is the browser, how do setup this loop? There’s a relatively new API called
requestAnimationFrame and that’s what most folks recommend. Check out these for details:
(I do recall reading something negative along the way about the API, but I couldn’t find it again.)
I used the
requestAnimationFrame shim referenced in the Paul Irish post above. The shim is only necessary for older browsers that have not implemented the API. By the way, we refer to each iteration of the loop as a “frame” because of the analogy with traditional animation.
Now that we’ve ensured that
requestAnimationFrame is present we can get to our game loop. Here is my game’s bootstrap code (well, an early version of it):
The heart of this the
loop function. It has the following step:
- capture the current time
- calculate the time that has elasped since the last frame
- execute the game’s logic for the frame (that’s the update and draw invocations)
- request the next invocation of
- record the current time of the this frame for calculations in the next one
N.B. This code doesn’t use
frameId yet. The idea is that this handle could be used to halt the loop.
beginLoop function is there merely to provide a closure for some of the variables used to track the state of the loop. It kicks off the loop with its initial invocation of
The big mystery inside of
loop is the
currentScreen object. Here I was thinking ahead (which can be dangerous). I know that my game will have at least two “screens”, possibly more:
- start menu screen
- main game screen (where the action takes place)
I wanted the loop logic to work with both (as well as any future screens). I expect screen objects to have two methods:
updatetakes the time elapsed since the last frame and is responsible for updating the state of the game.
drawtakes the drawing context (from the canvas) and is responsible for rendering the current state of the game.
You’ll also see that I grab a canvas element and capture its drawing context. If you are not familiar with the canvas APIs, I recommend that you start here.
Why two different methods for game logic?
draw functions separate is important. When frames becomes expensive to compute, the game may respond with lag or non-deterministic behavior. Too avoid this, you might want your game to skip over some logic during a particular iteration of the loop. However, it’s very likely that you won’t want to drop calls to
update. It’s not necessary a big deal if you skip rendering a couple of frames, however if skip calculating the location of a projectile then it might mysteriously “pass through” its target. This will become more relevant to us in particular, because I’d like to all the player to control the speed of game (a common feature of many tower defense games).
draw are always called for each iteration of the loop, so the distinction is academic in this context. We could though calculate our frame rate in
loop and occasionally skip invoking
draw if the rate slowed down.
Now we have enough in place to begin working on our start menu screen.