Chap. 03 - The Timer Queue and Initialization

The Basics

The system contains a timer that in many ways governs the operation of the entire system. The timer calls the Lua functions that you write, it invokes the physics engine at regular intervals, it drives the renderer at regular intervals, it even polls the keyboard and the mouse. Since the timer is at the core of the system, it is useful to understand exactly how the timer works.

Using Timer.later to Schedule Activities

The timer can be used to make events occur at scheduled times. The function Timer.later will schedule a function to be called after a specified amount of time. This program is an example:

function onSceneStart()
    Timer.later(printHello,1)
    Timer.later(printGoodbye,3)
end

function printHello()
    print("Hello")
end

function printGoodbye()
    print("Goodbye")
end

This program waits until 1 second from the start has elapsed, prints "Hello", then waits until 3 seconds after the start have elapsed, and prints "Goodbye."

The function Timer.every(task, delay) is a variant of Timer.later that schedules a function to be called over and over at the specified rate.

Using Background Jobs to Schedule Activities

There is an alternate way to achieve the same thing: create a background job. The method Coroutines.schedule creates a background job. Here is some sample code:

function onSceneStart()
    Coroutines.schedule(printHelloGoodbye)
end

function printHelloGoodbye()
    Timer.sleep(1)
    print("Hello")
    Timer.sleep(2)
    print("Goodbye")
end

The method Coroutines.schedule creates the background job, which starts running immediately after onSceneStart. The background job puts itself to sleep for 1 second, prints hello, puts itself to sleep for another 2 seconds, then prints goodbye. It then exits. See Chapter 4 for information explaining background jobs in greater detail.

This code is actually using the same Timer queue as the first version: the Timer.sleep command uses the Timer queue to wake the background job up at the specified time.

Scheduling an Activity for 'Next Frame'

Often, you want to schedule activities to occur once per frame. There is a special notation for this: use a time-value of zero in either Timer.later, Timer.every, or Timer.sleep. This will cause the task to be delayed until just before the next render.

Program Initialization

There are several activities that take place before the timer starts running. These are the program initialization activities.

The system-level initialization takes place first:

The user's main coroutine performs the following tasks, in order:

Your onSceneStart may spawn timer tasks and other coroutines. These other tasks may run concurrently with the main coroutine.

The plugin always begins by loading a scene file, this is true even if you want to start building a new game. To make it possible to start with a blank slate, we have provided an empty scene file "Wild Pockets Team/Blank Scene", a scene with no scene objects or scripts in it. You start by loading this empty file, and then begin adding objects. (Alternatively, you can just load the default scene then delete the four objects). When you are ready, you save it again on the Wild Pockets file server, under a new filename.

You might wonder why we require the use of scene files for simple games, like Pac Man, which don’t appear to need them. In that case, the scene file might very well contain just the filename of the Pac Man script, and nothing else. The scene file can, in some cases, just be a reference to the game's code. On the other hand, even in a simple game like Pac Man, it might be useful to save some objects in the saved game file. For instance, you could set up all the dots, walls, and power pellets using the builder, and then save the scene. When the player loads the game, the walls, dots, and power pellets are already in place.

Discrete Event Simulation

Wild Pockets is actually a discrete event simulation. What that means is:

Since the Timer clock is governed entirely by math, and not by any actual real-world clock, the simulation is deterministic. Since it is in no way governed by a real clock, in theory, it is possible for the simulation to run hundreds of times faster than real time. To prevent this, a throttling mechanism in place to slow the discrete event simulator down to at most real-time.

But regardless of the throttling mechanism, the simulation behaves deterministically. This makes it much easier to write games with predictable behavior.

The Fixed Frame Rate

The system schedules a render to occur once every 1/60th second. In other words, the game is expected to run at exactly 60 FPS. If the video card isn't capable of keeping up with this, then frames will be silently dropped. What this means is that the task that is supposed to render a frame will skip a frame, to lighten the load on the video card. When a frame is dropped, that fact is hidden from the Lua code. In other words, the Lua code is allowed to believe that a render just occurred, as scheduled, at exactly 60 FPS.

Presenting the illusion of a fixed 60 FPS frame rate makes it much easier for the Lua programmer to write predictable games - in particular, you don't have to worry about writing frame-rate independent behavior, which is always tricky.

Physics Timesteps and the Timer Queue

The physics engine is actually a Timer task. Every 1/240th of a second, the Timer runs the physics update function. The physics update process calculates forces on all the objects, and updates their positions and velocities. See Chapter 8 for more infomration on the Physics Engine.