Apex Predator Devlog


How I created Apex Predator

Apex Predator is my entry for the week-long 1-Bit Jam #2. The theme of the jam was "You Start With Everything And End With Nothing". However, I had already started brainstorming before the jam was announced. As I'm a busy college student, I wanted to make something easy and fun for me to make to hopefully give myself the motivation. This is why my game is about fish in the ocean. I think they're cool. I wanted to do something cool with high-contrast lighting with the 1-bit graphics, which is where the idea for the anglerfish came from. I thought the 1-bit style would be good for making a scary atmosphere, so I wanted to make the game atmospheric and tense. After the theme was announced, I thought I could make it kind of work. An anglerfish at the top of the food chain would have everything, and it would end with nothing by getting eaten by a bigger predator at the end. However, I think coming up with my ideas at the front hurt me in the long run because the game didn't end up feeling related to the theme very much.

After finishing the brainstorming, I created a new Godot project. One of my goals for this jam was to get better with Godot- I've used the engine before, but haven't made a complete game with it.  To make the game authentically low-res, I changed the viewport size to 240x140.  I decided to use a shader to make my graphics 1-bit. I had never used shaders in Godot, so this seemed like a good excuse. I found this Floyd-Steinberg Dither Shader on Godot Shaders that seemed to be a perfect fit. Adding the shader to my project was easier than I thought- I just had to create a new ColorRect above everything else, add a Shader Material, and paste the shader code in. To tint everything blue (for the ocean theme), I just added another ColorRect above the shader at a low opacity.

After setting up the project, I jumped straight into asset creation. Due to the small time frame of the project, I didn't want to mess around with placeholder assets. I also think that having your game look good early in the process works as a motivation boost. However, I knew that if I decided to devote loads of time to the art, I would be rushing in the end. As an artist, I've fallen into this trap. I also wanted this project to be coding-focused. I decided to use compressed images for the sprites- it ended up creating a really interesting aesthetic. Since the jam allowed copyrighted material, I started my hunt on google images. The angler fish started out as this image from DK find out. The small prey fish started out as this image from PXhere. The huge fish at the end (also an angler fish, actually) came from this article on It's Nature. I downloaded the images, cut the backgrounds out, compressed them, adjusted some details, then imported them into Godot.

I started out by creating the angler fish. The angler fish's light isn't actually a light at all- it's a trick. The light itself is just a PNG of a white circle with blurred edges, attached to the angler fish sprite. It's layered between the background everything else in the world. When the light moves behind something, it becomes visible against the black background layer.  The fish's collision detection is a rectangle for the body and a circle for the light stem.  A circular area over the mouth is what detects whether a prey has been eaten. The large circular area is how close you can get to your prey without causing it to flee. 


I tried a few different movement methods, using the Godot Docs 2D movement page as a guide. I first tried normal WASD movement, but I've done that before- I wanted to do something more interesting. Next, I tried click-to move movement, but I knew that I wanted the camera to follow the player around the environment, so I wasn't sure how well that would work. Finally, I tried tank-style movement. I chose it because it was something I haven't done before and I thought it was the best at conveying swimming underwater. To make the movement feel more floaty (for the underwater theme) I added deceleration to my movement. I tried adding deceleration for the rotation as well, but I had ended up spending too much time on the movement and decided to move onto something else.

Next I decided to create the  prey for the player to hunt. The prey are made of sprite, a rectangular area, and a small, circular hitbox. The area checks for whether the fish is in eating range, while the hitbox is for actual collisions with walls. I set it up like this so the player wouldn't experience weird collisions with fish while trying to eat them. I had trouble deciding whether fish should collide with walls at all- if they collide with walls, it's easy to trap them against a wall, making hunting prey easy. Having them being able to escape out-of-bounds gives more stakes to the hunting, but it felt unfair at times if they were able to escape too quickly. I ended up having them able to collide with walls, and increased their speed to make them more challenging to catch. 


To make the prey flee, I just made a vector from the prey to the player, then moved the prey the opposite direction. It worked surprisingly well- while the prey can be pretty stupid sometimes, their movement is interesting and they're fun to chase. 

The hunger bar was pretty simple- it's Godot's ProgressBar node. It drains over time, and catching prey fills it by 25%. I used signals for this- when they enter the player's EatArea, they send a signal to the hunger bar and then are removed from the scene. When it gets low, it starts flashing, and when it gets really low, it starts playing scary sounds. It doesn't actually do anything when it runs out, though. It's just there to scare people and push them towards the ending. 

At this point, my base systems were implemented, so I moved on to level design. I compressed a rock image and upped the contrast, then rotated it around to make a basic tilemap.

I had never used the tilemap system in Godot, but I found it really nice. Referencing tutorials, I was able to easily import my tilemap and add proper collisions to each tile. Then I made a basic layout of my level- a pretty linear path with some interesting bends and obstacles. Since the player has limited visibility, I didn't want to make it too complicated- I wanted to make sure they reached the end. 

After making the level, I manually populated it with prey. I spaced them out so that there would be more at the beginning and less at the end, hopefully causing the player to feel stressed as their hunger bar ticks down while they couldn't find any prey. Hopefully, by the time they reached the end of the level, they would already be starving and anxious. 

To finish off the gameplay, I added the ending. My goal was to make it big and scary. It was straightforward- if the player entered the area in front of the big fish, it would fade in, the screen would go black, and a pitched-down version of the eat noise would play, signaling the player's demise. It was one of my favorite parts to make, mostly because I liked editing the big fish sprite. Judging from feedback, I think it was pretty effective, although some said it was a bit out-of-nowhere and didn't tie into the overall jam theme that well.


Now that the gameplay was done, it was time for the boring bits- menus. I added a quick fade-out between scene changes to get rid of jarring cuts between scenes. Here is where I discovered Godot's AnimationPlayer node- my new favorite node. It allows you to keyframe any property of a node, letting you animate any node quickly and easily. I used this a lot for fade-ins and to animate the text in the intro cutscene. I found a nice typewriter font from Google Fonts to use for the menu title and the intro cutscene. It was Thursday at this point, so I didn't have too much time to spend on the menus. 

For my last finishing touches, I added some sounds. I took them off YouTube- I combined some underwater sounds and some whale noises for the ambient background audio, and added a sonar ping sound effect for when the hunger bar gets low. The sound effect for eating was generated with ChipTone

Then, the game was ready. Exporting Godot to web was easier than I thought- I had to look up a couple of settings, but it was easy to make it playable on itch.io. I'm glad exporting to web was easy. I like the accessibility of browser games, and it makes it easier to show people what you've made. 

Overall, this project went well. I set out with a really small scope for this project- a single level with simple 2D movement and one type of NPC. Because of the small scope, I was able to breeze through completing the game, even with other projects for school taking up my time. I was able to devote a lot of time to polish and building the atmosphere, which made it effective. 

As a game jam entry, it's fine. People liked it, and I think it's pretty cool, but it's debatable on how well it fit the theme. For the next jam I do, I'll wait to see the theme before brainstorming. 

However, my goal for this wasn't to win a game jam or get awards- it was to learn Godot. I felt like I really learned a lot in Godot- I went from only having done basic interaction to creating a whole game in a week. I feel a lot more confident in my skills now, and I learned specific techniques that will apply to most projects I work on in the future. I think I'll stick with Godot for sure. Unity is out of the question for obvious reasons, and Unreal takes up way too much space and power for my liking. I would 100% recommend Godot for beginners who want to learn their first game engine or for anyone wanting to make a small project quickly.

(This took a while to write, it's a very busy time of year)

Leave a comment

Log in with itch.io to leave a comment.