Null & Void - Relearning Game Dev


Hey! I am Bay Redif (aka Mr.Pdf).  We had lots of fun while making this game for the GoedWare Game Jam #9.  Our 3 man team is composed of one programmer (that's me!), the amazing artist Talluff,  and the very creative music composer TheSoulSelector.

Chapter 1: Why Even Make This Game?

I have been making games for over 4 years now with Unity Engine. Recently Unity made some questionable choices and broke my trust, so I thought, "Can I even make a game without Unity?".  At that moment I realized that I had been chained to the Unity Game Engine for making my games. After searching for alternative engines I found Godot Engine.  Godot is an open-source project so that took my interest. Now to learn Godot what should I do? Hmmmmm... Yes, I need to make a game, it's the fastest way to learn any game engine!

Chapter 2: Jam Time!

To make a game I needed some motivation, a time limit, a game jam! At this point, I looked through Itch's jam page and I found GoedWare Game Jam. My last 2 jams were 48 hours so I didn't want to stress myself too much. GoedWare had a 10-day time frame which was great.  Talluff and TheSoulSelector joined the team so I could just concentrate on learning Godot.

The theme was Broken Physics. After some discussions, we decided on a Metroidvania action platformer 2D game. The player would get abilities like slowing time, low gravity, light manipulation, and teleportation which you had to unlock by adventuring on the map. We decided on 6 regions:

  • The hub area
  • The mushroom forest
  • The red caves
  • The underground waterfalls
  • The floating ice islands
  • The castle

Talluff's first draft of the map

After more discussions, we began to work.

Chapter 3: Godot For Unity People

Okay, time to learn Godot! First, let's create a game object. WHAT?  What is a node? Where are the components? Why can't I add multiple scripts to nodes? GDScript what is that?

Yeah, it was hard at first but I got the hang of it quickly. Here is a quick rundown of Godot for Unity people.

  • Forget Gameobjects and components, everything is a node now. Want to add a sprite to your node? Then add the Sprite2D or AnimatedSprite2D  node as a child to that node.
  • Every node can only have one script attached to it, no more.
  • Monobehavior -> Node.
  • Prefabs and Scenes? Nope, those are now called PackedScenes and behave the same.
  • You can use many languages with addons but GDScript is specifically developed for Godot and is the preferred language. It is similar to Python and JavaScript. C# is officially supported but sadly there are not many learning sources on the internet.
  • When stuck consult the very helpful documentation. I AM LOOKING AT YOU UNITY!
  • Events are called Signals Which behave like UnityEvents.
  • [Serializefield] is now called [Export] and public fields are not exposed to the editor.
  • Start is _Ready, Update is _Process, FixedUpdate is _PhysicsProcess and OnDestroy is _ExitTree

Here is how you instantiate a prefab in both engines :

Unity


Godot with C#

There are some differences to note. In Godot, if you don't call any methods like AddChild or AddSibling instantiated node will not be added to the scene.

As you can see the concepts are very similar. I decided to use C# because it was the language I was comfortable with.

Chapter 4: Godot Is Amazing

When I wanted to download Godot I saw it was only a hundred megabytes! It was unreal (pun intended) to see an engine that small and easy to set up. For reference, Unity is like 3 gigabytes.  Also, the best part is whenever you play a scene it almost instantly loads and compiles scripts. In Unity, I would wait almost a minute just to test a change I have made. It's also very funny that you can download, open, and play an empty project in Godot while Unity opens an empty project you already created before.

One of the things I liked about Godot is the shader scripting. It's so easy to learn and use. Also, there are many shaders shared in the open-source Godot Shader Library (https://godotshaders.com/).  After studying some shaders I figured out how to use this space shader effect on enemies.


 In Unity whenever I want to make a timer I would do that with a custom timer class I created before. In Godot, there is a timer node that is very similar to my implementation. I used this node everywhere in the movement class. Jump buffer, coyote time, dash time, and slow-mo time are all controlled by this node. 

When it came to making the abilities I didn't have any problems. The process is almost beat by beat similar to Unity. Modify the velocity, apply gravity, etc. It was very fun implementing the player's abilities. Here take a look at the final product.

 

Dash and teleport ability all in one

Low gravity ability

There are more abilities but if I show all of them to you, where is the fun in that :D

When Talluff gave me the player sprite sheet I looked into how to animate in Godot. To make animations in Godot you can use the AnimatedSprite2D and AnimationPlayer nodes. AnimationPLayer is similar to Unity's animation system. AnimatedSprite2D is very useful if you just want to make sprite animations. I used the AnimatedSprite2D node because it was simple to set up and thought it would be easier to add more sprite animations later (foreshadowing).

Chapter 5: Godot Is Terrible

Now up to this point, I didn't have any problems with Godot and I was very happy. On the 4th day of the jam, Talluff gave me a sprite sheet for "Peak Animation". It was supposed to play when the player reached the jump peak. When this animation ended the fall animation would start. Easy right?

I heard that there was an animation tree node which is similar to the animator in Unity. It is a state machine that controls which animation should be playing. So I added this node and SUPRISE! It is incompatible with the AnimatedNode2D node! To use it you have to use AnimationPlayer node.  "Okay, I can just migrate the animations to the AnimationPlayer node".  Turns out there is no built-in conversion function. "Fine, I will just convert the animations by hand". 30 minutes of work later I wanted to change the animation speed. But wait where is the sample size filed? Nope, you can't change the sample size in AnimationPlayer but you can change the fps in AnimatedSprite2D node?


AnimatedSprite2D's fps option


Unity's samples option

No option for individual animation speed

Now I searched for how to change the playback speed for each animation. In the forums, they wrote that you can change the speed scale property of the AnimationPlayer node. Fine! After adding a track for the speed scale to every animation I was at the same point when I was using the AnimatedSprite2D node. Okay, time to use the AnimationTree. I connected the peak animation to the fall animation and set the connection to play fall when the peak animation ends.  Click play and... It works nicely, but wait! The animation speeds are all the same. WHY?

Turns out the AnimationTree node also controls the AnimationPlayer's speed scale. Now what? After scanning the forums again, they are saying that I should control each animation's speed from the tree. At this point, I threw the towel and made a custom script for AnimatedSprite2D.

So what is the lesson here? Don't waste your time on something unimportant otherwise, you will waste your time with nonsense.  I can't understand why there is no option for individual animation speeds.

Chapter 6: Godot Is Amazing Again

After wasting whole 4 hours on animations I began to work on the enemies. We had planned 8 enemy types:

  • Player follower flying bat
  • Basic walker
  • Ticking bomb enemy, when it sees the player it runs toward it and explodes. (Love this guy)
  • Platform-type enemy you can sit on but if you stay on longer,  it attacks you.
  • Spawner enemy with small bats
  • Turret enemy
  • Charger type enemy

Sadly only the first 4 enemies made it into the game. Implementing the enemies was really fun. Godot is a very good engine to use for composition so whatever I did was kind of modular. A node for Health, a node for attack area, and a node for movement I liked the structure.  You can also use composition in Unity but generally, I used Interfaces for these kinds of stuff. For the first time when I looked at my prefab(PackedScene), I knew what was going on.

Bat enemy PackedScene. You can guess what those nodes are at a glance

I created the bat, walker, platform, and bomb enemies. The bomb enemy was the most fun to implement. Love this little guy :D (it's name is Bomberino)

Bomb enemy in action

Chapter 7: "You can do that with a script"

The enemies were in the game but hitting them didn't feel great. That's why I shifted my attention to particle effects. Godot has 4 kinds of particle effects. CpuParticles2D-3D and GpuParticles2D-3D. It's awesome that you can write shaders for particle effects. I used the Cpu2D version because it was quicker to make good stuff. I wanted to make an enemy hurt particle effect. 

Looks cool right?

It was looking good so I wanted to set the stop action mode to destroy when done. That's what I would do in Unity. You guessed right there is no built-in stop action field. In the forums, everyone was saying "You can totally do that with a script why would you need it?".  Fine okay, I created a particle destroyer script just for that.

Now I wanted to make a trial particle for the charge attack. If I was in Unity I would increase the rate over the distance field. Well, Godot probably has that right? Nope "You can do that with a script" forums cried.

You see my problem here? Yes, you can do that with a script but I don't want to, I don't have time for that. And these are not some kind of edge case usage for particle systems.

The point is the particle system needs more options, more developer-friendly options.

Chapter 8: Godot Hates Cycles

Want to know how I got my first crash in Godot?  I wanted to connect our levels. When you enter an area from the left entrance you should arrive at the right entrance of that area. Simply just make a gate script that will instantiate the level and set the player position to the target gate. I made an export PackedScene variable that will hold the target level reference. Now it's time to test, click play, and... Godot crashes.  I am numb to Unity crashing so I thought it was one of those random crashes. Nope, it happened again, and again. Okay, I was doing something wrong with my code. After reading forum pages and GitHub issues I stumbled upon this https://github.com/godotengine/godot/issues/24146

Turns out that if a scene has a reference to another scene that has a reference to that scene crashes Godot because of a cyclic reference being created. Now this issue was reported in 2018 and still is not solved which worries me. At least the editor should detect the cyclic reference and terminate the play session not crash! Thankfully Github user Mithost was doing something similar and gave a fix for the issue. Thank you Mithost! 

The funny thing is there is a similar issue where if you reference the PackedScene in that same PackedScene this happens again. Please Godot...

Chapter 9: Panic!

The last day came and we had much to do like a lot of stuff was not in the game. On the last day, we added sound effects, Talluff created the map and drew lots of sprites like unhealthy amounts of sprites.

TheSoulSelector was going over thousands of sound effects to find something suitable for the game. I was busy with the dialogue system. Fortunately, there were very cool dialogue system projects for Godot. I found the plugin Dialogue Manager by Nathan Hoad to be the easiest to work with. (https://github.com/nathanhoad/godot_dialogue_manager)

Dialogue system in action

In the last hour, my power went out. PANIC PANIC PANIC OH NOOOO... WHAT SHOULD I DO? Luckily power came back after like 15 minutes. It was the most stressful minutes of my life. After Talluf's last-minute changes to the levels to make them playable (lol) we uploaded the game. Mission complete!

The Hub

The Mushroom Forest

The Caves

The Waterfall Caves

The Floating Ice Islands

The Castle

Now What?

I can say that Godot is a very cool engine. It has almost every tool needed for game development. Would I use it for my job? No, it needs more development time and developer-friendly features... Will I make games with it again? Yes! I really want to see Godot evolve and become the industry standard like Blender did. Currently, the jam is still going on and we are in the play and rate stage. I see lots of cool games and can't wait to play what people made.

 Thanks for reading!

-Bay Redif



Extra Art Notes:

Hi, I'm Tommy (Talluff) who worked on the art for this game and will try to go into some of those sections since Bay Redif did such a good job on the dev side!  I tried a few new things out in this jam that sometimes worked and sometimes didn't so will go over a few personal lessons going forward. 

Player:

Firstly even though I'm happy with how the character turned out,  I spent FAR too long on just the basic idle and will probably save this till run/jump are done in the future. It made the other actions a lot harder to match to this standard. When there isn't enough time to iterate on animations the majority of the game time (which is running/jumping) should be the focus. One frame of the idle should be enough to get the character design clear and then build everything else from there.

NPC:

Slightly new to me was having more of a focus on NPCs. Since it's such a key thing in Bay Redif's games I wanted to go for it this time and incorporating higher-res drawing with pixel art gaming allowed me to join two of my favourite hobbies (while not needing animation = timesave). Definitely will be doing more of this in the future! 


Enemies:

A positive decision from the jam was asking Bay Redif to make a shader to add an image through all of one colour of the sprite, this allowed me to finish up enemies far faster than would usually be the case but still (hopefully) have them look visually interesting. Below you can see the green we used for space transparency.  It was also interesting thinking a lot more about the silhouettes than usual and even though they didn't all make it into the game I'll probably use this method again. + A bonus from using silhouettes is that it is impossible to tell which leg is in front and behind so sometimes halving the needed frames : )


Tiles:

My biggest mistake was putting off the tile mapping till the end. Not having a nice visual place to test and work with a small vertical slice of the game really hurts the dev experience. It's basically going into the final vision of the game completely blind and should be built up steadily in between separate other tasks (maybe alternating between enemies and tiles). In spite of that though somehow this tilemap got drawn in one very long Sunday night :'| . So of course the actual levels suffered due to a lack of time to build them and virtually 20 mins per background parallax which was embarrassing and resulted in needing to reuse some mountains from a previous game for the top-level background. Quite a few gaps in the tile maps can be seen due to a lack of testing time as well as less satisfying level layouts without the time to plan...

In spite of all that though I think the building of the tilemap was a great learning experience. Since pixel art has such small file sizes working on just one file is perfectly viable for smaller games like this and allows for far easier production as it continues. It's like building an increasingly useful reference library and having it just a scroll away.  Also for the big tree in this project (top right of image), the goal was to have some of the branches in front of the player and some behind so I decided to make the leaf sprites completely separate. Though even just for building a regular forest, I think this approach is really helpful and would speed up building a variety of trees with different leaf/branch placements.


 Thanks for reading and hope you enjoyed what we managed to make so far!

-Tommy

Get Null & Void

Comments

Log in with itch.io to leave a comment.

(1 edit)

Really enjoyed this devlog. Hope next time I can write one half this good.

Now that Godot is being used so widely as the go-to replacement for Unity, maybe it will lead to more features and lots of improvement to existing features. In the meantime, if you want to experiment with other software, in my experience GDevelop gives better control over animations and their speed than you described from Godot, and particle effects usually are set to destroy when done, though the user can uncheck it. 

They have a nice online demo of the software and templates for every kind of game including a basic platformer.

(+1)

Thanks for reading! I will check GDevelop :)

Thank you for sharing this experience. Just wondering around itch io and stumbled on this is a blessing of it's own. Now I am convinced I can consider Godot as alternative to Unity, given I really dislike their recent moves.

(+1)

Glad you find it helpful. Have fun with Godot :]