top of page

Space Invaders Re-Engineered

Architecture of Real-Time Systems

The development of Space Invaders Re-Engineered took place over a period of 11 weeks, eventually comprising over 150 unique class objects totaling 3500 lines of code. The demands of Space Invaders to function within real-time constraints required additional levels of foresight pertaining to architectural design. Various software engineering design patterns were utilized to support the development of systems within the game including:

Command, Composite, Factory, Flyweight, Iterator, Object Pooling, Observer, Proxy, Singleton, State, Strategy, and Visitor Patterns.

Below is a general demo showcasing the major features within the game, captured entirely in Debug mode:

The following are partial excerpts from the design document of the application, including UML-style diagrams with accompanying code samples and explanations. The design documentation is focused on describing the software engineering design patterns featured within the game, with each section dedicated to a specific pattern.

Command Pattern

Command.png

Command Pattern Used in Space Invaders:

To solve the problem of processing the entirety of unique actions occurring within Space Invaders, the Command Pattern was used extensively. Using commands eased the management burden regarding actions taken by the majority of game objects. This allowed for less-complicated object implementation later-on. Encapsulating the actions of these objects within their own unique commands ensured a level of detachment from the class methods themselves.

 

Shown in the diagram above, TimerManager constantly updates throughout the running of a particular state within the application. The TimerManager, derived from the base class Manager, holds an active list of TimerEvent objects. These TimerEvent objects in turn hold references to command objects, as well as specific information pertaining to timing. Regarding the TimerManager specifically, the Update() function runs through the list of TimerEvents, and executes its referenced command only if currentTime exceeds triggerTime. Subsequently, once the command has been executed, it is added back onto the TimerManager, where it will be executed once again dependent upon the updated timing information. This ensures that the Command is executed routinely according to scheduled time.

 

In this specific example, the AnimationCommand, SoundCommand, and AlienGridMoveCommand hold information supporting the functionality of the alien grid. The AnimationCommand cycles through different Alien images, whereas the SoundCommand references the noises pertaining to the movement of the grid. Finally, the AlienGridMoveCommand does what its name implies, which is to signal the movement of the entire enemy composite structure. Important to note is the unique nature of each command’s Execute() function. Both AnimationCommand and SoundCommand have implementations of the Execute() method, but behave very differently. The composition of TimerManager does not care about this distinction and will execute the command(s) regardless of their derived type. This lends to a high level of reliable certainty with which commands are executed.

Edit_0.png

Lastly, it is important to mention the existence of the DelayedManager class. The DelayedManager functions almost identically to the TimerManager with one important difference: the DelayedManager does not re-add command objects for repeat execution. This provides the application a means to execute singular actions, while still supporting scheduled execution. This was extremely useful when resetting specific behavior, as well as ensuring dependable object removal.

Summary:

The Command Pattern was essential in solving the unique challenges faced within the creation of Space Invaders. This was made evident through its constant re-use throughout development. During the early stages of design, the earliest implementation of the pattern was used to animate the alien sprite object(s). Furthermore, the pattern was employed once again toward the end of development in order to support the timed displaying of text. This wide-ranging use summarily demonstrates the true versatility of the Command Pattern.

Composite Pattern

Edit_1.png

Composite Pattern Used in Space Invaders:

Using a Composite Patten to organize the objects within Space Invaders provided many advantages, including the support for simplified additions and removals pertaining to collections. As can be seen in the diagram above, both Composite and Leaf objects derive from the Component base class. While this means they both polymorphically inherit the same properties, the important distinction arrives in composite’s status as a collection. The use of the composite in Space Invaders fulfills the traditional characteristics of the pattern in that composite objects are able to hold collections of component(s). While both are of the same derived class, a simple type check using the “type” field can quickly distinguish the two if necessary.

The functionality of composite objects to allow both collections and individual objects was proven especially useful during implementation of the collision system. composites could be established pertaining to the alien grid and shield group, with sub-collections attached holding references to individual game objects. By organizing data in this manner, initial collision checks could be performed solely on the coordinates of the group’s entire collision object, designated poColObject. Then, once a collision is detected, the sub-collections containing alien column or shield can easily be accessed by way of the composite parent. Furthermore, if a collision is detected with a specific alien column or shield, the final checks occur against the leaf objects of the given composite. The composite is then utilized once again to update the coordinates of the collision boxes, to ensure precise detection each frame.

Edit_2.png

Aside from utilizing the pattern within the collision system, the composite also demonstrated its usefulness when updating the collections as a whole. During the running of the application, many game objects require frequent modification to demonstrate their desired behavior. This data modification needs assurances in regards to both consistency and reliability. Organizing data in a composite ensured that each item in the collection(s) updated uniformly. This assisted in streamlining the development of behavior for collections such as the alien grid. Using the Composite Pattern allowed for a single method call to the alien grid object, and thus, a uniformly specific modification to each alien object contained within.

Summary:

The Composite Pattern was one of the more foundational patterns employed within Space Invaders. Having the ability to uniformly organize objects for reliable access helped streamline production by reducing inefficient data management. This allowed for additional time spent in developing more challenging systems. The composite was implemented several weeks into development and saw consistent extension and re-use, further demonstrating its versatility.

State Pattern

State.png

State Pattern Used in Space Invaders:

Next to Command, the State Pattern was likely the most used design pattern throughout development. As with many real-time applications, objects in Space Invaders require fast, and often constant, behavioral modification. Using the State Pattern allowed for the support of shifting behavior within various objects in the game, while importantly avoiding the use of expensive conditional expressions. The pattern was first utilized upon implementation of the ship game object, as seen in the diagram above. ShipManager, which serves primarily as the context (manager), owns references to the various states deriving from the abstract class ShipState. Ship then maintains a reference to whichever derived state holds the behavior currently required of the object. When the ship needs to alter its behavior in some way, the object may request the appropriate state from the context.

Upon instantiation, the ship's pState field references the ShipStateReady object. This permits the object to exhibit the behavior contained within the ShipStateReady methods including MoveLeft() and MoveRight(). In this particular state, both methods include defined behavior for altering the x-coordinate parameter used within the ship’s rendering protocol. This means the ship is permitted to move both left and right based off of user-specified input. This behavior changes, however, once a collision is detected between the ship and either the WallLeft or WallRight objects. For example, once a ship collision occurs with WallRight, the ship is notified to change states, subsequently requesting the correct state from ShipManager, the context. In this scenario, Ship requests to swap states to ShipStateRightWall. ShipStateRightWall is contractually bound to implement the base class methods, and therefore, is acted upon in the same manner. However, ShipStateRightWall’s method for MoveRight fulfills typical “do-nothing” behavior. Essentially, this means that the same underlying logic tells the ship to “move right”, but because there is nothing defined within the method, its location remains unchanged. Lastly, once the ship object moves away from the wall, the state returns to ShipStateReady via the Handle() method, and regains full movement functionality.

Edit_3.png

Summary:

While the systems surrounding ship movement included the earliest implementation of the State Pattern, the design was also used in several other key areas. The missile object used the pattern in a way similar to that of the ship: by preventing specific behavioral actions at certain stages. The missile contains several cyclical states pertaining to timing information, all with differing behavioral characteristics. Finally, a State Pattern was also employed to help achieve the end-to-end user experience with the inclusion of the GameState class. To achieve this, the GameStateManager class was used as a context to swap between the various GameState objects; serving as screens pertaining to user interaction with the application.

All three instances of the State Pattern provide the same underlying benefits to improving performance at runtime. Throughout the execution of any real-time application, avoiding the constant state checking often accompanied by conditional expressions should be a top priority for any software architect. Avoiding these expensive expressions can often prove challenging, so precedence should be given to employing a State Pattern in areas of high traffic. In Space Invaders, these areas were primarily located in the update methods of the various objects.

bottom of page