Competing with 1,000 Game Developers for $500...

Competing with 1,000 Game Developers for $500...

Nuzcraft
Nuzcraft

Suck-Bot: Island Defense Roguelike was created over 2 weeks while I participated in Acerola Jam 0. I didn’t win anything, I had a good time, I learned a lot, and I’m excited to share some of my experience.

Screenshot of Suck-Bot

Screenshot of Suck-Bot

This update has been cross-posted on my newsletter. Please subscribe to get updates in your inbox!


Gameplay 🎮

Suck-Bot is a turn-based strategy game where the goal is to protect the lighthouse at the center of the island. The main mechanic involves absorbing enemies/allies to gain unique Actions. I wanted to explore restricting Actions to the cardinal directions (up, down, left, right) to see how I could encourage strategic positioning.

up:Attack, down:None, left:None, right:Build

up:Attack, down:None, left:None, right:Build

In the above example, the hero can Attack an enemy or wall upwards, Build a wall to the right, and has no available actions to the left or downward.

Actions are gained by absorbing enemies/allies. Each enemy/ally has a unique action that fills the cardinal slot in the direction the were absorbed from.

arrows:SUCK, up:Attack, down:None, left:None, right:Build

arrows:SUCK, up:Attack, down:None, left:None, right:Build

In the above example, the hero can choose a cardinal direction to Suck. An enemy/ally absorbed from that direction will replace the Action then available in that direction.


Lessons Learned 🏫

Find the Fun 🎉

The couple comments I’ve gotten on the game have echoed something I ignored while developing… the game isn’t fun to play.

It’s a good lesson.

Through the jam, I was focused on building this system and never really stopped to see if what I was building was fun. I was hoping it would all stitch together into something enjoyable at the end and that never really materialized. For other projects (including my larger roguelike project), taking a step back to find the fun will be a priority.

Planning Can Help 📝

At the beginning of project and about a week in, I found myself working on less-essential parts of the game. Things like polishing the wall textures or re-doing the player sprites or futzing with the lighting.

I stopped, put away my codebase, and did some planning of next steps.

This helped me focus on the more important aspects of what I felt I needed for a ‘finished’ game. I didn’t really finish but I got a lot closer than if I hadn’t stepped back to do some planning.


Details 💅

Let’s get into some of the nitty-gritty of game dev for someone like me.

This project was a bit of a ‘come-back’ challenge. Due to some life-events, I’d been away from game development completely for over a month. With some sanity returning to my schedule, I committed to participating in Acerola’s first game jam.

Check out Acerola here!

Planning began a few days before the jam started. I’d had this idea in my head as an extension of some ideas I want to pursue in my larger roguelike, and thought a jam setting would be a good way to test the idea. I tried to keep my plan abstract enough that it would work for whatever theme was announced for the jam.

Once the jam started, I was able to to spend between 1.5 and 2 hours in the evenings on development.

Time Spent (hrs) per Day. Between 1 and 2 hours were logged most days of the Jam.

Time Spent (hrs) per Day. Between 1 and 2 hours were logged most days of the Jam.

This was not particularly easy for me. I have lots of competing priorities at the moment, and making time for this required some sacrifices, mostly in sleep and exercise.

Progress in Pixels 🖼️

I tried to post on Mastodon as I made progress through the jam. Here are a few screenshots and a brief description of the development path.

A hero moves on the screen with light blocked by walls as they move

A hero moves on the screen with light blocked by walls as they move

I started with some 2D tile-based movement, a moving sprite for the water, and a tileset for walls, floor, and ground. The game was developed in Godot, and this was my first time using tileset terrain and occluders in Godot 4.0. It was a fun challenge to get the walls to auto-tile based on their orientation, as well as get them to block the light.

The player presses Z to enter action mode before attacking a breaking walls. In action mode, there is a pink border on the screen.

The player presses Z to enter action mode before attacking a breaking walls. In action mode, there is a pink border on the screen.

After movement, I set up the walls to break with multiple hits. I originally tried to do this by adding health to the tiles in the tilemap, but custom data is shared across all similar tiles when used that way. Instead I chose to use a second layer for the ‘cracks’ in the wall and use the presence of that sprite as an indicator of wall health. The player can enter Action Mode with the Z button and attack directly from there.

The hero breaks a wall and the enemy changes direction to pursue them with a shorter path.

The hero breaks a wall and the enemy changes direction to pursue them with a shorter path.

I added in an enemy, and spent some time setting up pathfinding. This was a bit of a challenge. I originally tried to use the built-in functionality of tilemaps, but it felt like that movement was very much to be used for more granular movement, and not the tile based movement I was looking for. I quickly shifted to setting up a separate pathfinding object. Getting the available paths to change when walls were broken was a fun challenge. Above you can see, after the wall is broken, the enemy finds a shorter path to the hero and changes course.

The hero builds a wall to block a pursuing enemy, then breaks a wall to attack and defeat it.

The hero builds a wall to block a pursuing enemy, then breaks a wall to attack and defeat it.

Big changes here! I reworked the hero and enemy sprites. I also spruced up the Action Mode menu to show which actions are available in each direction. In the above example, the hero can Attack downwards, left, or right, but the upward action is Build. They use this to build a wall blocking the enemy’s path. I was really happy with my progress this far, I was getting really close to a slice of what I wanted the gameplay to be.

an AI builder enters a room and repairs broken walls

an AI builder enters a room and repairs broken walls

I took a little detour here and added an ally, the Builder. In the above example, we can see the builder detecting damaged and broken walls, pathing to them, and fixing them. I put this in the game because I wanted the player to have a source of ‘build’ actions. I intended for the player to sacrifice their builders to gain the build Action, which would then help keep them safe and give the builders more walls to repair. In the end, the builders aren’t as impactful as I wanted them to be.

On a darkened island, a Builder on the left, 4 enemies on the top-right, a lighthouse is protected by a wall in the middle.

On a darkened island, a Builder on the left, 4 enemies on the top-right, a lighthouse is protected by a wall in the middle.

I added a button for Suck mode, which would be how the hero gained new Actions. I added the lighthouse as a central target for enemies, and I set up some enemies at the edges of the island to see how they would path towards the hero and lighthouse. I was happy to see the builders jump into action to repair the walls as they were broken by the enemies. Speaking of which, I adjusted the enemy pathfinding so they could and would path through walls if going around would be too long or wasn’t available.

Hero exits action mode, enters suck mode, absorbs the enemy above, then has a new ‘attack’ action in the up direction

Hero exits action mode, enters suck mode, absorbs the enemy above, then has a new ‘attack’ action in the up direction

Above is an example of Suck mode! The hero has no available actions upward, absorbs the upper enemy, then action mode shows they have access to attack upward!

  • Player can absorb enemies
  • Absorbed enemies grant the player new abilities
  • Player can use abilities in cardinal directions
  • Enemies attack the player and lighthouse

All that was left to finish up the main game loop were enemy spawning, spawn progression, and utilities to start, restart, pause, and end the game.

The enemy spawning system was kinda rushed, but I like some of the simplicity of it.

  • All around the edge of the island, Enemy Spawner nodes were placed
  • At the beginning of the game, spawn 2 enemies, each at a random node
  • After all enemies are defeated, start a 10 turn timer
    • At the end of the timer, spawn between 1.5 and 1.1 more enemies
    • Reset the Hero’s health to 20
    • Repeat the loop

I like how simple and extensible this loop is. I don’t like that it isn’t sustainable with the health pool of the hero. The combat/strategy needs more time to cook if we wanted to find a solution that didn’t rely on healing the hero between each wave.

Title Screen: Suck-Bot Island Defense Roguelike

Title Screen: Suck-Bot Island Defense Roguelike

I made the bare minimum start and pause screens as I could using the colors and fonts I was already using. I was hoping to spruce these up before the end of the jam, but ran out of time. High scores weren’t added until a little later, but they ended up being a cool addition to the game.

For high scores, I started keeping track of the number of turns taken each game. If the game ends normally (where the player or lighthouse is destroyed) the value is written to a file. When the game loads, the file is parsed out and the results are put in this little text box on the main screen. Fun!

With the title screen done, I was ready to get the itch.io page up and running as well as some automated build/deployments up and running.

Suck-Bot Github Repo Here!

Though Github actions and some copy-paste, I was able to get automated deployments up and running in short order. Check out the repo if you’re interested in seeing how those actions are set up. With a basic itch.io page and automated deployments, I could now focus on making smaller changes to enhance the game, and feel confident they would deploy out to web without issues and could get accepted into the jam (spoilers, this goes wrong).

Fire Enemy and Teleport Enemy

Fire Enemy and Teleport Enemy

In the above (manufactured in the game engine) example, you can see the 2 new enemy types I added at this point. The Fire enemy will shoot fire 2 spaces ahead (with a 1 turn cooldown) and the Teleport enemy can teleport 2 spaces ahead (with a 1 turn cooldown). Both enemies brought their action along to give to the player, which added some more variety to the player action pool in later turns. Note that each of the new enemies has 4 health, meaning they need to get damaged at least once before they can be absorbed with Suck mode.

Sound is difficult to describe in gifs and words, but suffice to say I added some sound effects that really helped the gamefeel. I did not get around to adding background noise or music.

Dialog Box at the bottom of the screen with the tutorial

Dialog Box at the bottom of the screen with the tutorial

Among the last features I added was a simple tutorial using Dialogic.

Check out Dialogic here!

It’s really a wonderful open-source tool.

Remember way back when I mentioned the automatic build and deploy was kinda set it and forget it? Welp, it came back to bite me. For some reason, the tutorial was not building into the game correctly and wouldn’t play in submitted builds. At this point, it was too late to debug the build, and the game was submitted without the tutorial.


The End 💀

Wow, long post! I had a lot of fun with this project. I’m really hoping to take some of what I learned with me to new projects. If you get a chance, please play Suck-Bot and subscribe here so you don’t miss my next post!

- nuzcraft