On Tuesday, 17 May 2022 at 16:59:31 UTC, Steven Schveighoffer wrote:
I unfortunately can't try it, as it's not open source, and I have a Mac. Are there any videos of gameplay?
Hi Steven. Apologies for the lack of a macOS build, I actually don't own any Apple hardware so my capabilities for testing on that platform are pretty limited at the moment. That said, all the dependencies for the engine should work on macOS, so that's probably something that I could remedy in the future. As for the video, I'll see if I can something up later today that showcases the gameplay.
Are there any plans to sell/release the engine?
No plans for selling/releasing the engine, though I would like to be able to use it to make a game that I can actually sell at some point.
Can you give a small overview of the engine design?
The engine takes a pretty standard OOP approach and relies heavily on the concept of 'managers'. There is a base 'Application' class (which can be sub-classed if needed) that handles a lot of the heavy lifting (window creation, main loop, input polling), and contains instances of all of the facilities that actually make it an engine (things like resource/sound/hook managers, filesystem abstractions and database connections).
As one would would expect with most modern engines, there is a 'scene' management system (which are referred to as contexts in the engine) that allows for easy implementation of game logic and rendering. Simply sub-class the base 'Context' class, and you have access to a set of methods that you can override as needed (update, draw, keypress, keyrelease, etc...) to implement the functionality of the scene. When you instance a context, it is automatically added to the engine's internal context manager, and can be activated/deactivated at any time. Here is an example of what that looks like:
class MyContext : Context
name = "MyContext";
override void activated()
// Load resources...
override void deactivated()
// Unload resources...
override void update(float delta)
// Update stuff...
override void draw(RenderWindow window)
// Draw stuff...
override void keyPressed(Event event)
// Key events...
And then instancing and actually using the engine looks like this (from USG's main.d file):
// create application
auto params = LaunchParameters();
params.windowName = "Untitled Shooter Game";
params.windowSize = Vector2i(1920, 1080);
params.statsEnabled = false;
params.uiAntiAliasing = 0;
params.uiDefaultSkin = "default:dark";
params.windowAntiAliasing = 0;
params.windowStyle = WindowStyle.Titlebar | WindowStyle.Close;
params.entryContext = "MainMenu";
// params.entryContext = "Game";
params.dataPath = "untitled-shooter-game";
auto app = new Game(params);
// create contexts
// start application
Beyond what I just described, the engine contains all kinds of components geared toward game development. These include things like timers, faders, oscillators, a SQLite-based registry system, a basic Lua API, no-gc vectors (really just an abstraction of std.container.array), and even a custom UI system (which has become almost as complex as the engine itself unfortunately). It also has a package of modules dedicated to creating and simulating 2D top-down worlds, complete with tile-based geometry and threaded pathing.
It's also very important to note that SFML makes most of the audio/graphical functionality possible, as the engine relies heavily on it's API (through CSFML).
Do you use the GC at all?
The engine takes a hybrid approach with it's memory management, but yes I do use the GC for a lot of it's functionality. Almost all of the modules that implement the 2D game world do their allocations outside of the GC (with malloc and the relevant emplacement functions), which allows for more granular control over how the simulation's memory works and reduces the burden on the GC heap. With this reduction of GC heap usage, it allows for GC-based operations in other parts of the engine without having to worry too much about triggering an allocation or collection cycle.
I know GCs are a big source of contention, particularly so among game developers, but I have to say I've never really experienced one of the (theoretical) scenarios where a GC ruins a game's performance or something like that, at least not with the D GC. It seems to just be a matter of not doing crazy things (like running heap-based operations every frame) and pre-allocating everything that you can with pools or something similar.