Engine - INeedAUniqueUsername/TranscendenceRL Wiki


Transcendence Rogue Frontier contains at least 16,000 lines of code. Much of this code implements world, movement, combat, and UI mechanics.


.NET 5.0

.NET 5.0 is a cross-platform runtime that allows us to build cross-platform applications


MonoGame is a framework on which SadConsole runs.


SadConsole is a tile rendering engine.

SadConsole provides the Console class onto which we can render tiles onto a grid. We call Update to update the logic, Render to draw the console onto the screen, ProcessKeyboard to handle keyboard controls, and ProcessMouse to handle mouse controls.

A console may call ProcessKeyboard or ProcessMouse on another console to handle input.

Render is automatically called every frame if the console is a child of the current screen and has IsVisible. Additionally, we can call Render to draw a console on the frame regardless of whether it should be visible. Consoles show up in the order that we call Render - first console is the last layer and the last console is the top layer.

By default, a Console holds Children elements provided by the SadConsole library and placed by the programmer. To implement game-specific code, we usually subclass Console and override Update and Render functions. To separate logic from graphics, we use Update for game logic only and Render for graphics only.


Composition over Inheritance

We strongly follow the principle Composition over Inheritance.

  • Graphics classes (e.g. the menus and displays which drive SadConsole) may inherit from Console
  • All other classes may not use inheritance.
  • Common behaviors should be split into separate modules.


We follow the principle of modular design. Groups of functions that address a common task go into their own modules.


To enable serialization, we must avoid using lambda functions at all costs. Instead, we encapsulate functions into container classes. For the most part, we keep most class members public for easy, automatic serialization.



The World keeps track of all active game objects.

We want to avoid modifying the entity/effect/event sets in the middle of an update. We keep added and removed sets which we use to update the entity/effect/event sets after each update. We also remove objects that are no longer active. Objects should call the appropriate Add and Remove functions if they must manually remove other objects from the world (e.g. without setting active to false).


The BaseShip is a structure that contains systems and logic common to both PlayerShip and AIShip. This includes basic movement, damage, and destruction mechanics. The BaseShip also holds hooks for events like Damaged and Destroyed.


The EnergySystem handles fuel mechanics for the player. EnergySystem requires access to the ship's DeviceSystem to calculate power usage and update Reactor energy usage.


DeviceSystem maintains collections for the ship's installed devices.


DamageSystem implements HP and armor mechanics, and automatically calls Destroy on the object.


HPSystem implements a basic, type-neutral HP system. Objects use a single HP counter and get destroyed upon reaching 0 HP.


LayeredArmorSystem implements a simple system of armor segments. Each armor segment has an HP counter. Damage is first applied to the topmost armor segment, then overflows to the next armor segment until all of it is absorbed. Objects get destroyed upon all armor segments reaching 0 HP.


The IShip interface determines the visible methods shared by both PlayerShip and AIShip. Noted: We may want to consolidate PlayerShip and AIShip into a single class, with differentiating behaviors implemented entirely via Controller.


PlayerShip implements logic for the player-controlled ship.


Player holds information specific to the player character, including name, genome, and money. We should also keep known station information here. The PlayerShip currently does not run on Controller, so consider the Player as the Controller equivalent for now.


AIShip implements behaviors for AI-controlled ships.


The IOrder interface determines the visible methods for AIShip behavior modules. We call Update(IShip owner) to implement the behavior. Note that we pass in the owner because an order could be shared by multiple ships, and that orders are not exclusive to AIShip (e.g. we can control PlayerShip behavior)


The Controller is the main IOrder that runs on the ship. Controller manages special ship behaviors and sub-orders.


We implement a variety of orders that any ship may perform. Some are composite orders.


The PlayerMain console manages the main loop, player controls and UI during gameplay. We split UI elements into separate consoles so that we can update and draw each element as needed.


The Readout shows the player basic text-based information about Energy, Device, HP, Targeting, and Messaging systems.


The Vignette shows the colored border around the player field of view.


The EdgeMap shows objects beyond the player's current field of view as colored hash symbols on the edge of the screen.


The MegaMap allows the player to scale the field of view and see more surroundings.

⚠️ **GitHub.com Fallback** ⚠️