Skip to content

Project Structure

DesirePathGames edited this page Jun 5, 2026 · 2 revisions

Project Structure

Below is an introductory rundown of the singletons and patterns that handle basic system architecture tasks such as data, messaging, and file handling in the framework. These perform simple but necessary functions used everywhere.

Messaging

StR uses a standard global event bus via the Signals autoload (TODO link to godot docs for an event bus). Bar specific exceptions, the majority of global signals are defined and called from here.

In the case of UI, some imperative messaging is also handled by HandManager since many other places in the code wish to access the hand/card state. This generates and stores a back-reference to the Hand UI element on game load.

FileLoader

Included in the framework is a utility script called FileLoader. By default Godot loads files from the project directory via load(). When you compile a game, everything in the project is thrown into a single executable file. This is fine for simple projects, however this has significant limitations in my opinion, as data and assets should be differentiated from code where possible and by including them in the build, you defeat the purpose of human readable files. By externalizing data assets, whatever game you make is significantly easier for users to edit or provide data driven mods for such as adding new cards/enemies/characters etc without having to decompile the game.

Instead, a folder hidden to godot via .gdignore (TODO link to ignoring files in godot docs) called external is included in the project directory, and the location of this directory is determined on game load by FileHandler. When running the game from the editor, this will be the project's directory. In compiled builds, this will be the executable's directory where the game was installed and the contents of that external folder should be copied over into the build's directory for the game to load them.

For images, animations, and json, you would simply run FileLoader.load_x("external/..."), passing in a partial file path and the game will prefix the path with the base directory, load things accordingly, and then cache them.

This file handling system is of course completely optional. To change it simply replace FileLoader calls with Godot's internal load() calls and change texture paths to use "res://" again.

For more information on how all of this is managed, see Mod Support

Scripts and Scenes Singletons

These store hard coded references to any kind of PackedScenes or script paths that can be referenced in other parts of the code base, in order to reduce technical debt by using global constants. It's not pretty but it beats magic strings and constants everywhere. It's mostly used for generating configuration data and dynamically generated UI components.

Random

StR uses seed based RandomNumberGenerators rather than simple calls to the global rng. This in theory ensures deterministic behavior across the core game. As a result some random functions like shuffling arrays, drafting cards, and other random number related tasks are defined here. Each random method is passed in an existing RandomNumberGenerator which is preserved between rolls. Some of this behavior may be extracted into various actions if you're so inclined.

ActionHandler

ActionHandler is the core of game, handling most game related behavior by passing in Actions into them. For further details, see the Action Handler section.

Clone this wiki locally