Background-image

BonzayRTS: documentation

As the engine is currently a work in progress, there is not much documentation for the engine, as of yet. Below is a brief overview of the engine and its main classes. Please check on the git source to familiarize yourself with the main abstractions, after reading below.

Documentation sections

  1. Architecture
    1. Subsystems
    2. Game-UI separation
    3. Events
    4. Networking
    5. Game abstractions
    6. GUI abstractions
  2. Starcraft clone documentation

Architecture

BonzayRTS is organized around a list of easily identifiable RTS concepts. These are high-level building blocks that can be customized to suit your game.

Subsystems

One way to reduce the complexities of an RTS game is to divide it into orthogonal pieces that need little or no coupling. Subsystems divide the game at the "service" level - these are huge functionality blocks grouped to provide certain services, and they can be used from anywhere in the program.

A subsystem usually initializes some resources that it will use betweeen start() and end().It has its own configuration section in the configuration file and knows how to read it. A subsystem usually deals with initializing and controlling resources, but may provide game logic as well.

Once a subsystem has been started, it can be used like this: GraphicsSubsystem::get_instance()->open_screen( 640, 480, 8 );

BonzayRTS provides the following subsystems:
  1. DebuggingSubsystem - defines what parts of the engine require debugging output.
  2. LoggingSubsystem - starts and stops logging of debug, info, error, and fatal error messages.
  3. GraphicsSubsystem - initializes video mode, rezises the main screen, toggles show cursor.
  4. SoundSubsystem - initializes sound and provides sound services.
  5. InputSubsystem - provides input from the mouse and keyboard.
  6. NetworkSubsystem - provides transport for messages over a network.
  7. GameResourceSubsystem - handles loading and keeping of game resources.
  8. PhysicsSubsystem - provides pluggable physics via a wrapper.
  9. UISubsystem - provides the UI. This subsystem takes care of handling user input, repainting the screen, painting the mouse, etc.
  10. PathfinderSubsystem - provides configuration of pathfinder behaviour.
  11. SteeringSubsystem - provides configuration of steering behaviour.
  12. ScriptingSubsystem - provides scripting functionality for your game.
  13. ProfilerSubsystem - provides custom profiling if required.

Game-UI separation

Another way to drastically reduce complexity is to divide the code into game-specific and UI-specific code. Code that deals with the things happening in the game universe is game-specific. Code that only needs to convey changes to the player and process player input, is UI-specific. Keeping this separation reduces confusion, allows for more robust and maintainable code.

BonzayRTS enforces game-UI separation by having the GUI and the game logic as separate threads. The UI threads displays things regardless of the game, and the game logic runs separately. This makes game logic simpler, and GUI simpler. If game logic and GUI need to communicate, they may do so via events.

For servers, BonzayRTS provides GameInstance class, holding the status of a game in progress.

For GUI, BonzayRTS provides UISubsystem, which may be customized to a great extent.

Events

Inside both the game and UI, a useful concept is Event. Events happen in the game, or the UI, that may need not to be processed immediately. Perhaps you do not have all the required information to process it, or perhaps other code needs to know something happened in the game. Events also serve to alert the GUI about changes in the game (e.g., a worker finished gathering and now is carrying a load that should be displayed in the GUI.)

BonzayRTS provides Event and GUI::Event interfaces that encapsulate events. It also provides EventProducer and EventConsumer interfaces to ease generation and handling of events. EventManager handles the collection and dispatch of events using a subscriber model.

Please note, that events do not cross Game/UI boundary. Events may be automatically forwarded from game to GUI by an EventBridge.

Networking

BonzayRTS provides networking concepts for communication between the UI and the game engine, and between peers/servers. The core concepts, in order of decreasing abstraction are:
  1. NetworkSubsystem - initializes/binds/releases network objects (sockets, etc).
  2. GameMessage - a piece of data informing of network changes relating to a game.
  3. NetworkMessage - translated GameMessage. GameMessages may not have a 1-1 correspondence to NetworkMessages.
  4. MessageBridge - translates GameMessages to NetworkMessages and vice-versa.
  5. Network - implements a specific protocol for communication over a transport.
  6. Transport Engine - physical network. BonzayRTS provides UDP and Local transports.
  7. MessagePacker/MessageUnpacker - packs/unpacks multiple network messages that are sent over transport.
Think of this as of the Transport Layer of a game. The layer keeps track of transmission delays and timeouts of peers, and is used as the layer to carry over negotiation of games. It also provides hooks for denying certain messages based on sender' address. Usually there is little need to customize this layer.

On top of this layer, BonzayRTS provides a synchronization layer to handle what we call game synchronization between peers. A SyncEvent embodies change inside the game; e.g., a unit finishes performing an activity. SyncEvents are encapsulated into the transport layer as payload and are delivered to the SyncLayer object belonging a GameInProgress.

SyncEvents can be stored for later replay or desync recovery by SyncEventStorage.

BonzayRTS also uses the concept of SynchronizationStrategies to allow Peer2Peer or Client/Server style of synchronization. The SynchThread can be used to implement the synchronization thread for a game. See Starcraft as an example.

Game Abstractions

BonzayRTS provides a lot of game abstractions, in the hope that they will simplify the design process of an RTS game. Below is a list of most significant:
  1. Unit - contains a critter, unit, building, or resource on the map.
  2. UnitClass - defines the properties of a unit. Defines how a unit is created, its allowed commands, its full HP, etc.
  3. UnitClassGUI - GUI counterpart for UnitClass. Holds GUI properties of the unit class - appearance, sounds, visual size.
  4. Weapon - If the game requires that the weapon wears out, this is required.
  5. WeaponClass - the definition of a weapon - contains reload time, damage class, damage value, upgradeability, wear-out rate.
  6. Armor - If the game supports damageable armor, this is required.
  7. ArmorClass - Defines resistance to various types of damage, as well as other properties, like weight, suitability checks, etc.
  8. Disturbance - source of an effect on any unit that falls under its range. May be applied to a unit or on the map.
  9. Modifier - effect that modifies a unit's properties.
  10. Damage - When instantiated, will apply various HP damage to units depending on range and unit type.
  11. DamageClass - Defines the amount of HP hit taken by a unit, depending on the range from damage center, and unit type.
  12. UnitFormation - a group of units executing the same command chain.
  13. Command - contains the command that is assigned to a unit or unit formation.
  14. Action - contains information concerning the command currently being performed.
  15. Activity - performing a command may require many intermediate steps. Activity is one step in the list of steps being performed.
  16. WalkabilityMap - contains the walkable bits on the map. This is for PathFinder's consumption
  17. UnitTracker - keeps track of all the units on the map.
  18. UnitMapper - keeps track of unit ID's and converts from UnitId to Unit* (this is required in Game/UI messaging).
  19. TechTree - contains the tech tree information, plus there are classes to contain current tech tree.

As you can see, the abstractions provide for quite a flexible set of RTS and even RPG elements. It also assists in deciding what kind of features to include in an RTS game.

A few explanations regarding the need for Damage: If the game deals with various damage types, like in Starcraft, where normal, concussive, and explosive damage types deal different damage depending on the unit size, then Damage and DamageClass should be used. Additionally, for splash damage that covers an area and may fade with distance, DamageClass allows to specify that. Instantiating a damage object will allow to apply damage in a programmatically uniform way.

Other game abstractions have to do with entities outside the map:
  1. Player - Identifies a player in a game.
  2. PlayerStats - Holds information about player, including their network details.
  3. Team - Holds the players in a team.
  4. Scenario - Holds a game scenario, including game type, map name, and other game settings.
  5. NegotiatedGame - Holds the details of a game in negotiation phase.
  6. GameInProgress - Contains data for a game in progress.

GUI Abstractions

BonzayRTS tries to abstract away the gory details of painting 2D elements on the screen, to the point where one could swap out SDL in favour of something else and things should not break. Out of the box, BonzayRTS supports 2D drawing via SDL in 8-bit mode, PCX and GRP images, and playback of 8-bit SMK videos.
The lowest level of abstraction involves the following classes:
  1. ScreenCanvas - This allows drawing on the screen.
  2. Image - Interface for an entity that knows how to load itself and draw itself onto a canvas.
  3. ImageFrame - An Image as part of a FrameSet.
  4. FrameSet - A set of images that can be played sequentially.
  5. ImageContainer - A set of images, not related to each other.
  6. AnimatedImage - An animation consisting of a set of images played in sequence.
  7. AnimatedImageDef - An animation definition - blueprint for creating an AnimatedImage.
  8. MultiAnimation - An animation with multiple sides, for units that rotate.
  9. Overlay - A layer put on top of the existing image, saving what's underneath, to be restored as if nothing was painted. This is very useful for displaying small things on top of other things, like the cursor, or tooltips.

Next is the widget set, which is not very interesting in itself - a standard widget library framework.

Then there are GUI objects related to the UI, such as:
  1. Pointer - Abstracts the mouse pointer.
  2. HUD - Abstracts a Heads-Up-Display.
  3. Minimap - Minimap display.
  4. UnitAppearance - This class holds a unit's current appearance.
  5. UnitAppearanceDriver - Unit's appearance driving code. Knows which appearance to use for the activity being performed.
  6. LayeredDisplay - Repaints units in an area based on a multi-layered approach, where some units must be painted in lower layers. Needed in 2D games only.
  7. TerrainTiles - This class is used in displaying the map terrain.
  8. Viewport - Current Viewport of the player onto the map.
  9. PointerTheme - A pointer theme allowing to switch pointer themes.
  10. UITheme - UI theme, if the game has multiple UI versions (standard/experimental is often the case). Decides on how to paint the HUD and minimap

There is also the Unit's counterpart - GUI::Unit, which holds the unit's appearance and other UI properties of the unit.

Last, but no least, is the UI Subsystem which is supposed to handle everything in UI, from keyboard/mouse input, to refreshing the screen, cycling frames, outputting unit sounds, handling selection and updating the HUD and minimap. One can see it in action for Starcraft clone.