Dev Article - Refactoring
Author: HS_Dave
- Posted on: 22/02/2015
Post Type: Blog Entry
TL;DR - Write better code and it'll save you time later. Pretty pictures in future blog posts.


This one is for the dev's. I want to shower you all in screenshots and visual media but I'm "not allowed" until it's "ready" says the artist. So instead I'm going to chat on about some of the work I've been doing codewise - what it entails and potentially how to avoid having to do it yourself if you are teaching yourself development right now.

The majority of the work at the moment falls roughly under the category of "Refactoring". This is where I take the code base and try to fix everything I did wrong 7 years ago. The ultimate goal is to end up with code that is a lot more concise, readable and maintainable.

So, why?

When I decided I wanted Dodeka to be more than just a pc port and that I wanted to add new features I immediately started hitting problems that were caused simply by how the old code was written. Even relatively simple things like face lifting the GUI was turning out to be a nightmare with everything hard-coded.

I decided that if I started "cleaning up" then I could save a lot of the game logic (which is actually pretty good, albeit untidy) and at the same time I could start altering code to prepare it for my new additions.

What about just rewriting it?

So that's the million dollar question. A friend of mine who works for a game studio in Canada actually recommended I just rewrote the game and I was umming and ahhing until I decided I actually wanted to save as much of it as possible. In hindsight I probably should of started from scratch.

One thing that has become clear during this process is that my programming is radically different from 7 years ago (as I should hope!). Not only do I tend to write tidier and quicker but I actually have a completely different style that becomes obvious when you compare blocks of old and new code in Dodeka.

On the plus side I have gained a good insight into my development as a game dev by doing it this way. If you are in a similar situation then ultimately you will have to answer this question yourself.

Some practicals then.

The State Machine of Doom

A lot of tutorials used to have a state machine style setup for controlling program flow. For example you would have a DrawGame() and Update() method and inside each you'd see a small switch() statement that would check engine state. For example your DrawGame method may of looked like:

switch(GameState)
{
case States.Menu:
     Menu_Drawing_Code;
        break;
        
    case States.InGame:
     Game_Drawing_Code;
        break;
}

Or something like that. When you are following a small tutorial that's fine. But when you start working on a large game and you just keep adding little tidbits to the state machine it quickly becomes disgustingly convoluted! This happened inside Duodecad with some case statements having additional switches inside, REALLY BAD idea.

State machines are a good thing. Filling case blocks with lots of game code is not. Get your case statements to call external methods which handle things - it will save you a lot of headache later on. If you use visual studio then you'll notice switches are not collapsible. There is also no "go to" quick bookmarking for them. When you get lost in a giant state machine of doom you really ARE on your own, so do not create them.

Extracting Code

Finding code that can be moved ("extracted") to an external method is a key part of refactoring and it does not just apply to state machines. It is very easy as you work on a project and add new features that you just "add a line of code" to an existing method. 7 months of development later and you've built a 650 line mega method one line at a time unless you've been doing frequent refactoring sweeps. Find groupings of code that can be moved to their own method and replace the original block with a single call to that method. Naming the method something in plain English (or your own native language of course) will doubly increase the readability of your parent method.

Taking an example from my own code again, I had ended up with a mega method called UpdateCards(); It's job was simple: Tell all the cards where they are positioned on the screen.

Originally there could be 2 places a card would appear: On the side of the screen or on the actual game board. The first thing that was added was Player 2 - their cards were in a different place. Then I added an effect that showed a card sliding off screen then back down to the board when it was placed. Then I changed scaling of a card if it was selected and then they had to be rotated if cards were hidden from a player and.. you get the point. It went on for ages.

Younger me had never heard of refactoring but would of benefited a lot from it. Most of that code could be extracted into smaller, readable methods. PositionBoardCards(); PositionCardsInHand(); UpdateCardMovement(); etc.

Because of this the main UpdateCards() function is now very easy to read, you can see exactly what it is doing where and if a bug turns up or a new feature is required its very easy to just go straight to the piece of code and get the job done.

Naming and Readability

Readable code is easy to work with code. You know where you are, what is happening and thus what WILL happen if you add or change something at any particular point. To that end the simplest refactor and one of the most useful is the rename. Do you have a variable called xt? That is not useful - what is it doing? It makes perfect sense to you right now but you'd be amazed how it wont if you come back to it in 5 years. Let alone if someone else comes to look at the code.

With the advent of super powerful IDE's (big Visual Studio fan here), incredible Intellisense and auto completion there is no need to use tiny short hand for everything. It saves you nothing. Perhaps you're a javascript developer and you're trying to save on filesize? A worthy aim but write good readable code and then minify your js using a tool later.

There are of course conventions that are completely fine. Everyone knows that N in a loop is a counter and X/Y/Z in iterative loops are self explanatory. But things become a bit vague when you write xs instead of XSpacing and cw instead of CardWidth.

I am also a big fan of keeping things in separate files. Each class, each enum etc I move to an external file with the same filename as the class or enum inside it. Visual Studio has good integration for this type of system too where if you rename a file in the Solution Explorer it will automatically rename the class inside and update references to it. It just means everything is always easy to find.



Refactoring is a giant topic and I could be writing on forever about it. There are several books you can buy and a plethora of videos on youtube that can help explain it all in more detail, I really recommend having a look. But if I had just been covering the 3 headings above when working on my original game the changes I'm making today might well be done already.

Look after your code and it will look after you :)
Dodeka Development #3
Author: HS_Dave
- Posted on: 04/02/2015
Post Type: Blog Entry
Well I managed to skip a whole month of blog updates, but better late than never right?

I may not have been blogging much but I *have* been working, I promise! The network back end for the Dodeka match making service has been really taking shape. I say the "Dodeka match making service" but as I suggested in the previous post the "Heavenly Software match making service" is more accurate as its designed to do the work for all games I make. At the moment it is going simply under the name HNET but I am open to suggestions :)

The service is currently providing game discovery and live chat for Dodeka as well as some essential services like NAT punch through. It also has a decent framework for providing Achievement like services which I'm umming and ahhing about adding - if you have an opinion on that then do drop me a line! There is also potential for things like competitions and ladders in the future but due to the work involved that would be considered AFTER a successful release if the game seemed popular enough to merit the investment.

So, pushing the boring network updates out the way let me move on to the game. Sadly it's almost as dull as network chat as most of the work over the past month has been on GUI features as I attempt to craft a system that is a lot more fluid and quick to navigate - I know one of the major failings of Duodecad is the GUI was quite clunky and not always clear. It's worth the time investment, I promise :)

I have also invested a fair chunk of extra time rewriting a lot of code to not depend on XNA so much anymore. Infact the ultimate goal is that the Dodeka engine does not actually know what XNA is despite the fact it uses it for all it's rendering etc. This move was made after I received a very welcome message from a fan on facebook who said they really enjoyed Duodecad and wanted to know if Dodeka would also be on Xbox. Now, I can't promise that it will be. But it did prompt me to start thinking about other platforms that people use and how I can bring the game to them.

Properly abstracting certain parts of the engine will make this "possible" but not guaranteed. But I *DO* want to bring Dodeka to as many platforms as possible (including mac, linux, consoles and tablets) so to make sure I have a good fighting chance of doing that I'm laying down the ground work now. However when it comes to the consoles there are additional licensing fees and usually dev kits required etc so just having code that "will probably work" does not mean I will manage to push to that specific platform!

As always, it's not only me that has been working. Elin is still drawing away - mostly concentrating on the GUI as that is where I have put the focus at the moment but also bringing new cards to me!

So as a little treat to make up for my lazy blogging habbits here is a look at the latest one I was sent:



and a link to the high resolution version: here

This is one of the new level 10 cards that you'll see in Dodeka. One of the new features the game will have is that any card can be potentially be found as a rare "foil" card - it's going to be interesting to see how these look on shiny backgrounds!

Let us know what you think through facebook or twitter. I'll try to blog a bit sooner next time!