DEV Community

Kelly Brown
Kelly Brown

Posted on • Updated on

Jawbone: a new game dev library for .NET 5

(Obviously, time has passed, and I'm targeting .NET 7 now.)

I want to develop cross-platform games in modern C#. I have effectively retired from C++; I want to build my little game dev empire in the latest version of .NET. Frankly, I want nothing to do with .NET Framework or Mono anymore.

After a bunch of research and lots of disappointment (a whole blog post for another day), I have begun development of a new cross-platform game library. It is called Jawbone because it is a super important part of the piranha! (My company is "Obvious Piranha". That's the reference.) This middleware will simplify deploying to Windows, Mac, and Linux.

Features

This library provides access to SDL 2, OpenGL, OpenAL, STB (images, fonts, and Vorbis), and SQLite 3. In addition to raw access, there are abstractions that make working with these tools less painful.

The entire library makes use of nullable references. This will make it absolutely clear to consumers when null is an acceptable value. Jawbone will also make use of spans.

Continuing the tradition of projects such as SQLite and STB, all source code for Jawbone is public domain.

The native libraries are also all dynamically loaded, which makes it easier to pick and choose the components important to you. The native libraries are not automatically included. (Also, see this repo for building the public domain libraries for use with Jawbone.) This helps avoid inadvertently including a bunch of native binaries in a project that only wanted the C# code.

Jawbone makes heavy use of dependency injection.

There are many more individual features I hope to detail in future posts!

Roadmap

Before anyone becomes too excited, it is important to understand that the library is in a wildly immature state. The API contract is unstable and undocumented. I will most certainly post updates later on as the API matures. I have plans for three major phases.

Version 0

I am working on two games using this library. As a result, the design will shift every day. Building real games will help me harden the library's design and add needed features, but the library will be completely filled with sharp edges. It will be unfit for public consumption in this state as it will continue to be undocumented and incomplete as there will most certainly be features that other games need that my games happen to omit.

If you are a daring developer and choose to dive into the code at this stage, just know that you will run into things that don't make sense as there is still code leftover from when I began pursuing one design and shifted over to another. :)

Version 1

After completion of those two games, I will revisit the library and begin removing those sharp edges. I will refine the API into a user-friendly contract that makes sense and form pits of success. There will be documentation explaining proper use of the library as well more sample code. Completion of this phase is when I'll feel more comfortable spreading the news to places like Reddit and submitting binary builds to Nuget. :)

Version 2

Eventually, I want to reduce reliance on raw access to the various native libraries. Raw access will always be an option for power users, but I want to build an abstraction that is nice to use without sacrificing performance. I anticipate adding more robust access to OpenGL ES and Vulkan in this version as well.

Sneak Peek

To see the framework in action, I released a binary build of the sample application (currently Windows 64-bit only). Enjoy!

Top comments (2)

Collapse
 
benwurth profile image
Ben Wurth

I love that you're using nullable references! What's the reason for making use of spans?

Collapse
 
thebuzzsaw profile image
Kelly Brown • Edited

Well, there's the primary benefits: I can avoid making copies of arrays, and I am spared the burden of passing startIndex and length everywhere. The secondary benefit is huge in game dev: a span can reference managed or unmanaged memory! So, regardless of whether the underlying data came from a new byte[...] in C# or a malloc in C (common in my native libraries like SQLite), I can write nice clean C# code to interact with it.