Here’s this week’s progress report for new updates to Toytles: Leaf Raking, my family-friendly leaf-raking business simulation available for iPhones, iPads, and Android devices.
Learn how to get it at the Toytles: Leaf Raking page.
In the previous report, I said I had spent time mocking up the indicators that tell you whether or not a neighbor is a client and getting feedback from friends and colleagues.
I also said:
I expect it won’t take me long to actually get the indicators working in the game. I think the bulk of my time this coming week will be playing the game and getting a feel for how the indicators change the experience.
Last week’s sprint plan was:
- Make it clear from the map which neighbors are your clients, ex-clients, and prospects
After 5.75 hours of game development, almost as much as the previous sprint, I…still do not have indicators implemented.
So what was I doing?
Well, as I said in previous progress reports, I wish my Past Self had spent more time on making the code more maintainable for me today. It’s almost entirely implemented in a single file and has very few automated unit tests, which means most changes can be difficult to make, and they might introduce bugs or make the game unplayable without anything to warn me.
So in the spirit of helping my Future Self, and in the optimism that I’ll be continuing to create updates to Toytles: Leaf Raking for years to come, I am moving old code carefully into separate files, adding automated tests to ensure they work correctly, and even playing the game to make sure that everything continues to work (since there weren’t tests already, I might miss something important that needs to be tested).
In this case, in order to add the neighbor status indicators, I wanted to make sure I can do so by test-driving a solution. The problem was that most of the code handling the logic of setting up and managing the neighborhood was split across a few otherwise unrelated functions and data structures.
So I spent last week moving all of those functions and data structures into a Neighborhood class. I did so as safely as I could considering that there were no tests to prevent me from breaking the game. I used the existing code, then moved a data structure into the class, including its related functions, then replaced the old function calls with calls into the functions of the class, then deleted the original data structures and functions. Then I repeated again with each of the remaining data structures until I had the game using the class instead of the original disparate data and functions. All in all, it was a fairly smooth, if tedious, process.
And the class has automated unit tests associated with it, which means going forward I am always going to be more confident that this code will continue to work in the future.
Now, it’s very easy to change code, run tests, see them pass, and not realize that I missed something important that prevents the game itself from running. It’s especially true when working with untested code. The main way to catch these issues is to bring up the entire game and play it. So one change I am glad I made was a very high level test that does nothing more than run a single iteration of the update() loop in my main game state (InGameState). It won’t catch everything, but it has helped me catch more than a few crash bugs as soon as they are introduced, saving me a lot of time.
The downside is that all of this work took longer than I expected. I really thought I was going to finish this work earlier in the week and then move on to adding status indicators to the Neighborhood class by test-driving them in.
And at almost 6 hours, that’s once again the equivalent of less than a full-time day’s work, another reminder that I wish I could dedicate more time to this project than I do. Another couple of hours, and I would have finished the sprint’s commitment and then probably would have created and published a new release.
Maybe I could have created the neighbor status indicators independent of the above the code changes above. That is, I could have test-driven the new code and left the old code as-is, and I would just have to deal with adding more untested code around the usage of the indicators. I probably could have gotten the feature into the game sooner and only then spend time moving code around and adding tests.
I might try that approach in a future sprint, but for now, I will say that I am pleased that I took out hundreds of lines of code from InGameState.cpp, which is now at just under 4,000 lines. I have another class that holds most of the data structures relevant to the game, GameData, and its header has shrunk from 359 lines to 190 lines. Most of these line count reductions are the result of moving the code into separate modules.
Lines of code aren’t everything, but fewer lines generally means less complexity, which means it is easier to write tests for.
And automated tests are a key investment into saving Future Self time. In fact, as I mentioned above, I am already getting benefits out of having a a more robust, automated test suite for this game. Unlike game developer Ron Gilbert, I have always found unit tests in games to be useful. I just wish my Past Self had valued it enough to bother adding them earlier.
Anyway, this week I expect to finally implement the neighbor status indicators and publish a new update of the game. Make sure to sign up for the GBGames Curiosities mailing list (see link below), and I’ll let you know about the next release.
Thanks for reading!
Want to learn when I release updates to Toytles: Leaf Raking or about future games I am creating? Sign up for the GBGames Curiosities newsletter, and get the 24-page, full color PDF of the Toytles: Leaf Raking Player’s Guide for free!