Building, Bit By Bit
New items, new rooms, new visuals, new noises. This month, my work on Bit Crusher was all about a whole lotta new. But not too much new. I took my time to build a system that makes sure I could keep making new, so that new new is easier to make new.
Modularity In Practice
The big push this phase was getting the foundation to a place where adding new content doesn't feel like a chore. When I get an idea for a new item, or room, or whatever, I want the speed at which I can develop that new feature to be fast enough to where I don’t run out of steam halfway through. Additionally, since this is a roguelike, I will soon be developing a system that allows a player to boost or modify the numbers within this system as they progress through a run. Risk of Rain 2 does this with items, Hades does this with boons, Slay The Spire does this with artifacts. They all have a core system, and ways to augment stats and behavior within that system. In addition to what I’ve already mentioned, this foundation that I’m building also needs to serve this kind of mutable system.
This was important for me developing Bit Crusher, but also for someone playing it. As a player, when items and rooms share similar structure, you can dependably rely on how items or mechanics that tweak the system will do so. It opens up a reward track for players who LEARN the system and can figure out how to GAME the system. Going back to Risk of Rain 2, you can always depend on the Lens Maker’s Glasses to increase your critical rate, which requires a system in place that allows that item to target the same stat on each character. Additionally, this item means very different things between someone playing the ranged and high-rate of fire Commando and someone playing the hard hitting melee character Loader. A reliable, learnable, and MUTABLE system like this is a really great way to implement depth and complexity within a game. For Bit Crusher, I am hoping to accomplish something similar: a player might think “maybe instead of increasing damage for my gun, I want to decrease its cooldown.” or “this item isn’t really my style because its damage is so low, but maybe I can keep an eye out for effects or items that remedy that.” The same applies to rooms: “my health is low, and I am close to beating this zone…I’ll go with a 1-bit room with less enemies and play it safe.”
In order for me to create ways for the player to game the system, though…the system needs to exist. So, I built out shared base classes for player equipment and rooms so that everything follows the same skeleton. New items this phase: freeze ray, bubble, ram, and gun. (Ram not shown in the demo viD below)
Offensive items are built off a shared class that consists of variables such as cooldown and damage. Defensive items are similar, but have a variable that measures their effect and a similar cooldown variable. New rooms: 1-bit, 2-bit, and 3-bit. The rooms are only differentiated by the number of waves of enemies per room, and I’m planning on making more unique encounters for certain rooms. And while there aren’t any features in place yet that take advantage of the system I’m setting up, I have confidence now that the system is somewhat prepared for me to introduce those features. For now, this is a good baseline.
SWAG (SENSORY WORK ASSISTED GAMEPLAY)
Speaking of a unified system: a really easy way to make everything feel more cohesive is with visual and audio cues. While I intend to tell the player how the system works, it will certainly be easier to do if I am also SHOWING the player the effects of the system through audio and visuals. So I also decided to work on more SWAG — Sensory Work Assisted Gameplay. Patent pending.
The idea is the game should be communicating through what the player sees and hears, not just through a health bar in the corner. So I pushed on two things: make what's already there feel better, and add what was missing.
In regards to what was already there, I added some spice to the ‘bits’ the player has so far (which is basically your ‘score’) as well as revamping how the background looks. A lot cleaner looking, while still maintaining the low pixel style. I want the background to look interesting just because it gives Bit Crusher some more whimsy, but the score looking cool was a bit more important to me. The indicator of your current progress needs to be as flashy as possible. “Number go up” is a good start, but that reward cycle needs to be as satisfying as I can make it. This will certainly not be the last pass on this idea.
The background now reacts to hits and deaths. Under the hood, I actually completely changed how the background is displayed, so that everything felt a bit more cohesive. The bit value of the room you’re about to enter is displayed when you hover over it with your mouse. And the game has sound now. Firstly, I have hit sounds and “fake” hit sounds for when an enemy gets hit during their i-frames. When a player engages with the system in a way that might reduce an enemy’s i-frames, these audio cues will be a lot more meaningful. I also worked on a death sound, which is a necessity.
I also have music, but I’ll be honest and admit that it is kind of hard to bring myself to showcase any of it. That stuff feels like much more of an art, whereas all the stuff I am usually talking about here is much more so system design and stuff. Due to that, I’m inclined to a “when it's ready” approach to showcasing music in these dev logs, just with how much more of a form of personal expression it feels like.
One thing I’m really proud of is how I show enemy health, which is also now visible…in the form of dice. You see the health values when they spawn, but you won’t know who is who until they start dying. I play a lot of Dungeons and Dragons, and I actually like the idea of the player not knowing exactly what an enemy’s health may be. I feel like this is a good middle ground. This might all seem like small stuff, but it makes a real difference in how it feels to play.
Conclusion
Happy with where things are heading. Adding content is actually starting to feel like adding content, which hasn't always been the case. It usually felt more like having to learn how best to implement a feature in a way that is Godot friendly, then having to figure out how to code it, but also what not to code since the editor provides so much abstraction that isn't always directly visible, and then I try implementing it and it doesn't work, then I get mad, then I want to do something else, then I go play Kenshi and my skeleton character gets knocked out for the 40th time and since he's a robot fixing him is insanely expensive so now I'm double mad and everything sucks.
Anyways, I'm still a little uneasy that Godot probably has built-in solutions for some of what I've been doing manually — nothing catastrophic yet, but it's in the back of my head. I have a side project that I recently started working on as a way to pivot away from Bit Crusher, so I can come back to it with some more tools in my tool kit, so to speak.
But until then, I am finally ready to move towards the part of Bit Crusher's development where its personality will truly start developing. It is time for phase four.
Card game.
The Game Crushed Back
The past month of working on Bit crusher has been quite the intense reality check. I ended off my last post being like, "I actually am super comfortable with Godot now and I feel like I can really start cooking." Total lie; the last month has just been like speed bump after speed bump after speed bump after speed bump.
It has been nightmarish, but in a really fun way. Like "God, that was awful…let's do it again."
The past month, the priorities were intended to be number one: make the base game "good enough." Basically just iterating upon the core gameplay loop of my game. Number 2 was to work on implementing the complexity reduction system that I mentioned in the last dev log, and then number three, I kind of wanted to just hone in a bit on the style of Bit Crusher. I'm not done iterating upon the style, but I just kind of wanted to get a better idea of the direction in which I wanted to take it.
Those were my main three goals initially, and then I kind of had to force a fourth goal in there: fixing my horrible code and design choices. Everything was a complete mess, and I think it's a bit less of a mess now, but that's kind of up for debate.
Quick Clean Up
Before I could get started on the goals I had set up for this part of my game development cycle, I wanted to fix some random issues that my game was having. Hence why I had "making my game good enough" as the first priority. Before moving on to each phase of my game development cycle, I am hoping I can do this before each step, so that I am at least 80% positive that the work I'm leaving behind is solid.
First of all, my game was way too fast. It didn't really leave a lot of room for skillful action. Because everything was moving so fast, it was basically impossible to be good at. So I had to tone down the speed for a lot of the player movement and enemy movement.
There was also this weird behavior that enemies and the player were exhibiting, where they moved a lot faster when going in a negative direction as opposed to a positive one. At the time, I didn't want to deal with this issue (the speed thing was kind of done first in the hopes that it would make this behavior less noticeable), but eventually I had to. The floating point numbers within the speed vectors being added were causing unexpected behavior after the x and y positions were converted to integers, but at the time, I wasn't exactly sure of what was happening. So my solution was to make the speed values integers before adding them: boom solved.
In addition to that, the collision detection was really bad. Part of that was due to the high speed of things, so that had already been partially mitigated. But outside of that, I didn't really know what the issue was, so I just made the collision boxes bigger. Easy fix.
I also wanted visual indicators of in-game events, like for when the player got hit. What I had for that was color changes for the player and the enemy when that happened, as well as when the player's defensive item was activated. I plan on implementing cool down systems for specific defensive and offensive weapons, and I wanted to start now with making those states visible within the game itself, as opposed to the UI.
Before I could move on, I started noticing this weird error where my player was taking damage twice but it wouldn't update twice? I was just getting notified of the player being hit twice. It took me the better part of an entire hour to find out I had another instance of the player scene hidden beneath the root scene. It was in my Project Settings as a global object for reasons far beyond my understanding.
Mathematical Complexity Reduction
So the first real goal that I wanted to tackle after this quick housekeeping session was implementing the mathematical complexity reduction with bit shifting that I had always been thinking about.
Compatibility is a pretty big deal for me. I would like for anyone on any machine to be able to play this. If someone had a Nokia phone, I was hoping I could get them to be part of the club.
The concept behind what I was attempting to do was this: close your eyes. What is 3 plus 4? Easy. 9 plus 6, easy too. 17 plus 37, a bit harder but doable. 296 plus 137, definitely harder. See how the math gets more difficult with each digit added? Computers work the same way, but the digit increases in binary, not in the base-10 arithmetic that we use. If I could force the computer to work at a lower digit count, I was under the impression that I could make huge strides in optimization.
To make sure I wasn't being unreasonable, I went to Reddit for some tips. I posted about the system I wanted to implement and got flamed, especially for doing collision math this way. But I was still convinced that doing collision and movement math with positions shifted down by a certain factor could work.
The idea was to perform collision and movement calculations with positions shifted down, then shift the values back up when rendering them on the screen. Shifting down would let me work with smaller numbers and avoid floats, making arithmetic simpler and potentially improving performance by reducing computational complexity.
I was a little worried, though, because the player might feel cheated if what they see on screen doesn't match the collision detection happening in the physics engine.
This system also wasn't very Godot-friendly. People on Reddit pointed me toward Vector2i, which I started using, but a lot of Vector2 methods I depended on for enemy and player movement were unusable without using Vector2. Godot also doesn't easily recognize custom variables in enemy scenes unless they inherit from a shared class, which was important since I was storing the "raw position" of the game entities as a separate variable within each entity. Accessing that additional variable was doable, but a bit unsafe.
As I kept working to implement this system, I started to question whether it was even worth it. For a 2D game, is there really that much heavy computation happening in the first place?
I also realized that while I wanted to reduce collision complexity with this system, I wasn't even applying it to Area2D.
At that point, I gave up. I'm not using this system. It's not worth it, and a full implementation across the entire game would be a nightmare.
Instead, I'll make it a class and keep it visual. I'll still use Vector2i, and I'll maintain a separate Vector2i for position, converting it later when needed. Now I have a class for it. I might organize my classes into a dedicated folder instead of mixing them with enemy-specific and weapon-specific code. Or maybe not.
Style
So with the complexity reduction system kind of canned, I wanted to move on to something that I was at least kind of positive I wouldn't be canning, which was the style I wanted to pursue.
I want it to be very very simple visually, where it's just simple shapes fighting each other, like Agar.io. A lot of old arcade games resorted to a style like that due to hardware limitations. There's also diep.io where you level up your turret and move around, becoming different kinds of turrets. Similar simple shapes only vibe.
I have so much admiration for the style of modern 2D pixel art games, stuff like Enter the Gungeon, Deltarune, and Geometry Dash. I know that one doesn't exactly count, but still. Those games have so much swag. But I also wanted to commit to the classic game feel, where the pixelation is actually consistent. The reason pixelation was consistent back in the day was because they were working with lower resolution screens, but there are modern games that commit to that as well. One of the best examples is Animal Well. So that is the direction I plan on taking it: simple shapes and geometry behind an old ass monitor.
So initially, I tested a bunch of random stuff, specifically things I had already created in the previous proof of concept that I've mentioned a few times. One of the first things I implemented was a trail system where enemies and the player leave a trail as they move.
The trail was pretty easy. I've done that before. It's just a list of the entity's previous positions and then drawing shapes at those positions.
I also had another simple trick for making the game look "old-school," which were lines over the screen. I had the lines over the screen for every eight pixels, as that is something Animal Well has as well (but admittedly way cooler). I also added another set of lines in the same exact place, however they quickly move down the screen and rubber band back to their original position after moving a short distance, to once again further hone in on the old school monitor vibe.
Something I didn't have in the old proof of concept was a shifting background that I wanted to implement as well. I also added lines over the screen, with each line being one pixel wide and spaced at a factor of eight to somewhat replicate the look of older displays where you'd see those scanline-like artifacts.
The background was more of a challenge because I had never worked with the GLSL shader system in Godot. It was completely new to me. At first, I was applying everything to the vertex, which was not correct. Once I figured out what I was actually supposed to apply it to, it worked as intended.
In addition, I took the low precision system I had and applied it to the trail and the shifting background. And boom. That's a good start to my style.
…alright something feels wrong.
The Walk Back
It was around this time in my development cycle where I finally couldn't ignore the bad feeling that had been creeping up on me about a lot of the choices I was making. It just felt like I was taking a very…weird route.
Not only was I building up a lot of technical debt, with having no folders for specific code files and assets, and just no documentation in general, I was also forcing Godot into very strange behavior that it doesn't really support, and jumping through weird hoops for results.
Outside of the usual technical debt, I was also making just bad game design choices. The visual style that I had at the time that I called "good enough" heavily muddled the visual information that was supposed to be delivered to the player to inform them on what was actually going on on the screen. There was just so much random shit that it got in the way of knowing where the enemy was and how close I was to hitting them.
In addition, there wasn't enough reaction from the game entities in response to specific events such as a player getting hit or an enemy getting hit. This was especially still the case for my collision boxes, which were heavily hindered by my having a very low physics tick count at the time (in an attempt to truly imitate old school arcade games).
This is where I inserted the aforementioned fourth goal of fixing my stupid mistakes and cleaning up my code. I knew I would pay for my technical debt later. I was already paying for it with two dev streams where it was 90% just me staring at my computer and saying to myself, "what on earth is happening?" So to try and prevent that in the future, I went back and fixed a bunch of stuff.
When converting the position to make it so that entities wrap around the screen, I made sure to round the position instead of doing a direct int conversion, which floors it toward zero. So if the y position was 10.1, it would go down to 10, and if it was 10.9, it would also go to 10. I had to explicitly round the numbers instead of allowing the implicit int conversion to truncate the decimal point to make sure that the speed was consistent.
I also modulated a bunch of shared behavior between game entities into a class so that I wouldn't have to spend so much time redoing code I've written a million times before. Having shared classes makes it a lot easier to create prefabs of enemies and items.
I then toned down the visual flair a bit and made sure that it didn't get in the way of conveying information to the player about what's happening in the game. Part of the way I did that was expanding the size of the trail and making it so that the part of the trail closer to the player is black. This allows the trail to still create an interesting effect while also centralizing the player's attention on the darkest part of the screen, which contains the player and the enemies. Now, my visual flair was adding swag AND improving the game's readability.
I also had to make everything delta-based. The only reason I had to do that was because I had to raise the physics tick rate to improve collision detection, which made everything much faster since I wasn't using delta before. That was a nightmare to figure out.
Once I was done with a lot of this cleanup, I went back and made a testable build to figure out if what I had was fun. I made a restart button, implemented player health and a health bar, and added a bunch of things that felt early to implement, but that I needed immediately so I could properly test the game.
I figured out that what I have so far is actually pretty fun. It's still early and nowhere near release. I'm not trying to pull a Pirate Software and say that this is 99% done. If anything, it's less than 10%. But I think I'm working on a good foundation.
After testing a bit, I went back over my original design milestones to ensure their completion.
Conclusion
Okay, well, maybe I'm not perfect as a game dev yet, but regardless, I'm having so much fun with this process. I am even more excited to keep moving forward now that I know a bit more on how to set a good foundation and I also now have a bit more of a foundation built so I can start building the really cool stuff.
Next, I want to further modularize my game so that I set an even better foundation.
Then, to build on that foundation, I want to add more defensive and offensive items so that it's not just this spinning cube and the directional shield. I also want to add rooms with different mechanics, number of enemies, and other stuff.
Once I have those two things figured out, I want to build on the style further. Minor visual changes. I don't want to add much visually yet, but I do want to add audio such as music and sound effects. Not a lot, just a little to refine the proof of concept.
Learning to Crush
First ever post about my first ever video game Bit Crusher, coming out…eventually. I literally started working on this last month so there is no concrete long term plan whatsoever. I've learned from the many many mistakes of other industry giants that any sort of promises made too early on will basically always come back to bite you in the ass, so I'm not setting any expectations here. At least, not yet. Additionally, I don't really want to put myself in any sort of box: maybe I work on this for a couple months and make something kind of neat, maybe I work on this for two or three years and make some straight heat. Either way, what I know for sure is that I want to document my progress and my work and potentially get some super valuable feedback. I have an idea for where I want to take the game genre/direction wise, and I'm currently planning to make it in Godot considering that it's free, open source, and not UE5. But all of this is very subject to change.
For those not super in the know, Godot is a video game engine. In the same way that you use Photoshop to edit pictures and CapCut to edit videos, you can use Godot to make video games. Emphasis on "can" here: coding everything is an option, but I'd rather work smarter not harder here. Much like the grand multitude of options there are for photo editing software and video editing software, there are more than a couple for making video games, called "game engines." Many different professional game studios have their own game engine made in house, but there are a couple that are publicly available. Examples include Unity, dog shit computer shredding unoptimized slop machine Unreal Engine 5, and Godot. Part of why Godot interests me is the fact that it is open source. I would consider myself quite an aspiring computer whiz, and frankly, I would love to one day build a game engine much like other studios have done, but on top of Godot. However, I would be pretty out of my depth if I tried that now, so first, I want to get familiar with using Godot. Starting out, I'm not exactly setting out to make anything crazy yet: I'm well aware of the rule of thumb of not making your dream game for your first game. Starting off, I'm just mostly trying to learn the tech. To reign in my scope a bit, I'm going to be rebuilding this old game I made a few years ago when I was learning how to code in Java. It wasn't anything crazy, but I think the foundation had some potential. Plus, maybe lightning will strike during the beginning stages?
So, I dove into Godot having watched maybe one YouTube video, like a complete idiot. I started with the version of Godot that supported C# because I thought it might give me some mobility—if Godot didn't do it for me, I'd at least have some C# experience if I ever wanted to move to Unity or…okay not Unreal Engine. No thanks. In hindsight though, choosing to use the Mono version was an… interesting choice.
At first, I hard coded nearly everything myself. I ignored Godot's built-in scenes, signals, and shaders. I could've learned how to use these things with some YouTube videos, but again: I'm an idiot. My character and enemy trails were made up of polygons created as children of the root scene so that their position wouldn't be relative to the originating entity. The only reason I did it like that was because I didn't know that the global_position variable existed, because I didn't watch any YouTube videos, because I am an idiot. For movement, I bypassed Godot's pre-built input system entirely and handled key presses within the script of the player, handling all the nuances of key-up and key-down logic myself. I even made a VHS-style overlay with a bunch of lines over the screen, not knowing that shaders could have done the same thing but way cooler.
On top of that, C# support in Godot was rough. There was no built-in autocomplete, documentation was scarce, and most of the editor's features were built for GDScript, not C# (particularly signals, which did not auto-generate methods for me). I did a small amount of research recently and it seems that there were solutions to a few of these issues, but at the time, the level of "newness" I was experiencing kind of overwhelmed me. Frustration was one thing, but then I realized something pretty crucial: games made with C# cannot be built for the web. This is probably something I should've known from the start, but again: idiot. Being able to share a simple demo online was very important to me, so once I realized that, I dropped C# almost immediately. Additionally, I took a step back a bit and looked into the parts of Godot that I should focus on learning. Knowing how to code is one thing, but that's only half of the battle here.
So once I shifted away from using the mono version of Godot and left C# behind, I really began to figure out how to work with Godot more as opposed to against it. I watched a few more YouTube videos, I read more of the documentation, and I became a genius, basically. I started working with GDScript instead and I learned very quickly how much of a nice shift that was going to be. It's a very simple programming language, and reminds me a lot of Python which I have a lot of experience in.
I also looked more into what scenes are and what they do. As expected, they weren't exactly a one-to-one replacement of object-oriented programming principles, but it's still similar enough to where I can utilize it in a way that I need to. (I would later realize that custom classes can in fact be made in Godot, but I haven't exactly utilized that knowledge quite yet.) In addition, I started working with the parent-child hierarchy more. I realized that I could just take the top level node that was my original game and place that inside of the new top level node of a different scene as a child of that new top level node and it would still work fine without any change in logic. I thought that was pretty neat and I was stoked once I realized that that was something I could do. It's actually inspired me a bit to shift away from having just the game idea I originally had and now I want a game on top of that game. I'm not sure if that makes sense, but hopefully in a future post I can elaborate a bit more.
In addition, despite scenes not exactly being the same as classes, scenes still allow programmatic creation of object prefabs; what that means is I can make a loop inside of the game within a game node that randomly generates a couple enemies from the enemy scene. Once I realized I could do that, I was very happy with where I was in the regular version of Godot and started getting a lot more comfortable.
Looking at the goals I set when I started working in Godot in regards to getting familiar with it, I'd say I'm close-ish. The old proof of concept is mostly rebuilt, but it's not finished. The original version had level variations and different enemy archetypes depending on the level, and that still needs to be implemented.
That said, while I don't fully "understand" Godot yet, I now understand what I don't understand—and more importantly, I can see the path towards understanding what I don't understand. Basically, I know what I need to learn and where to learn it.
I also think some of my original goals need reevaluating. Not because they're impossible, but because they might not be necessary — at least not right now. The mathematical complexity reduction idea with bit shifting is a good example. It's something I experimented with, and I still find it interesting, but I need to figure out whether it actually does what I think it could do for my game. I'll break that theoretical system down more in a future dev log.
Moving forward, the priorities are fairly clear: I need to lock down the core gameplay loop. I still want to implement the VHS-style overlay — I think it fits the tone I'm going for. And I also need to set up programmatic recreation of the gameplay loop. I want this to be a roguelike. I don't want to handcraft every level. Rooms, encounters, progression — all of that needs to be generated dynamically. Hopefully, I can make all of that happen in the next few months. Maybe.