When I was working on my first game project, I decided to introduce different types of enemies. For example, simple guardians will patrol their area and can attack the player only when he is near. More complex samurais will not only see the player, but also can chase him. This is a common task in game development. In this short case study I want to demonstrate you how I created such character in Godot.
Create an enemy object
The samurai inherits the
KinematicBody2D class, which means, that it is not controlled by engine’s physics, but is controlled by the developer (in our case by code). When the samurai detects the player nearby, it will move into its direction. There are two important things I want to mention here:
- What does that mean “near”? How the samurai can “see” the player?
- The “Masks of Edo” is a platformer game, so we need to move the samurai only in a single direction by X-axis
Let start with the structure of the entity. Take a look on the screenshot below:
Here I have an
Area2D object that plays a role of the detection box. Once the player enters this zone, the samurai will start to chase him. I also have an another zone to attack the player, but we will not cover it in this post. The principle is however the same. Let start with the first point – how the samurai will detect the ninja.
Make an enemy see the player
The most common pattern that I found is to create a detection box, and once the player enters it, the enemy will follow the player. There is some specific stuff for “Masks of Edo”. First, there is an invisible mode, so once the ninja is invisible, the samurai will not follow him, even the ninja overlaps the detection area. Second, I want to know where does the player stand relating to the samurai – on the left or on the right, so I could to flip the sprite accordingly.
Let start by registering two signal listeners for the
body_entered()is fired once the body will enter the area. Don’t forget to configure collision layers, so only the player entity would call this method
body_exited()indictes that the player left the area, so the samurai stops to chase him
The next step is to implement these methods. Please note, that I use GDScript here. I also defined a class variable
player which indicates the player instance:
var player = null func _on_DetectionBox_body_entered(body): if body.has_method('get_invisible'): is_player_invisible = body.get_invisible() if not is_player_invisible: player = body func _on_DetectionBox_body_exited(body): player = null
The code snippet is self-explanatory. Once the body enters the detection area, we call its
get_invisible() method in order to verify that the player is not in invisible mode (I use the precaution
has_method maybe due to my past in strong typed languages, yet it is not necessary). Once the ninja leaves the detection box area, we set the
player value to null.
The next question I want to tackle is how to rotate the samurai based on the player’s position. Because, the ninja also extends the
KinematicBody2D class, we can obtain its position by calling the respected property. I wrote a simple method to do so:
var is_left_oriented = false func check_if_player_is_on_the_left(): if player: var player_position = player.position is_left_oriented = player_position.x < position.x else: is_left_oriented = false
Follow your nose!
Now, the samurai will see the player but he also need to move towards the ninja. This logic lives inside the
_physics_process loop. Basically, we go here through following steps:
- Check if player is detected (e.g. not null)
- Check that player is visible
- Verify the position of the player
- If the player is on the left – we move into negative direction
- If the player is on the right – we move into positive direction
This is how it can be defined. But, what do these directions mean? Let me explain. From the technical point of view, positions in Godot are vectors (e.g. 2D pairs). The motion direction of the player can be described as the difference with the player multiplied by the speed. Godot has a helper method
direction_to which simplifies our life a lot. All what we need to do is:
var direction = motion.direction_to(player.position) * SPEED
But be careful! This value is the vector, but we need to move the enemy only by single axis. That means, that we write only
motion.x value, but the
motion.y is 0.
The complete implementation is below:
func _physics_process(delta): var motion = Vector2.ZERO if player: is_player_invisible = player.get_invisible() if not is_player_invisible: check_if_player_is_on_the_left() if not is_left_oriented: var direction = motion.direction_to(player.position) * SPEED motion.x = direction.x motion.y = 0 AnimationSprite.flip_h = false AnimationSprite.animation = "walk" else: var direction = motion.direction_to(player.position) * SPEED motion.x = -(direction.x) motion.y = 0 AnimationSprite.flip_h = true AnimationSprite.animation = "walk" else: motion = Vector2.ZERO AnimationSprite.animation = "idle" else: motion = Vector2.ZERO AnimationSprite.animation = "idle" move_and_slide(motion)
This code makes the samurai to chase the ninja. The result looks like this:
I hope that this post helped you at least a bit! If you’re interested in more content about Godot and game programming, don’t hesitate to follow me in social networks.