Posted July 03, 2024 by wherritt
#game jam
Learn You a Game Jam
(is this your first time etc?):
This will be my first game jam. I started coding about six months ago with JavaScript in preparation for a bootcamp. I did small things outside of the class that I found interesting, because I wanted to enjoy the learning process. I made a web page and some miscellaneous, but quickly gravitated toward making the very simple games that I could. I made rock paper scissors, a story game, and then a more refined memory game that ran inside of a web browser. After that, I wanted to control a character to run around and fight enemies. Something like “Super Mario” or “Kirby’s Adventure”. I began my project in HTML/JavaScript, and while trying to figure out what a “ray cast” was, I discovered game engines.
(What did you want to learn going into the jam?):
Something I really want to learn in this game jam is using Git. Building a game with a team seems like the perfect place. I’ve never used it before, and it seems like an essential tool.
I want to become more intuitive with coding concepts. Finding the solution to a lot of these puzzles I find myself in is a bit of a struggle, and I need help often, but I grow with every new project. I hope to enhance my problem-solving ability in coding through this process. I assume it’s like a lot of growth. It will come from experiencing setbacks, learning from them, and adding their solutions to your tools.
Git/GitHub/GitHub-Desktop:
Branches:
There is one “main” or “master” branch, that contains the stable, and most up to date version of the project. The Godot game in this case.
When collaborating with others across the world, you can use a web platform such as “GitHub”, that will allow you to store the branches and all of their information online. These branches will then be accessible for cloning from the GitHub.
The project is built by making branches off of the main or master. A team member, once they have the current stable build of the master cloned onto their local device, can create their own branch. This team member can then work on adding new features to the game within their branch, building on top of a clone of the master, and then when their added features are completed, their branch is merged back into the master.
Once the master is successfully merged into by the team member’s branch, all other members of the project should “pull” the updated master branch onto their devices, so that they are now, and again, working with the most current and stable build of the game.
It is essential that all feature branches of the project are stable, and verified by the rest of the team before a merge. There is great potential to “break” the project through mismanagement of these tools.
It’s through this process of branching, and merging, that a stable game is incrementally built by a team of numerous contributors. Communication is key to safe and successful development.
Workflow:
An important idea to keep in mind, is that the master is ultimately untouched at all times besides the merge of a stable feature branch. The master should, to my knowledge, almost never be altered directly. The master is cloned (or “pulled”) onto a member’s device -> a branch is made for that specific team member and the feature they are working on -> the branch is completed -> that member’s branch is merged back into the master -> everyone pulls the updated master onto their local devices, and the project continues.
Godot:
This was my first time working with Godot. I had previously worked with Unity in order to make my first game using any kind of game engine. I’ll list some of the higher key items that stood out to me as a new developer in Godot.
Script attachment to game objects (“Nodes” as they’re called in Godot)
In Godot, developers typically add a single script to a node. This means that your player, the enemies, and all scripted objects(nodes) will have just one script attached to them, that handles all of their actions.
There are some cases where a node will have a child object, like a different kind of collider, that will have another script attached to it. For example, my enemies have two colliders. One that is attached to the “CharacterBody2D” because a character body is required to have a collision shape, and another that is attached to an “Area2D”, which is a child of the character body. The Area2D has the ability to detect when nodes have entered into this collider and perform functions as a result of the event. This has also become a useful tool when disabling one type of collider/ setting its layer and mask to detect different nodes in the scene.
Layers and masks:
For objects that will be colliding with others in your game, Godot has their “Layer” and “Mask” tool. This is represented when selecting a node, under the “inspector” tab on the right, with two rectangles containing 16 boxes inside marked numbers 1-16. One rectangle is marked “Layer” and the other “Mask”.
This was a bit confusing at first, but I’ve figured out a sort of method to remember their roles:
Layers are what the object is itself. If you select a node and make its layers 1, 2, and 4, then that node is layers 1, 2, and 4.
Masks are what this node will be able to collide with.
So, if I have a node with layers 1, 2, and 4, and another node with masks 3 and 5, then that node will not be able to collide with the other.
This is useful for scenarios where you might want certain enemies to go through each other, say on a 2D platformer. You could set that specific enemy’s layers to 2, and its masks to 1. As long as your player is on layer 1, then the enemies will not collide with each other, but they will collide with your player.
Nodes are layers, and their masks collide with layers that match their masks.
Singelton instance:
A singleton instance (or “autoload”) is a script that is always loaded in memory and is particularly useful for handling “global data”. For example, I have a flying enemy whose speed I want to increase by 20 every time the player makes it to the next stage. Since each one of these enemies are their own instance, meaning they are each a separate object with their own script, if I tried to adjust their speed directly inside of their own script, then every time the player killed one of these enemies, their script would be destroyed along with them. A new enemy would be instantiated into the scene, and the function that was called would have only affected those enemies who are now, already destroyed.
I fixed this by routing the enemy’s speed to a singleton instance. A separate, autoload script, called “flyer_speed”. This script contained an initial speed variable set to 120, and a function with the ability to increase the speed by 20. The flying enemy’s speed is then set to reference this autoload script in order to obtain what speed they should be using. When the player successfully passes to the next stage, the autoload’s speed increase function is activated, and all enemies now use the new adjusted speed variable (140).
A convenient feature of a singleton instance is that you can access its functions and variables directly inside of other scripts by simply writing the script’s name, then “.” The action you want from the singleton.
For example:
Singleton.do_function_inside_singleton()
Keyboard ghosting:
One of the bugs that seemed to stick around during development, was the inability to move left and jump, while also shooting. It was a strange issue because moving right with the same actions was no problem and there were no discrepancies in the code.
Eventually, I reached out to forum.godotengine.org with a description of my problem along with screenshots of the relevant code. Luckily, someone pointed out that it sounded like “keyboard ghosting” and linked a page to test it. It turns out many keyboards will be overloaded by multiple inputs on certain keys. My keyboard was having trouble incorporating numerous arrow keys along with the space bar, yet worked fine with the W, A, S, D configuration. I simply went into Godot’s project settings -> inputs and added these keys as valid inputs for movement and jumping.
Sprite Sheets
This was my first time making animations with sprite sheets for my game. I was always hesitant because it seemed like another art form I had to learn, and as I was first getting into game development, I was overloaded with the many things that were taking me away from my ultimate goal of learning how to code. However, it seemed to fit in this game. My character had a very simple single animation of jumping, making his wheel go up and down, and once I’d grasped the basics, I was inclined to start adding more sophisticated animations to the game. I love the finished look of it and I think I’ll be using this method of animation more often whenever I find myself making 2D games again.
Audio Compressor
When I was adding sound to my enemies, I ran into an issue where when numerous died at the same moment, their death sounds would compound and create one, very loud noise. I figured this must have been a common issue and looked at Godot’s https://docs.godotengine.org/ . They had a perfect solution to my problem which was a “compressor”. It is a feature that is attached to an “audio bus” (similar to a master in audio) and it will compress any audio that surpasses a certain decibel. Now I was able to play numerous sounds at the same time, but they would not resonate with each other.
https://docs.godotengine.org/en/stable/classes/class_audioeffectcompressor.html
Final Notes:
This was my first game jam and I didn’t know what to expect going into it, except that I had the intention to learn git. Now finishing up and looking back, I learned more about a steady work flow and staying committed to a goal. I saw that pushing myself to get the work done resulted in more rewards than passively making my game. This was a growing experience. It was tough, but I‘m very happy with how much I’ve grown through this process. I feel like I’ve gained an amount of skill and knowledge that would’ve come in many months had I not pushed myself.