NOTE: DAY 3 WAS ADDED AS A COMMENT HERE SINCE I HAVE APPARENTLY EXCEEDED THE CHARACTER LIMIT FOR THE MAIN SUBJECT BODY (oops ^^")
DAY 3
Sooo it's technically not day 3 anymore where I live (timezones are weird) but I was so close to succeeding at making a functional line of code that I just had to work and experiment on it just a little longer than I usually would. As I told you all in yesterday's devlog my big goal for today was making some very basic yet functional enemy AI. And (spoilers) I succeeded ! ...mostly ^^" Now without anymore waiting let me take you all through the very exciting day full of unexpected discoveries !
My coding day started with...not coding. After all just like a player character, an enemy in a videogame is an object in the room. But unlike the player character the player does (obviously) not have direct control over an enemy. Instead it cycles through a certain pattern or behaviour dictated on lines of code. Why am I telling you all this ? Well let me take you through the thought process I had when trying to logically find the answer to what kind of object (or node in Godot specifically) I would have to add to my prototype level to program an enemy with.
Until this point I had only used a KinematicBody2D (Node), the kinematic part in this instance refers to the fact that this can have motion or can move. It's "kinetic". All documentation I read so far said it's most common use was for a controllable character, like I did. So I mentally scrapped that option off. Still with me ? Okay, let's continue ! Going through some more documentation on Godot's different nodes (again, objects you can add to your room) I found one that was particularly familiar to me since I had messed around with Unity a few years back in high school. A so-called RigidBody, or RigidBody2D in this case. After reading this description I was sure I had the right train of thought going.
So in full anticipation and excitement I add it into my scene, attach a sprite and hitbox to it. All pretty standard so far and since this is my third day spending a lot of hours with Godot the UI slowly but surely becomes more familiar to me. I finish by adding a script and get to work.
Following the same logic I had used to make the player character move I add some variables and constants first (not all of them of course since some are mostly only applicable on controllable characters). When applying some of these constants and variables I also decided to use a different naming convention for a select few as was recommended to me by Godot users on the official forums (for example using velocity to determine things like movement direction and location of the floor). I put in all the code, press play and...absolutely nothing. Huh? I was at a total loss.
Upon further research into RigidBody I suddenly realised something that was so totally obvious that I honestly couldn't help but laugh at my own expense a little (all in good fun of course). The reason I mentioned the whole story about a KinematicBody again was because well, and it's probably a bit of an anticlimax, it was indeed the object I needed to program an enemy. You see, there are two very major differences between a RigidBody and KinematicBody, that in in of themselves define the entire way you use each of them. Problem is, these differences can be missed for beginners like me since the official description can be taken in a totally wrong way to what a RigidBody's use actually is. To make a long theoretical explanation a bit clearer I'll use an example:
A possible RigidBody in a game could be something like a ball. A KinematicBody can be, as said before, a player character. The player in in of itself can move continuously with the right inputs. Gravity and such still affect it but if you keep pressing the keys, he/she will keep moving. A ball on the other hand can not move on it's own. It needs a force pushing, pulling,... it to move - in other words: physics. Just like in real life. A ball just laying on the ground won't move. Place a ball on a downwards slope and due to natural physics pulling it down it'll start to roll and gain momentum. So in other words we need a KinematicBody to make an enemy since we want it to be capable to move naturally on it's own and not just be a lifeless object we push around using long lines of code induced physics. This way movement will also feel more natural since our enemy, in the context of the game, will most likely be a living organism in the world as well.
So with that revelation I set out again to do the exact same I did before and added a KinematicBody, attached a sprite and a hitbox and went to work on coding. It didn't take long before I succeeded in making my enemy sprite move forward. That's a start, now on to the next thing step: adding collision behaviour. In simple words, coding so the enemy walks to the opposite direction when hitting a wall. But just like I wanted the enemy to react when hitting a wall, I myself hit a wall on how to actually achieve this. I started again with my logical cause = effect and which "formula" to use to achieve this. After a while I came up with a formula I was kind of positive would have the intended effect.
if is_on_wall():
velocity = velocity * -1
For those of you who already have some coding experience you'll probably already realise this wasn't only horribly wrong, but hilariously so. Take a look for yourself:
After a good minute of laughing at my own failure and it's...unexpected (at least for me) consequence I set out to find the error in my logic.
ATTEMPT #2
I started my logical reasoning by just deciding to change the constant by which I multiplied the velocity. I changed it from a number to the constant FLOOR, so:
if is_on_wall():
velocity = velocity * FLOOR
And even though (spoiler alert) it turned out to not be what I set out to achieve it wasn't a absolute failure like the previous attempt. See for yourselves.
This time I felt surprised in an entirely different way. I quickly made notes, after all with some imagination (don't worry I'm working on some fleshed out sprites *hint hint*) this result can be seen the enemy "climbing" up the ledge....just change the black blocks into ladders. I make sure to write down the formula and set out again to find my solution. And again, it was something so obvious I forgot all about it.
ATTEMPT #3
All I had to do was add another variable: if we want a character to go in the opposite way they came from we want them to go in another direction. Again I couldn't help but laugh at how obvious it all was. So I added a variable direction = 1 (since the starting position to where the AI is supposed to go at first is to the right) and completely changed my calculation (I had to add * direction to my x-axis velocity calculation so velocity . x = SPEED * direction). Here's the result of all this trial and error:
if is_on_wall():
direction = direction * -1
I add it in,
click on run and
I couldn't believe my eyes and again felt overwhelmed by a feeling of proud. Not only because I succeeded in the goal I set for myself but also because I achieved it while being a little less dependent on help from forums, documents and tutorial searches. This success again reassures me that even if I am not that mathematically talented, I can still learn to code and take the journey towards making my own game (and hopefully games beyond this point, but let's not get ahead of ourselves).
And it's with that same satisfied feeling I finish off writing today's devlog and I can tell you that today especially game development is, just like games sometimes, a lot of trial and error. And that not all errors are bad by any means (some are just more hilarious or potentially useful).
Anyway it's time for me to head to bed ! Tomorrow I'll try to expand upon this basic AI behaviour by specifically adding the same reaction my enemy has to walls but with edges of platforms as well. Since I have most of the fundamentals as well as the formula involved this should (with emphasis on should) be an easier right but bear with me. Aside from that I'll continue work on character concepts as well as lay the finishing touches on the musical piece I teased about yesterday. And before you ask, no you can't get a sneak peak of it yet... ;D But I'll leave you all with a small hint: echoes of beats. I'll leave it up to you to figure out what that means.
Thanks again for reading and see you all tomorrow !
Feel free to leave your thoughts, experiences, tips,... down below, I'd love to get some input on...well pretty much anything concerning making videogames.