The Big Refactoring

Screenshot: Askutron CLI

What’s this? Is Askutron in 2D now? Not quite. It’s still a 3D game. It does have a text client now, though. Let me tell you why.

About one and a half years ago we started working on Askutron. Back then both of us didn’t really know what were are doing. We were still learning Unity and at the same time just tried to get the game implemented as quickly as possible.

Unsurprisingly the resulting code and Unity project hasn’t turned out particularly elegant, well organized, or even well optimized.

Rough spots

“Organic” code like this combined with our inexperience with Unity lead to several issues. While we have had a working game since late 2017 these issues started to slow us down.

Stability & code quality

We didn’t write any tests for our game. Everything was just cobbled together, tried out and adjusted until it seemed to work alright. This left room for a number of bugs.

Main game loop in Playmaker

This is what the main game loop of the simplest quiz round (Point Hunt) in Askutron looks like in Playmaker. It’s a finite state maschine (FSM) defining what happens when during the game.

It’s good to have a visual representation. Especially if you are not a programmer but mainly a game designer. But using Playmaker our core game logic was spread across numerous Unity screens like this on one hand and a C# project on the other. This made it difficult to stay on top of things. Considering that both of us are first and foremost programmers this was really unecessary.

Another big downside of how we used these FSMs is reusbility. For each new round we would simply copy this FSM and adjust it for the new round. For instance in the Viewpoints round players are asked 2 questions before the actual answer is revealed.

This duplication can lead to bugs when you need to update something across all game rounds, but forget to do it in one. This is particularly easy to do because you have to click on each state (box) in these diagrams and only then see the details for each in a separate section of the window.

Development hurdles

I in particular have always been a bit reluctant to work in Unity. It is somewhat sluggish. Also collaboration is quite cumbersome. From the perspective of a software developer who works with Ruby and tracks their changes using git this seemed to be quite a step back.

Unity allows you to make games for multiple platforms. For Askutron we aim to support Windows, Linux and OSX. The actual development is always happening on Windows, though, since Unity only runs on Windows and OSX.

Only when we actually built the game for the other platforms through Unity and then actually tried them would we discover problems on these platforms.

Performance

Even with the very simple graphics Askutron takes a lot of power to run smoothly. This is mostly due to the extensive use of co-routines in Unity for everything from animations to loading content.

The game only starts once it has finished loading everything, and takes a quite noticable amount of time.

Doing things better

Our solution was to start a big refactoring. That means we would restructure and partly rewrite big swathes of code, but in the end it will be functionally the same.

All the players will notice is improved stability and performance. At the same time, for us it means that we can work faster and ouput a better quality game.

The product of this refactoring is the Asktron Core. Our core library which implements the core game with everything including:

  • the complete game logic
  • loading of content (questions, media)
  • user interaction including mobile controllers
  • the network layer for the multiplayer mode
  • unit and integration tests for the whole game

The core is a plain C# library. It doesn’t need Unity. It runs completely headless. An added bonus is that I can now develop the game on Linux. The main advantage, however, is that it allows us to fix the issues mentioned above.

Improved stability & code quality

All the logic is in one place now which makes it easier to keep track of everything. Where we copied PlayMaker state machines before to implement new game modes we now just use plain old OOP techniques to extend existing logic.

For instance the whole code necessary for implementing The Fastest Finger round is the following:

public class FastestFinger : Round
{
    public static readonly int[] Points = new int[] {400, 300, 200, 100};

    public override int GetScore(Game game, Player player, bool correct)
    {
        if (correct)
        {
            var order = (
                from p in game.Players
                where p.AnswerCorrect
                orderby p.AnswerMs ascending
                select p.Id
            )
                .ToList();

            int i = Math.Min(order.IndexOf(player.Id), 3);

            return Points[i];
        }
        else
        {
            return 0;
        }
    }
}

All we do is override the way the score is determined so that it is dependent on how fast the players answered.

Most importantly there are now automated tests for the whole game. Each round is tested separately and all in conjunction with each other. Changes pushed to our main repository on gitlab are tested and only merged into the master branch of the game if all tests pass.

This makes it a lot harder to introduce new bugs into the game when changing existing code or adding new features, making sure the game is a lot more stable.

Overcoming development hurdles

A big part of the development can now happen in a plain C# project. All code is tracked using git. This is a lot faster and easier than Unity’s collaboration feature for us.

Since the core is now a plain C# project I can actually develop on Linux. Which is a big plus for me personally seeing as I do work on a Linux laptop.

Besides that we can now run all the core tests on all supported platforms to make sure that the core itself including the multiplayer mode work correctly across the different platforms.

Performance

To be frank we weren’t even concerned with performance. We never had any complaints. But it turns out that a side effect of our refactoring was that the game now performs a lot better.

We don’t use coroutines for everything anymore. Instead we use good old threads.

Due to this the loading times were reduced drastically. The unity coroutines all run in one thread. This meant that every bit of content and each media file (such as audio and pictures) were downloaded one after another.

With the new code things can be downloaded simultaneously which speeds it up a lot. Also we are now smarter and don’t actually wait until everything is loaded. As soon as the first question is loaded the game starts. While it plays the rest is loaded in the background in said threads.

Game Clients

With the whole game being handled by the Askutron Core all that is left is the actual presentation.

Text Client

Remember the screenshot from the beginning? Having the game logic encapsulated like this also allows us to easily create different presentations for the game. To put this to the test we implemented a Command Line Interface (CLI), or text, client for our game. This is quickly done. It doesn’t require any 3D assets and can be run anywhere, even on a server without any sort of graphics card.

This allows us to quickly prototype new game modes and test changes in the game before starting to work on the 3D representation.

Askutron Final

This is the game’s final played in the text client. It’s very basic but contains all the necessary information and allows us to test and develop the game rapidly without even having to fire up the big and slow Unity.

It includes buzzer sounds. It also supports mobile controllers and can be played online, too!

3D Client

This is what the Unity project is for. It contains zero game logic. It has the core as a dependency. All it does is delegate the input of local users (via keyboard or controllers) to the core and then render the game’s state in 3D.

Askutron 3D

It still looks just the same as before.

While it doesn’t include any actual game logic, the 3D game client of course does a lot of other important things. As opposed to the text client we need 3D models. Those need to be animated. We need to define the camera movement and have our host move around to make the game look more dynamic and lively.

State of the art

We have finished the refactoring of the core game logic and it’s fully covered with automated tests. The text client is complete. You can play through a whole game, alone or with other plays locally or online.

Changes

At the start of this post I said that after the refactoring the game would be functionally the same. That’s not entirely true.

We actually did change how Cut the cake and the final work a little considering the feedback we got from our players. I will cover what we changed exactly and why in a separate post.

The next update

We are still working on finishing wiring up the 3D client to the new core. At the same time we are working on improving the 3D client. Our current plan is to have the refactored game ready and the Steam update rolled out in December.

Outlook

We finally have found a 3D artist who helps us by building a proper studio. Also we’re working on the free Askutron Film Quiz DLC at the same time. More on that soon in separate posts.