sludge

sludge

13 devlogs
70h 23m
•  Ship certified
Created by ingobeans

A tower defense game in Rust with deck-building mechanics inspired by Noita's wand building!

Timeline

Ship 1

1 payout of shell 779.0 shells

ingobeans

about 1 month ago

ingobeans Covers 13 devlogs and 69h 40m

I had to make a Web build of my game because Windows Defender decided my extremely simple game was actually malware, so I cant ship a windows executable. I assumed it would be easy to build for web, I've done it before with this graphics library (Macroquad), but I ran in to some really strange issues that took me the entire day to figure out. Basically, I render a low-res 192x144 viewport, that I upscale to fullscreen, for the graphics. This is so that the game is always pixel-perfect. In macroquad, this is done with a render target. Problem was, the part of my code that defined this render target always crashed on web builds. Apparently, after getting help from their discord, this is because the javascript frontend library in web builds, that communicates with my Rust game, was outdated. But how did I get an outdated version of the library? Because thats the one they use in the documentation! Apparently the maintainer of the library doesnt update it very often. Anyways, after that I also had to implement savefiles. On native builds, I write to a file on the computer, on web builds, I communicate with a JS library that lets me write to the web browsers local storage. The local storage on browsers is a key/value database for websites. Each website has their own local storage. Though since the local storage is in plaintext, and my savedata is in raw binary, I have to encode and decode it to base64. But now thats done, and i set up a GitHub workflow to build this web version, and host it on their servers, so I should be able to ship this now, Yey!

Update attachment

[SEE VIDEO for a little gameplay montage]
Coming up with new content for the game is becoming really difficult, which indicates to me that it is probably about finished. I've been doing a lot of bug patches, and once again restructuring data to prevent stack overflows LOL. The last time this happened it was because i was storing map data on the stack, which was like 13 kb, and this time the inventory was the problem. Thankfully the fix both times was quite easy, replace my usage of arrays (go on stack), with vectors (go on heap). If you dont know, the stack and heap are two different memory regions where data can be stored. The heap is dynamically allocated, and big data, and data that can grow should be on the heap. The stack is more for fast smaller reads, and if you put too much data there, or infinitely recursively call a function, you get a stack overflow and your program crashes. Ive added a lot of new enemies and cards, and my last stroke of genius was adding suprise mushroom rounds, every now and then theres a round thats all mushrooms. It sounds stupid but i really like it for some reason. I also had to fix some issues regarding sprite centering, basically enemies position vector points to the top left of a 8x8 sprite, but for checking projectile collisions i need to find the enemies center. This becomes a huge problem for enemies that are multiple tiles in size, as their center would be far away from their coordinate and screw up collision detection. I also had to implement stun immunity frames, because I realized during a playtest that if you could make a tower rapid-fire any projectile with the stun modifier card added, you literally stop any enemy from passing through, as theyd be stunned and not be able to move. I also had to reimplement a system i had for enemy spawning, basically some enemies spawn other enemies when they die, like the big spider that spawns children, and i used to have a spawn queue, that I'd add to when this happened, and every frame I would pop one item from the spawn queue and instantiate it. Problem though, in later rounds, theres like houndreds of entries in the spawn queue, so when an enemy with a payload dies, it takes several seconds for their payload to spawn. I first fixed this by making it parallel, but I realized it would be better to just drop the system all together and I made it work by spawning it all directly. I've also done a million more things (theres been like 50 commits since last devlog), but i cant mention everything. I plan to ship after this devlog, wish me luck !

Game design is so much harder than programming lol. This devlog ive been focusing on game design, and the problem solving you need is so much harder. One problem i had was how, if the player knows what they are doing, and get good shop items, they could quite early on in the game create INSANELY powerful builds, that basically last them til near the end of the game, which is really boring when you dont have to do anything for like 20 minutes (see video, its really boring when you dont even see the enemies spawn in before they die, and it just lasts like that for minutes). This however is kind of intended, creating OP builds is part of the game, i just didnt want a one fits all solution, i wanted more diversity required. I realized that a really OP build generally requires like 4 parts, a base projectile, something to speed up recharge time, something to tie it all together (like a multidraw or trigger), and optionally a payload, so I made sure to tinker with the shop's RNG to make the early game almost always miss one of those elements. Then i slowly over the course of the game reduce the tampering. I also introduced more enemies with resistances. My game has different damage types, and enemies can be (fully or partially) resistant to those. I realized that having enemies with multiple phases was a good idea, like a knight that has a shield that protects from explosion/burn, and then when that breaks, he just has his armor which protects from piercing. This makes you need at least 2 types of damage, again punishing those one fits all solutions. I also had to figure out how the player receives new towers, mind you, until this point, every game you just had the two starting towers. While that still worked fine because of the variety of cards, it gets limiting in the higher rounds. I considered having them available in the shop for a high price, but decided to automatically reward the player with one tower at round 17, and one at round 34. Forcing them unto the player I hope will nurture experimentation, as their more card slots open up new possibilities (and gettign new towers also shakes things up a ton, and the player will hopefully reallocate their cards and create new builds so they dont get stuck with those foul one fits all towers).

I can pretty safely say that all the game's UI is complete at this point! I've added a map selection to the main menu, as well as... multiple maps to play. The hardest part about making a map is just coming up with an idea/theme, the rest is really easy. I use a software called tiled to draw the maps, it exports to xml that my game parses, and it allows multiple layers, so different behaviour is tied to different layers, theres a Background layer, where you're allowed to place towers, an Out of Bounds layer, where you're not allowed to, an Obstructions layer, that also collides with projectiles, and a Path layer, where the actual path that the enemies travel on is stored. The way the path works is that a special tile indicates the start, and another special tile indicates continued path. Then I just have to find the start tile, and recursively iterate through all its neighbouring continue tiles until we reach the end. All I really want to add to this project now is more enemies and rounds.

All core game concepts are pretty much in place, so I'm now in a part of the development where my creativity is the only limit, which is great! I can have an idea for a card, and spend 5-15 minutes adding it (most time is probably drawing sprites and writing particle effects). Often times I need to add new functionality to the core projectile class to implement a new card, which might seem like a lot of work to just add a new card, but its really not. The projectile class in my game now has like 30 fields, some of which only used by a single card, but every time i add new functionality, that means that future cards will be even faster to implement, and i can combine different aspects of previous cards, and its really fun! Enemies are code-wise really basic, no enemies so far have any 'special' behaviour, they all just have different stats and optional payloads, but I still spend A LOT of time on them just drawing sprites, which always takes me ages. My least favourite part of development rn is adding rounds. Its REALLY hard making rounds both fun AND balanced. But I've realized that having lots of weaker enemies is basically a cheat code to stimulation, just seeing your towers SHRED through layers upon layers of foes is really satisfying, and then I just use the stronger, more visually interesting enemies as garnish, that I sprinkle on. Sometimes to keep it interesting I do a whole round with just the big strong guys, or the opposite. Anyways, game is nearing completion (fr), I can only think of a couple fixes and features I want to add, and while I could basically perpetually add new cards and enemies, I'll try to remember that this just has to be an MVP, and its fine if game only has a couple hours of content.

Update attachment

Implementing Saving was both harder and easier than I thought it would be. On one hand, since this is rust, I can just pack all save data in to a struct and transmute that to bytes that can be loaded, on the other hand, that is incredibly unsafe and could theoretically destroy the system. You have to ensure that the struct CAN be safely loaded, with for instance bytemuck (a library). I did end up after a while just going with bincode (another library) instead, which abstracts everything unsafe away.
Ive also added the ability to rotate towers freely, which I think is good for game design because it fits my idea of constantly moving towers around and restructuring and not being held back. Sound effects was kind of a pain to get working, I ended up having to reorganize a lot of data, because I was getting stack overflows because my game state had gotten to slightly over 20 000 bytes (on the stack) (oops).

Update attachment

This is the longest ive gone without writing a devlog, yet also the most boring devlog. I've mostly been working balancing, making spells and enemies just right. I've also added PROGRESSION, finally. In between certain rounds, a little shop appears, where you can buy different random spells. Its hard balancing the game because of this, because I cant know before hand how good cards/builds the player will have at any given point, because the shop is random. My solution was to always assume the best of the player, which does make the game harder, but which also rewards planning ahead and experimenting with builds. This devlog isnt very technical, because its really just about game design (which i unfortunately SUCK at), but thats just as important when making a game. The game is coming close to being finished, now I just need to add saving, and a bit more content and polish (like sound).

Reworking my entire UI system was as mind numbing as i though it would be. Since i chose not to make an entire UI engine, it instead meant dealing with lots of random coordinates and comparing mouse coordinates to arbitrary bounds. I also made AN ENTIRE FONT (actually just a-z, 0-9 and : and .). The challenge with making fonts for such low-res games is that each character has to be really tiny to fit much text on screen, in my case i had each character be 4x3 pixels. This makes some characters quite unintelligible, but mostly it looks ... fine. I also added a win and lose screen, and you can TECHNICALLY win the game. Speaking of which, I'll be working on adding progression now. I'll have to plan out how and when you receive new cards, towers and abilities, but i have some ideas.

Update attachment

Today ive added lots of CARDS and ENEMIES!!!
My biggest obstacle this devlog was again, figuring out how to store data, in this case, round/wave data. Enemies arrive in waves and rounds, and figuring out a format for encoding that data took some time. With a statically typed (and borrow checked) language like Rust, planning out the structure of data before-hand is basically a necessity. You need to know what parts of your systems need to interact, and when and how to share memory, which is why you can see i spend a lot of time doing that.
Other than that, adding a bunch of cards and enemies was fun, since the core systems are in place its really easy to add new stuff.
NOW ig ill focus more on setting up win/lose states, and UI. Ive been avoiding UI since its often really time consuming, but my plan now is to just try to get through it and never think about it again.

ive spent 7 hours now implementing DECK BUILDING! ive coded a couple of cards that you currently are given all of when you start the game. i plan on making them be purchaseable in shops in-between rounds and rewarded randomly.
the deck building is really quite complex, since theres a lot of different states that need to be tracked, and many nische mechanics like wrapping and what not, but ive made a robust system that does this, that keeps track of all contexts and buffers and whatnots.
the most difficult thing to do was to figure out HOW cards are stored, like, what are they? i wrote down a list of cards i wanted to create, and from there figured out which features they would need. ive now landed on a quite nice design where most of the card specific data is stored IN the type enum (in rust, enum variants can hold unique values).
next ill focus on getting a game loop, adding more cards, adding some UI (descriptions and names of cards)

Update attachment

ive set up the system for towers and UI now!!!!
an idea i had is actually that you only ever have 4 or so towers. you start with 2, and receive new ones every couple rounds. this would put the focus on building cool and smart decks, and maybe changing up the build on the fly (which is also why i want you able to move them freely).
NOW, i can finally focus on making the deck building system and getting a full game loop up and running. wish me luck!

ive created the systems for enemies and maps :)
the first and only enemy ive drawn is this little spider guy i wanted to show. he moves real fast but ill change that later. for now ill work on setting up player input and classes for the placeable towers and that

FIRST DEVLOG!!!
i want to create a tower defense game. i really like btd5, so something thematically similar to that is my goal. but to make it interesting i want to combine it with Noita's wand-building (Noita is an awesome finnish roguelike).

so far i've really just set up the infrastructure that the game will run on, that is, a rust project built on macroquad (a dope graphics lib), and come up with the ideas and goals of the project.

i want the game to feel semi-retro, like pico-8 games, so i've decided to target a fixed 192x144 (because its 4:3 aspect ratio, and divisible by 8) resolution, with 8x8 sprites. i've also found a nice 16bit palette that i will be using for art.

Update attachment