Skip to content

Source code walkthrough

sam edited this page Nov 2, 2017 · 13 revisions

Understanding the source code

BubbleGrow is designed to be "easier" to understand and is filled with comments to help navigate each section. The basic breakdown of the game is into two sections: the "game state", which holds all information regarding the game and processes the game; and the "Graphics" section, which handles everything the player sees, hears, and inputs into the game from their keyboard and mouse.

This walk through is divided by the two sections and covers the source code by the main classes in the source code.

Game State

The game state handles the game's logic and units, and can run completely on its own (it has no knowledge of the graphics, audio, and input). The game state is divided into 3 major classes: the World, the Players that belong to that World, and the Units that belong to each Player.

World.hpp

The "World" class manages a single game. It holds references to each Player (including computer players), determines the size of the game world, and has functions that process the entire game world.

Important variables

  • players: A map that contains each Player reference, access by their unique id.
  • map_radius: Determines the size of the game world. Players who leave this area automatically lose all their units and are removed from the game.

Important methods

  • UpdateAndProcess(duration): Processes one "cycle" of the game (where duration the length of a single frame in the game).
  • AddPlayer(): Adds a new Player to the game, automatically assigning it a unique id.
  • AddResources(amount, radius, density): Adds a "resource Player" to the game, which is a special player type that only exists to create the resource bubbles you see in game.
  • FindUnit(owner_id, unit_id): A helper function used by other classes to retrieve the reference for a specific Unit based on its unique id.
  • EndWorld(): This cleans up the game world, removing circular shared pointer references that would normally cause memory leaks. Since both the Player and Unit class also reference World, this has to be manually called instead of being in the destructor.

Player.hpp

The "Player" class manages the state and actions of each player, including the computers. Each player has a position and Units that follow the position of the player. Additionally, a Player has resources that allow it to buy more Units.

Important variables

  • ai_type: This determines whether the Player's actions are controlled by AI, by the human player, or by nothing.
  • requests_array: The requests array holds a slot for each request type that exists, and it is scanned every frame to determine if any actions need to be taken for the player. This includes things like requests to move to a destination or create a new Unit.
  • unit_requests: Similar to the requests_array, but holds requests for individual Units instead.
  • units: A map of all Units owned by the Player, accessed by its unique id.
  • position: The position of the player in the game World.
  • resources: The number of resources the Player has.

Important methods

  • ProcessPlayerRequests(duration): Executes all requests made for the player.
  • PlayerMoveRequest(destination, speed): Creates a request (in the requests_array) to have the player move toward the desired location.
  • PlayerPurchaseRequest(purchase_amount, purchase_type): Creates a request to attempt to purchase a Unit of the specified type.
  • Update(duration): Calls the update function for each Unit the player controls.
  • ProcessRequests(duration): Calls the process request function for each Unit the player controls, then executes the player's own requests.
  • MakeDecisions(duration): Calls the Unit's AI to make a decision (request) for every Unit the player owns, then for computer controlled players calls its own AI to make a decision.
  • RemoveExpiredUnits(): Removes dead units from the player's ownership.
  • CreateUnits(amount, type): Creates a unit of the specified type for the Player.
  • RandomWanderLocation(): Provides a random location somewhere on the world map.
  • PurchaseUnits(amount, purchase_type): Attempts to purchase the units (will only purchase what the player can afford).

Unit.hpp

The "Unit" class holds the state and methods for every Bubble Unit in the game. Each Unit is capable of making AI decisions and executing those decisions and are managed by a Player class.

Important variables

  • events: Events are actions recorded by the Unit, such as an attack, a death, or gathering resources. This is used by the sound manager to know what sounds to play.

Important methods

  • WalkTo(destination, duration, update_action): Processes a walk to action for the given duration.
  • Attack(target, target_owner, duration): Processes an attack action for the given duration.
  • Gather(target, target_owner, duration): Processes a gather action for the given duration.
  • Update(duration): Updates the Unit (including any pending damage to apply).
  • MakeDecision(request): Calls the AI to make a decision and create a request for it.
  • ProcessRequest(request, duration): Processes a request for the Unit, such as attacking or walking.

Graphics, Audio, and Input

This section covers everything involving what is seen, heard, and input on the game screen. This section of code, unlike the Game State, is dependent on SFML.

Renderer.hpp

The "Renderer" handles the display of everything on the screen. Uses a combination of batch drawing and SFML supported classes like "sf::Sprite" and "sf::Text" for most of the displayed graphics.

Important variables

  • events: Used by the sound manager to know which sounds to play, such as clicking a menu entry or starting a new game.
  • window: This is the reference to SFML's RenderWindow, which is used to display everything on the screen.
  • menu_text_entries: This holds all existing menu entries that are displayed, and is used to track if the mouse clicks one of them.
  • current_menu: Tells the renderer which menu stage it is currently at.

Important methods

  • RenderGame(duration): Based on whether at the main menu or in a game, renders either.
  • RenderUnits(): Renders all players and their units.
  • RenderPlayer(player_to_render, main_player_position): Renders all units owned by a player.
  • RenderInterface(duration): Renders the interface, including text, logo, and directional arrows.
  • RenderDirectionArrows(): Renders arrows at the edge of the screen that point toward other players.
  • RenderMenu(): Renders either the in-game menu or the main menu.

InputHandler.hpp

The "InputHandler" class is a helper class to the Renderer and is tightly coupled to the Renderer. It handles processing all input from the user.

Important variables

  • renderer: The InputHandler class is a "friend" of the Renderer and, using this reference, the InputHandler class has access to all the private members of the renderer.

Important methods

  • QuickMatchGame(num_players = 16): Initializes a new game by creating a new world and new players in that world. One of the players are assigned to the user.
  • PollEvents(): SFML adds all input events (such as a keyboard or mouse click) to a stack that is processed by the InputHandler. This allows the InputHandler to know all input events that occurred the previous frame.
  • ProcessInputs(): This function handles all non-event related inputs, such as the current mouse position, to determine if any other input handling is needed.
  • GamePollEvents(event): This is called by "PollEvents()" if the current mode is in game.
  • MenuPollEvents(event): This is called by "PollEvents()" if the current mode is at the main menu.

SoundManager.hpp

The "SoundManager" class goes through all events that have occurred and plays the corresponding sounds, whether that be an attack, gather, death, mouse click on a menu, etc. Additionally, handles which song is playing.

Important variables

  • sound_files: A map of all sound files loaded in the game.
  • sounds: A vector of 255 "channels" from which sounds can be played on. This is due to SFML only supporting up to 255 simultaneous sounds.
  • sound_availability: Keeps track of which sound channels are currently available for new sounds to play on.
  • master_volume: Scales the volume of all sounds.

Important methods

  • PlaySound(id, screen_position): Plays a sound at the given screen position (which, using stereo sound, changes where you hear the sound directionally and volume-wise).
  • PlaySound(event): Plays a sound depending on which event occurred, such as an attack or death.
  • PlayEventSounds(events): Goes through all pending events and plays their corresponding sounds.
  • ProcessPendingEvents(): Goes through all events in both the game World and Renderer to determine what needs to be played.