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.
Introducing....No Crooks On Christmas!
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.
Tutorial Manager script received a lot of refactoring and cutting. The lines of code highlighted in pink were all deleted.
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.
An empty method ready for deletion!
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 game's four main rooms
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.
TurnEnemy method is triggered via a Collider which sits on each "turning block."
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.
This section controls whether a special ability is ready to use.
Once an object is clicked, a switch statement determines which method to call next.
The switch statement controls 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
The four different enemies in the game
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.
Introducing a new enemy.
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.
This simple code controls the transition between the "Defend" and "Idle" animations for the game's Turtle enemy.
Game Programming Patterns
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.
Separating assets into different folders makes it easier to find what you're looking for
Odds and Ends
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.
The original lighting in the game was more blue-toned and less warm.
Warmer lighting and a simpler UI make for a better player experience.
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! 🎅🏻