Sunday, December 14, 2014

New Programming Project


The original game client, written in Dart and ran inside a browser.

A year ago I was researching new programming languages and came across Dart, Google's alternative to Javascript. I gave it a shot and started writing some Dart programs to get a feel for it, and decided to write a simple Diablo clone for it. I used the 2D library StageXL along with Clint Bellanger's sprites used from his game Flare to mock up a simple game where you can run around, teleport, and have skeleton minions.

Due to limitations in performance, I decided to move to C++ with a complete rewrite of the game. The biggest issue I ran into with Dart was that cross-thread communication required only very basic supported types, including numbers and strings. On top of that, it required communication to be done as pass by value. This meant that whenever I wanted one thread to send data to another, I was sending up to megabytes of information at a time.

A rewrite of the game in C++ using SDL2.

Although my experience with C++ prior to this project was a only single class at university, I did a lot of reading and my background in C was strong enough to trudge through it in a brute force manner. The above picture shows the results of what I was able to do using C++14, Boost, and SDL2.

The biggest weakness of my project was that it was very much hacked together due to inexperience with the language. I originally used Boost's "any" variable (which can hold any variable dynamically, to be cast to the correct type later) a lot to fill in whatever data I needed. Additionally, I tried way too hard to make everything very generalized; my attempt being to allow for as many possibilities in the future. An example of this was the spell system, which read from a text file and could use any combination of spell effects at varying levels of strength and duration. This made things very complex and hard to keep track of instead of just writing dedicated spell functions.

An early version of the second rewrite in C++, using SFML.

The whole project was a mess because I used it as a platform to learn C++, all with minimal experience. During this time I read several books on C++, including "The C++ Programming Language", "C++ Concurrency in Action: Practical Multithreading", and "Intel Threading Building Blocks: Outfitting C++ for Multi-core Processor Parallelism". Additionally, I studied books on both GIMP and Blender to learn how to create my own media content for the game (all content in the rewrite, including the screenshot above, are self-made). The results in the screenshot above show  a complete rewrite of the game.

Although it still needs some more work (most notably the UI and lighting) to catch up to the old version of the game, it's already apparent how much better the game is performing. A philosophy I learned in the "Intel Threading Building Blocks" book is that when you write a program and expect to use concurrency, you should design the program from the ground up with that in mind. This is a critical design decision that was not made in the old version of the game. Originally, everything was mutex protected for thread safety. This was costly and created a lot of thread blocking; an ugly tack-on that performed poorly. Instead, every variable that has to be accessed by multiple threads now uses an atomic data type; no mutexes are used (aside from whatever is internally used by the atomic and concurrent types defined by the C++11 standard and TBB library). Additionally, using the Threading Building Blocks (TBB) library by Intel, a good portion of the game loop is handled automatically by Intel's thread pool manager. I also used TBB's concurrent containers, specifically the concurrent hash map and concurrent queue for cross thread communication.

Threading Building Block's thread pool kicks in to maximize processor core utilization as demands on the processor increase. In this case, going from handling 10 units (left) on screen to 10,000 (right).


From the images above, it becomes apparent very quickly how effectively the game utilizes all the cores on the system. In the first image, with only 10 units, the demand on the CPU is relatively light and only a few cores are really needed for processing. Once we increase this to 10,000 units being handled simultaneously, the TBB library spreads all that work amongst the 8 threads, greatly improving performance. The beauty of this library is that it will use as many cores as you give it, so theoretically performance should only improve as computers increase in core numbers.

10,000 units filling the screen.

In later posts I'll describe how the actual game is implemented, but for now my next plans are to add lighting and the interface. Also, I plan to go into more detail on the graphics of the game, which were made using Blender, GIMP, and the Python PIL library. It feels good to start posting again on here.

No comments: