Anyone who has been following the progress of .NET Core knows we’ve been talking a lot about console and server applications. In this blog, I’ll be exploring another use of .NET Core, and showing a multi-platform 3D game engine, editor, and game that I’ve built from scratch. As a dev on the .NET team, I follow a lot of community discussions and have seen some increased interest in this area (for example). I’m hoping this blog will shed some light on the capabilities of .NET Core, and excite others to explore this space.
In this first post, I’ll be introducing my game Crazy Core, an arcade-style 3D platformer where you guide a ball through various obstacle-filled levels. This will be a broad overview, and subsequent posts will dive into more details about the game, its engine and editor, and the technologies I’ve used to make it all work.
Disclaimer: this is purely a one-man developer game built from scratch. It will be evident that no artists were hired during the creation of this game, and I can’t promise that they won’t feel harmed upon viewing the primitive artwork.
This is a self-contained program. Simply download the zip file for your platform and run the “CrazyCore” executable inside it. If you are running on Ubuntu, there are some prerequisites that need to be installed first.
The mechanics of the game are pretty self-explanatory. You control a ball, rolling through a 3D world. This world is very simple at first. Gradually, new mechanics are introduced, and the environment and obstacles become more and more complicated as you progress. The final levels have some truly “crazy” mechanics, if you manage to make it that far.
Why .NET Core?
Primarily, this project was a great way to put .NET Core through its paces, and test a scenario off the beaten path. Although I may be a bit biased, I also believe .NET Core has a ton of technical advantages for games:
- Open-source. You can view, modify, and optimize any part of the stack.
- Lean, optimized runtime designed for multiple platforms. This means that there is significantly less to worry about when releasing on different platforms.
- It’s .NET. You can use any .NET language with all of the great tools and debugging experiences that are already available.
- Future-facing. .NET Core is rapidly evolving, and performance optimizations are merged in every day. On another front, the CoreRT project is going to be a very interesting technology for building games. While not ready for prime-time yet, the ability to deliver a heavily-optimized, ahead-of-time-compiled binary will be great for games.
Game Engine Architecture
As with any game engine, there are a ton of different components intertwined here that make a real-time 3D game possible. I hope to explore some of these topics in much more detail in subsequent posts, but to give a general idea of the structure and capabilities of the engine, I’ll highlight the most important things here.
- The engine is component-based, with a programming model loosely similar to Unity. I’ve used Unity a lot in the past, so this was a familiar way to develop for me.
- Support for both Direct3D11 (Windows) and OpenGL (all platforms) for graphics. The graphics are implemented on top of an API-agnostic abstraction layer called “Veldrid”.
- Support for both XAudio2 (Windows) and OpenAL (all platforms) for audio. There is another (much thinner) abstraction layer which allows either API to power the 3D positional audio in the engine.
- Windowing and input handling are handled by the OpenTK library.
- Real-time 3D physics, using the awesome BEPUphysics library.
- Custom asset management and serialization system, used for storing a variety of things including:
- Binary assets (models, textures, audio, etc.)
- Entity and component state
- Scene composition and linkage
- Meta-information, like player progress and high scores
- Project settings
To construct the different levels of the game, I built a separate editor application, which reuses various components of the engine. The editor is a standalone 3D program that lets you view and modify game assets, put together game entities, construct full scenes, and manage project-level options.
Like a typical editor, the game itself can be tested from within the application, and various pieces of game state can be tweaked live. The editor also has features enabling things like project publishing, debugging, code hot-swapping, and more.
This video above shows some of the cool things you can do by tweaking things live in the editor.
One of the most useful features of the editor is that it is trivial to run on multiple platforms, since it also uses .NET Core. This makes it extremely easy to quickly apply and test changes to the engine and game anywhere.
Although I said this was built “from scratch,” I used quite a few open-source libraries for features of the engine. Some of these libraries are available on NuGet and were used as-is. Others needed to be recompiled for .NET Core, but none needed very complicated re-writing. I’ve found that game-related libraries are often low-level enough that their dependencies are not difficult to satisfy.
Below are the libraries I used in this project, and what they were used for. Anyone interested in game-related stuff in .NET should take a look at some of these libraries, they are quite cool!
- SharpDX – Bindings for Direct3D11 and XAudio2. These technologies are Windows-only, and are used by default there in the engine. SharpDX already supports a PCL profile, so it can be used unchanged on .NET Core.
- OpenTK – Bindings for OpenGL and OpenAL (alternatives for the above), as well as windowing and input. This library is quite large and quite old; it needed some work to compile on .NET Core.
- ImageSharp – Cross-platform image loading. This is used to load all of the textures used in the game. Shout out to James who is doing a really great job with this project.
- BEPUphysics – Real-time 3D physics. This is a really cool and well-designed library. It recently moved to GitHub and a very intriguing v2.0 is planned.
- dear imgui – Immediate mode UI, used for the editor’s GUI, and for the menus in Crazy Core. I’ve written a .NET wrapper for the original C++ library: ImGui.NET.
- SharpFont – TrueType font loading and rendering. This is used for some 2D text rendering components in the engine.
- Newtonsoft.Json – I think everyone knows this library. I’ve used it to serialize all of the custom data types in my engine, including entity, component, and scene data.
Thanks for reading! I hope this post has illuminated some of the things that are possible with .NET Core today. In the next post, I’ll talk more about how 3D rendering is handled in the engine. It is the most complicated part of the engine, but also turned out to be the most interesting and fun part to develop. Stay tuned!