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 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
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
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.
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
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
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.
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.
IShip interface determines the visible methods shared by both
AIShip. Noted: We may want to consolidate
AIShip into a single class, with differentiating behaviors implemented entirely via
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.
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
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.
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.
Readout shows the player basic text-based information about Energy, Device, HP, Targeting, and Messaging systems.
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.
MegaMap allows the player to scale the field of view and see more surroundings.