Star Child Dev Log #21
Jay Ingle - lead developer, designer, and artist:
Last week we took a look at creating a new enemy, setting up our nodes. This week we look at the code itself. If you want to understand more about creating this enemy, make sure you have read last week's devlog. Here is our finished product, with placeholder graphics:

We setup some variables here:

We need to preload the projectile that the enemy fires, so we can instance it later. We have walk speed, a control variable for when the enemy is walking, and one for when dead. I also setup an enum for left and right, since i prefer DirectionType.LEFT rather than the magic "-1", even though i know that -1 means left in Godot coordinates, this is more readable and less error-prone. Dir.LEFT would probably be an improvement, but I have not standardized what DIR means to me yet, it could mean a few things. So when it doubt, spell it out.
Our ready function, which is called whenever the enemy is first loaded into the scene, sets our first fire_cooldown wait_time to our exported first_delay variable (which we will see later), and starts the cooldown.
Main process and switching direction:

The process function is a built-in function that is called by the engine every frame. Since this Area2D root node enemy will only be moving left and right, we can use Godot's built-in global_transform for walking back and forth.
Make sure control variable walking is true, make sure dead is false, and away we go. We make absolutely sure to multiple by delta, because if we don't, a higher frame-rate would mean that the enemy would move faster!
Next we check the raycasts that are checking for the absence of floor.. ceiling actually.. cause it's upside down sorta..... There is no ceiling in Godot, floor is based on gravity direction.. but I digress. If there is no more ceiling to traverse in front of you, turn around. Then, if there is a wall in front of you, turn around.
We have a turn_around_timer that only lets us turn around once, until the delay is finished. Imagine the enemy reaching a wall, turning around, but it isn't far enough away from the wall on the next frame, so it detects the wall again, so it turns around again, and becomes stuck in a loop of turning around forever. The first time I encountered this issue, it wasn't happening for me, but it was for Janne. Reason? My monitor was 60Hz and his was 120Hz. The enemy had time to get away from the wall on my slow refresh rate, but was too quick on Janne's!
I also set the turn_around_timer to autostart, because the enemy was turning around on it's own at the very start of the scene. I finally figured out that the enemy was loading in before the ceiling. So it detected no ceiling next to it, so it turned around. Must be careful of raycasts that are set to detect something that might be loading in later than expected.
This devlog is longer than expected so... tune in next week and we will talk more about how this enemy works under the hood!
Last week we took a look at creating a new enemy, setting up our nodes. This week we look at the code itself. If you want to understand more about creating this enemy, make sure you have read last week's devlog. Here is our finished product, with placeholder graphics:

We setup some variables here:

We need to preload the projectile that the enemy fires, so we can instance it later. We have walk speed, a control variable for when the enemy is walking, and one for when dead. I also setup an enum for left and right, since i prefer DirectionType.LEFT rather than the magic "-1", even though i know that -1 means left in Godot coordinates, this is more readable and less error-prone. Dir.LEFT would probably be an improvement, but I have not standardized what DIR means to me yet, it could mean a few things. So when it doubt, spell it out.
Our ready function, which is called whenever the enemy is first loaded into the scene, sets our first fire_cooldown wait_time to our exported first_delay variable (which we will see later), and starts the cooldown.
Main process and switching direction:

The process function is a built-in function that is called by the engine every frame. Since this Area2D root node enemy will only be moving left and right, we can use Godot's built-in global_transform for walking back and forth.
Make sure control variable walking is true, make sure dead is false, and away we go. We make absolutely sure to multiple by delta, because if we don't, a higher frame-rate would mean that the enemy would move faster!
Next we check the raycasts that are checking for the absence of floor.. ceiling actually.. cause it's upside down sorta..... There is no ceiling in Godot, floor is based on gravity direction.. but I digress. If there is no more ceiling to traverse in front of you, turn around. Then, if there is a wall in front of you, turn around.
We have a turn_around_timer that only lets us turn around once, until the delay is finished. Imagine the enemy reaching a wall, turning around, but it isn't far enough away from the wall on the next frame, so it detects the wall again, so it turns around again, and becomes stuck in a loop of turning around forever. The first time I encountered this issue, it wasn't happening for me, but it was for Janne. Reason? My monitor was 60Hz and his was 120Hz. The enemy had time to get away from the wall on my slow refresh rate, but was too quick on Janne's!
I also set the turn_around_timer to autostart, because the enemy was turning around on it's own at the very start of the scene. I finally figured out that the enemy was loading in before the ceiling. So it detected no ceiling next to it, so it turned around. Must be careful of raycasts that are set to detect something that might be loading in later than expected.
This devlog is longer than expected so... tune in next week and we will talk more about how this enemy works under the hood!