A New Game Written in D

Kenny Shields mail at kennyshields.net
Tue May 17 23:19:55 UTC 2022


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:

```d
class MyContext : Context
{

     this(Application app)
     {
         name = "MyContext";
         super(app);
     }

     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):

```d
void main()
{
     // 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
     new MainMenuContext(app);
     new GameContext(app);
     // start application
     app.start();
}
```

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.




More information about the Digitalmars-d-announce mailing list