Welcome, please login or register

PushButton Engine: Table of Contents » Flow Of Execution

Flow Of Execution

An important part of understanding PushButton Engine is understanding what is run when. While most of the behavior described in this chapter is completely automated, it is helpful background information when you are developing or debugging components.

Note: Because PushButton Engine is very modular, different components may execute different code. Components should document this behavior. Most components will build off "core" PushButton Engine code like the ProcessManager and there will have behavior outlined in this document.

Main Loop

PushButton Engine does not implement its own main loop or take "control" of your game. Everything is instigated by you, the developer, as this chapter outlines. In general, code and managers are created and executed on demand - for instance the first time you use the TemplateManager, it initializes itself. When you add the first object to the ProcessManager, it registers for callbacks, and when you unregister the last object it turns itself off.

As a rule: you pay for what you use.

Engine Startup

If you are using any of the PushButton Engine MXML tags, these are processed as early as possible in application startup. Level-related tags are processed when the applicationComplete event fires. Resource-related tags are processed as soon as they are loaded by Flex - usually in the first few frames.

As a side effect of these tags, the ResourceManager, LevelManager, and other managers may be initialized. They are all created on demand, as mentioned above, when you first access them via their static Instance member.

If you are manually initializing your game, by directly calling the managers without using the tags, then it's up to you when everything starts.

ProcessManager

The main piece of code that will be run after initialization is done is the ProcessManager, which is called at the start of every frame. The ProcessManager is responsible for managing the processing of time-related code. It does this with two kinds of callbacks - per tick and per frame.

The ProcessManager allows you to set a priority for when in the course of processing time your object is called back. Higher priority objects are called first, followed by lower priority objects. Priority defaults to zero.

Frame Callbacks

Per-frame callbacks happen via the IAnimatedObject interface. Simply implement the IAnimatedObject interface, and call ProcessManager.instance.addAnimatedObject(this); to get callbacks. For example:

   // Example of a component that receives per-frame callbacks.
   public class DemoAnimatedComponent extends EntityComponent implements IAnimatedObject
   {
      public function onFrame(elapsed:Number):void
      {
         trace("Frame happened, and " + elapsed + "ms passed since last time.");
      }
      
      protected override function onAdd():void
      {
         ProcessManager.instance.addAnimatedObject(this);
      }
      
      protected override function onRemove():void
      {
         ProcessManager.instance.removeAnimatedObject(this);
      }
   }

Because you have to implement the above logic for every animated object, there is a helper base class provided with the engine, PBLabs.Engine.Components.AnimatedComponent, which not only automatically registers/unregisters for you, but lets you specify a priority.

Ticks

Ticks are extremely useful when trying to implement gameplay that doesn't break at very high or low framerates. Ticks are guaranteed to happen at a fixed interval (see ProcessManager API documentation for details on the interval). At the start of each frame, the ProcessManager checks to see how long it has been since the last tick was processed. If it has been one or more tick-intervals, then it processes a tick. If it has been a long time, then it will run many ticks - however are many needed to stay caught up with realtime.

This is great for gameplay because it means the game runs consistently no matter what - internally, everything is processed at 32Hz (or whatever you set it the tick rate to). The rule is to implement any gameplay code in the onTick callbacks, and any "display" code - for instance updating a particle system or interpolating position for smoother display - in onFrame.

A simple component that receives ticked looks like this. Notice it implements the ITickedObject interface:

   // Example of a component which receives tick callbacks.
   public class DemoTickedComponent extends EntityComponent implements ITickedObject
   {
      public function onTick(tickRate:Number):void
      {
         trace("A tick happened!");
      }
      
      protected override function onAdd():void
      {
         ProcessManager.instance.addTickedObject(this);
      }
      
      protected override function onRemove():void
      {
         ProcessManager.instance.removeTickedObject(this);
      }
   }

As with the AnimatedComponent base class, there is a TickedComponent base class which simplifies creating a component that creates ticks.

To summarize the behavior of ProcessManager, at the start of every frame (on the ENTER_FRAME event), it does the following:

  1. Process IAnimatedObject callbacks.
  2. Process any pending ticks by calling ITickedObject onTick zero or more times.
  3. Process any pending events.

Managing Time

There are several convenient values the ProcessManager calculates for you. These are virtualTime, which is milliseconds of simulated time since the game started based on elapsed ticks, and interpolationFactor, which is identical to the parameter passed to onInterpolateTick. In general, you should use virtualTime instead of flash.utils.getTimer() and interpolationFactor when you need to be aware of where you are relative to ticks.

You may want to experiment with altering timeScale on the ProcessManager. This will allow you to do bullet time type effects or speed up the action. Unfortunately, you cannot reverse time.

Shutdown

Currently, no code is run at game shutdown time.

Low-level Explanations

The ProcessManager exists to provide a consistent environment for gameplay code to execute. If you are concerned with how time is processed in Flash, you might benefit from reading Sean Christmann's article on Updated 'Elastic Racetrack' for Flash 9 and AVM2, based on Ted Patrick's original Elastic Racetrack article.

Conclusion

PushButton Engine starts its managers on demand. There is no strict main loop. If you are concerned about the specific details of exactly how a specific piece of code is run, you should review its API docs and source code - this will be the most up to date and accurate.