- Genre: Tower defense with a vaguely roguelike choose-1-of-3 upgrade system
- Links: play it on itch or check out the code on github
- Engine: Godot 3.5
- Time Spent: Uh. 15ish days? May 8th - May 13th part time, May 29th - June 11th full time1.
- Other Stuff: This game shamelessly rips off the UI of DesktopTD, one of my favorite games of the flash game era. Thanks for the many hours of enjoyment, DesktopTD!
I was so excited when I first combined 'many projectiles' and 'exploding projectiles'
High level thoughts
Tower Defenses were a pretty popular genre when I was growing up (probably because they were a great fit for Warcraft 3 custom maps and maybe not that hard to make in flash?) and I loved them back then. I’ve known since before I actually started this process of making games that I wanted to make a few tower defense games but held off on making one till now because I wanted to make some less complicated things first.
I’m pretty happy with how ReShape came out! I think the game feels relatively good (although it’s got the most complicated UI of any of my games so far and I could easily have spent two more days just working on the UI - it’s far from perfect). I enjoyed focusing on building a game that I, as a tower defense lover, wanted to play.
I wanted the game to feel chaotic in a fun way - and in particular I wanted almost any possible combination of tower upgrades to feel crazy and imbalanced and like you were getting away with something. I kept the sentence “‘does not stack’ might be the saddest phrase in game design” (from this RPS article on Slay the Spire) in my head: I wanted everything to stack.
And I mostly did make things stack! If a tower shoots multiple projectiles that explode, those explosions stack. If you get a tower that buffs other towers in range, that buff stacks. Damage buffs stack multiplicatively. etc. I was delighted at how chaotic the game felt once you got a few upgrades and I did feel like I was getting away with something when I got a particularly fun set of upgrades.
But I don’t think that I achieved the strategic depth here that I imagined at the start of the game. A commenter points out that the optimal way to play was to only use 2 tower types and I think that’s right - and unfortunately I don’t think there’s quite enough depth to developing your buff tower vs your DPS tower2. So maybe more strategic depth is a goal when I make the next tower defense :)
Adding juice and lacking a theme
A day or two before shipping the game I spent a few hours adding some polish and a little bit of ‘juice’ and was really shocked at how little it took to make the game took and feel a whole lot better.
No juice on the left, juice on the right
The stuff I did was really simple: towers make a sound effect and pulse when they shoot, and they flash when they’re upgrading. Creeps make a sound when they spawn and a sound when they escape. The “rank up” button begins to pulse if you don’t use it in the first few turns.
But it made a big difference! There’s plenty more I wanted to do here (like add more sounds) but didn’t because of lack of time (or because I was worreid that the sounds would be grating) - but it was cool to see how little it took to make the game feel better.
I’m also really excited that I’ve improved here - it was pretty obvious to me what I could do to start adding a little juice and it didn’t take me long at all to add it. And I’ve started recognizing common techniques in the wild! Last night I was watching someone play Brotato and said to myself “oh, the death animation here is just tweening down scale and rotation at the same time!” Cool stuff.
However one thing that really jumped out at me after finishing the game was how themeless it felt. It’s a game where you build shapes that shoot at other less common shapes. The game might do an ok job of appealing to folks that already know that they like tower defenses, but it is probably not gonna draw anyone in. While building ReShape I listened to an interview with George Fan, the creator of Plants vs Zombies (which may be the best example of a tower defense dressed up as another game out there!). At several points Fan talks about the importance of having a theme both to draw folks in and to make it easier to explain your game: he mentions how everyone knows that plants don’t move, so the game doesn’t have to explain why the plants stay in place. It’s a good interview, and next time I’ll make a TD I’ll aim to have a real theme.
Pathfinding and some other technical details
Skip this if you don’t want to read about programming!
Early versions had the creeps display their pathing like this for debugging purposes.
This was probably the most interesting game that I’ve worked on technically so far.
I found Godot to be a particularly good fit for much of the game: I was able to compose the game into a couple of different parts (Creep, Projectile, Tower, UI), write the logic for each of those components separately, and then throw them together with just a tiny bit of glue and have everything work3!
The game also came with a fun technical challenge: adding building and pathfinding to a grid. I changed my approach here pretty substantially between my prototype and the final product and thought it’d be interesting to write about that evolution.
Here are the nouns and verbs I think you need to build a game like this:
- The coordinates of all cells that are pathable
- The coordinates of all cells that are buildable (a subset of 1. in this game, but it doesn’t have to be that way)
- A way to keep track of whether a cell is currently unpathable (because a tower is there) or unbuildable (because a creep or tower is there)
- A way to go from “a creep” to “the cell(s) that creep is currently in”
- A way to go from “the mouse” to “the cell that the mouse is currently pointing at”
- A way for a creep to, given a destination, ask for the shortest path from their current position to the destination.
My original approach conflated some of these problems in confusing ways - for example, the pathing grid (the thing we run A* on) had some hardcoded stuff relating to which parts of the grid were buildable and which parts were pathable.
My final approach looked something like this (note: cells in this example are 16 pixels wide):
- Anything (pathable stuff, creeps, towers) is a child of a node called “Battlefield” - allowing us to adjust the position of the battlefield without impacting logic elsewhere.
- Pathable stuff offers a function that returns “the list of points in this object that are pathable” - e.g. a 1 x 3 box might return [(0, 0), (0, 16), (0, 32)], along with a function that says whether they’re buildable.
- The process of constructing the data we eventually feed to A* is just “ask each pathable thing what points on it are pathable, add those points to the position of that pathable thing on the battlefield, and make sure that there’s no overlap.”
- To determine where something (like a creep) is we “snap” its position to the grid (using integer division, divide and then multiply it by the cell size).
- Creeps are told their destination (as a coordinate pair) when they’re created and get a path by snapping themselves to the grid and then asking our AStar object where to go.
- To determine where the mouse is, we take the position of the mouse on the screen, subtract the position of the left corner of the battlefield, and then “snap” it to the screen.
- To determine whether the mouse is hovering over a creep we…just draw a square around the mouse and check whether that collides with a creep. Whatever.
- When we build a tower, we tell Godot’s AStar object “disable pathing for these points”
- We maintain a duplicate copy of our AStar object to ensure that towers can’t “block” paths - before placing a tower, we disable the relevant points in the duplicate AStar object and ensure that no paths are blocked.
Once I sorted all of this out the actual “use AStar” part felt pretty simple - but if you’re curious you can see the code for it here.
Working like it’s my job and writing down what I do
I felt like I blinked after releasing click click trick and a week had passed - and that felt pretty bad! When thinking about what had happened I decided that a big cause was that my work schedule wasn’t very consistent - I was oscilating between working 16 hours in a day and working 0 to 2 hours, and if you work 0 to 2 hours for a week not much happens.
So I tried out a few things while building ReShape:
- I aimed to work more ‘normal’ hours - both by starting earlier in the day and by being happy to finish in the evening and do something else even if I was in a groove
- I tried to hold myself more accountable for getting something done every day.
I didn’t quite stick to normal hours: it was still hard for me to get started in the mornings without someone pushing me, and I also was up till around 4:30 AM the night before I shipped. But I kept my late hours much more contained!
And I posted just about everything I planned to do + everything I did do (along with the games I was playing) to my log. I really liked this: I found it fun and energizing to update (maybe particularly because it was public) and I’m excited to be able to read it later4.
For the time being I think I’m going to keep updating the log; I’ll revist how it feels in a few weeks.
That’s it! I’ll almost certainly build a few more tower defenses this year - hopefully the next one has a better theme and a little more depth.
My next game will likely be an entry in the Portland Indie Game Squad’s Idle Summer Slow Jam! I’ve been wanting to make an idle game for a while so I’m looking forward to it!
More context than you want or need: I started making a tower defense, went on a trip and worked on it in my off hours, dropped it to make click click trick for a game jam, and then started back up on a new tower defense on June 7th (using the bones of the original TD). ↩
The upgrades (maybe obviously) are all inspired by Path of Exile support gems. Early in PoE support gems feel incredible - it feels like are just so many cool possibilities for how to make them interact! And there are! But even in PoE folks that have played for a while complain about there being one or two obvious “best” combinations of gems for a skill. Not that ReShape is anywhere close to PoE but - getting this right is hard!! ↩
Yes sure some of this is just that I’m a more competent Godot dev than I was a few months ago. ↩