Finite State Machine - Refactor Take 2

Published November 04, 2023
Advertisement

I finally came back to my Gaslands side project after about a year. For those that don't know, Gaslands is a turn-based table-top miniatures game where you modify toy cars to look like Mad Max vehicles. The goals of a game changes based on the scenario, but in general you move around with special Maneuver Templates and shoot each other's vehicles with various weapons. Check out the Table-Top game here: https://gaslands.com/

File Names

When I left off last time, I had coded up a Finite State Machine and started putting it to use. Here's a link to the previous article: https://www.gamedev.net/blogs/entry/2274204-finite-state-machine-for-turn-based-games/ After that post, I got most of the Movement Step working. Even though it worked, there were still a few problems that made working in it difficult. When debugging the code, I knew what file the problem was in. But finding out where I was in the sequence (where we came from, where we're going next) was extremely difficult. The steps during an activation are very sequential, but Visual Studio sorts all the files in a folder alphabetically. As you can see, below, the sequence bounces all over the place making it extremely difficult to have a mental picture of what was going on.

Old File Names - The sequence of steps bounces all over the alphabetical listing.

One thing that I did was put a prefix on the filenames that identified its place in the sequence. And for state-machines with substates, I added another _00 to further identify them. This simple trick made it TONS easier to track what was going on. Compare the previous layout to the picture below and see for yourself. If we had a problem in the MoveToTemplateStep, I know what the previous step is at a quick glance.

New File Names - It's so much easier to see the sequence now.

Single Responsibility

Another problem I was running into was deciding where certain bits of code should live, and how the different pieces communicate with each other. Originally I had a GameController class that different game states might fire a message off to. Then it would route those to other bits of code, show some UI, perform some game logic functions, and then call back into the game states. Different bits of code were scattered throughout the project. Again, this added complexity to the project and made it difficult to debug.

Here's an example of how things existed in the previous version. For the SelectManeuverTemplate step, the state machine sent a message to the GameController. It would then show the UI, let the user confirm their selection, and then mark the message as complete. It was responsible for too much so I just cut out the middle man. So now the UI listened for the message directly. Let the user confirm their selection and then called the OnComplete callback. Instead of the GameController managing more states outside of the state-machine, I added more states and everything started flowing more smoothly.

There was also several bits of code that was scattered across the project. This code existed inside the GameController, inside some UI Classes, and inside the StateMachine steps. I pulled all this code out into a separate GameLogic class. This allowed me to wire them up to a test framework so I could verify their correctness individually. There wasn't much left in the GameController class at all and I was able to drop it entirely.

According to git, my previous commit before this refactor effort was about a year ago. And after three weeks of work, the functionality is back where it was. >.< However, now the project feels MUCH cleaner so it was definitely a good investment. I have a good idea of where new code should go and how new features in the combat game are going to be implemented. And I'm really looking forward to getting back in the code to tackle what's next.

A full round of movement where we take turns between the blue and green teams.

Next Steps

I'm not sure what I'll be working on next. Probably one of these.

  1. Finish up the Movement Step - I got the rough basics of the movement step/turn structure working, but there's still plenty to do with the MovementStep. I need to create more UI / player communication instead of just using the Unity Console Log.
  2. Wire up some cool assets instead of my dev art - I also have plenty of Unity assets that I have bought over the years. Hooking up some actual cars/motorcycles would elevate the coolness factor. I might save that for when my interest is waning a bit.
  3. Start work on a Save Game system - I'm actually leaning towards working on the Save Game system early. I see so many projects leave that until the very end and it quickly becomes a nightmare trying to shoe-horn it in.

Tips from your Uncle Eck

  1. Complexity is the enemy! - If you find your code base starting to become a pain to work in and difficult to debug, it slows down productivity across the board. Take a step back and refactor it into something more manageable.
  2. Refactoring your code should be part of your dev process. - It does take time, but it quickly pays dividends. A cleaner code base has less bugs, and it's easier to fix them. It also helps keep your motivation high.
  3. Keep a Notes.txt file in your project and take notes on what you're thinking/planning to do. It was a year since I worked on this side-project last and it greatly reduced my spin-up time to get back into the swing of things.
2 likes 0 comments

Comments

Nobody has left a comment. You can be the first!
You must log in to join the conversation.
Don't have a GameDev.net account? Sign up!
Advertisement