Time Processing


The game world processing of objects is handled almost entirely in the game portion of the engine. All game world object classes are derived from GameBase, which is a subclass of SceneObject. GameBase objects that wish to be notified of the passage of time can be added to one of the two process lists - the global server or global client process list, depending on whether the object is a server object or a client ghost.

All objects in the process list are "ticked" once every 32 milliseconds. The ordering of the objects is determined by the GameBase::processAfter method, which is called if an object must be processed at some time after another object (not necessarily immediately afterward). For example, a player mounted to a vehicle would be set to processAfter the vehicle, so that after the vehicle moved the player's position could be updated to the correct position on the vehicles new position.

Update Interfaces

Game objects are updated in three separate functions, overridden from GameBase: GameBase::processTick(), which takes a single Move structure as an argument (it may be NULL) and advances the object in time by one 32 ms tick, GameBase::interpolateTick(), which interpolates a client object backwards from the end of its current tick to the present time, and GameBase::advanceTime(), which allows a client object to advance animations and effects by the full duration of the time event.

Server side objects are only simulated on even tick boundaries, but client objects, in order to present a smooth view when the frame rate is high, are simulated after each time event. GameBase::processTick is still only invoked on even tick boundaries, but at the end of the time advance, objects are essentially rewound by the time difference to the end of the tick. Also, client objects that need to animate only by the total elapsed time can do so in the GameBase::advanceTime function, which is only called once per time advancement.

If the control object is sent new object state from the server, it will be advanced by every Move the client has recorded that the server has not yet acknowledged - this is because the server has old data as far as the client is concerned, so the client skips forward through all the new data it knows about.

Processing Events

During the processing of an object, situations may arise that are important to the Gameplay Implementation layer, and therefore need to be somehow communicated to this layer for further processing. Since a majority of the time our Gameplay Implementation occurs in TorqueScript, Torque provides a mechanism for notifying this layer of the event called a Callback.

When a callback is triggered, execution within the Game Processing loop pauses, and control of execution is handed over to the Console, which in turn searches the loaded TorqueScript code for an appropriate Callback Handler--a TorqueScript only block of code to be executed when the event occurs.

Common callback handlers may include playing a sound when an object is picked up (collided with), incrementing a score when a player dies, or allowing the Gameplay layer to know when other important events have occured.

Callbacks are very powerful, and a large majority of our Gameplay Implementation is simply writing callback handlers for the hundreds of events that can occur during processing, but it is important to keep in mind that execution of the engine is effectively paused while a callback is handled! Attempting to perform complex calculations such as a script based A* path find with 100,000 nodes is not recommended during Game Process level callbacks.

Callbacks may also be ignored by the Gameplay Implementation layer, and if no handler is provided for a specific callback, the event will be ignored and processing will continue.

Callbacks can and do occur elsewhere in the engine besides the Game Processing layer--examples include things like a new client entering the game (GameConnection::onClientEnterGame()), a new object registered with the simulation (SimObject::onAdd()), and many more.