In today's post, I'll be talking about my latest Unity project, which is an updated version of the first game I ever published online.
I decided to upgrade No Crooks On Christmas as a kind of challenge to myself to see what I had learned about C# programming over the last year. In December of 2020, I had only been programming for a few months when I set a goal of publishing a short tower defense game by the end of the year. I worked on it pretty much every day through October and November and was able to publish it on December 1st. At the time, this was a big accomplishment! I've been thinking about going back and updating the game for some time now and with the holiday season in full swing, I thought now was the perfect time.
So let's take a look at some of the work I undertook to make No Crooks On Christmas, Version 2.0!
I hadn't worked on the project since December of last year so I wasn't really sure what to expect when I opened it back up again. I was pleasantly surprised to find that the code still worked, but it needed a LOT of cleaning up.
My first goal was to refactor as much as possible. I had a lot of repetition in my code, especially when it came to turning on/off particle effects and audio. I could see many places where I over-complicated my code, such as in the
Tutorial Manager class, where I initially used a complex
for loop that really wasn't necessary.
While refactoring, some of my methods ended up empty. It was a great feeling to be able to delete them and shorten my classes even more.
This was the part I was most excited about, but also most nervous about. I had a general idea of how I wanted to expand the game and add in new features, but it was hard to pull the trigger and start pulling apart the game so that I could put it back together again.
I started by expanding the play space so that the game's action no longer took place in just one room, but over the space of a whole house. This took more time than I wanted it to but I felt it was important to make sure I was satisfied with it. I ended up with four main rooms: the bedroom, laundry room, bathroom, and living room.
The enemies move around the play space using a simple Pathfinder system, which I left mostly in tact. I did, however, add in some code for turning the enemies once they reached the end of a path so that they always ended up facing forward.
The next thing I tackled were the special abilities in the game. I already had a Water Bucket programmed which could be used to douse the flames on the player base. However, I wanted to streamline the code for this ability and add in new, similar abilities for the player to use.
I decided to create a central
Special Ability class for the Water Bucket, a newly-created Bomb ability, as well as a newly-created Toilet Flush ability. This script controls the cooldowns for each ability and listens for player clicks on the special ability objects.
Once an object is clicked, a switch statement determines which method to call next.
I would have preferred to have all of the special ability mechanics in one script, but I did end up having to attach short scripts onto each special ability object to handle any mechanics that were specific to that ability. I'm always looking for ways to centralize my code and write it so that it can be easily scaled up as I'm adding in new features. This felt like a fairly satisfying way to handle the special abilities in my game though, so I was ready to move on to the next thing.
Another big project I tackled was adding in some more enemy types. I could probably write a whole blog post on this alone since there was a lot involved in this process. Not only did I have to perfect and in some cases create enemy animations, but I also needed to program unique abilities for each enemy. I wanted abilities that would have a sizable impact on the player but wouldn't be too complicated to code.
In the previous iteration of the game, there was only one enemy (a goblin) with no special abilities. This time around, I added in three more enemies.
Eyebat : Uses laser beam to reset the special Bucket ability (making it harder for the player to use the heal-over-time ability)
Spiky Turtle : Resists turret attacks
Slime : Resists special attacks such as the Toilet Flush and Bomb
I also added in a fun little 'intro' each time a new enemy appears on the screen. In my code, I use
transform on the Main Camera to zoom in, and then reset the Camera position after the intro is finished.
Since I was using premade assets, I knew it might be tricky to alter the animations that came with them. Normally, animations from premade assets are read-only, but you can usually get around this by making a copy of the animation and modifying it in the Animation window.
Once my animations were set, it was a simple matter of hooking them up in the Animator window and making triggers so that the animations transitioned in and out at the appropriate times in the game.
I spent some time recently learning about game programming patterns via GameDev.tv's excellent course and I was eager for an opportunity to put what I'd learned into practice. One thing they stress in the course is that once you know about patterns, it's easy to overuse them or to use them when it's not really necessary. So I knew that I needed to be careful in my judgement.
I could, however, see several places in my project where the Observer pattern would be really useful.
Player Health class controls when the presents start on fire, so I started by creating a public event in that class and referencing it at the top of the script.
Next, I added a reference to the
Player Health class in my
Presents class and subscribed to the
onTriggerFire event in the
With this in place, my Presents class now automatically runs the
IgniteFlames() method when the
onTriggerFire event occurs. Cool, right? This eliminates the need to use public methods, which can create a lot of messy spaghetti code. I really like the Observer pattern and can't wait to use it in some of my other projects.
This was less of a priority, but I did spend some time cleaning up my project assets and making sure they were properly organized. I usually try to have a dedicated folder for each type of asset (Scripts, SFX, VFX, Images, Animations, etc.), but as a project expands, it's inevitable that there will be assets out of place. Having well-organized assets makes it so much easier to invite others to collaborate on your project. Plus it's much easier to find things when you come back to your project after some time away.
One of the noticeable visual changes I made was to the lighting in the game. Initially, I had gone with more cool tones but I decided to warm things up in this iteration of the game. You can see the color difference in the screenshots below.
I've been focused lately on improving my
git commit messages and I strove to be more intentional and conscientious when writing commit messages this time around. I think it really did pay off, especially when I had to unexpectedly roll back my project to a prior commit just before uploading it to Steam! If you haven't spent some time considering the form and syntax of your
git messages, I highly recommend it. It's time well-spent!
Now that the new version of the game is completed, it's time to promote it! I have to admit that this is my least favorite part (I think that's common for developers!).
Honestly, after working my way through this behemoth of a project, I've realized that my favorite part of game development is actually the coding. I do love curating and creating assets as well but I think that programming is where my heart truly lies. It's such an exciting experience to learn something new (like the Observer pattern I mentioned above) and implement it for the first time in my code! Hopefully I'll be doing that a lot more in the future as I continue to learn and develop my programming skills.
Happy Holidays and thanks for reading! 🎅🏻