Up to date

This page is up to date for Godot 4.0. If you still find outdated information, please open an issue.

Creating the enemy

Now it’s time to make the enemies our player will have to dodge. Their behavior will not be very complex: mobs will spawn randomly at the edges of the screen, choose a random direction, and move in a straight line.

We’ll create a Mob scene, which we can then instance to create any number of independent mobs in the game.

Node setup

Click Scene -> New Scene from the top menu and add the following nodes:

Don’t forget to set the children so they can’t be selected, like you did with the Player scene.

In the RigidBody2D properties, set Gravity Scale to 0, so the mob will not fall downward. In addition, under the CollisionObject2D section, uncheck the 1 inside the Mask property. This will ensure the mobs do not collide with each other.

../../_images/set_collision_mask.webp

Set up the AnimatedSprite2D like you did for the player. This time, we have 3 animations: fly, swim, and walk. There are two images for each animation in the art folder.

The Animation Speed property has to be set for each individual animation. Adjust it to 3 for all 3 animations.

../../_images/mob_animations.webp

You can use the “Play Animation” buttons on the right of the Animation Speed input field to preview your animations.

We’ll select one of these animations randomly so that the mobs will have some variety.

Like the player images, these mob images need to be scaled down. Set the AnimatedSprite2D‘s Scale property to (0.75, 0.75).

As in the Player scene, add a CapsuleShape2D for the collision. To align the shape with the image, you’ll need to set the Rotation Degrees property to 90 (under “Transform” in the Inspector).

Save the scene.

Enemy script

Add a script to the Mob like this:

GDScriptC#C++

  1. extends RigidBody2D
  1. using Godot;
  2. public partial class Mob : RigidBody2D
  3. {
  4. // Don't forget to rebuild the project.
  5. }
  1. // Copy `player.gdns` to `mob.gdns` and replace `Player` with `Mob`.
  2. // Attach the `mob.gdns` file to the Mob node.
  3. // Create two files `mob.cpp` and `mob.hpp` next to `entry.cpp` in `src`.
  4. // This code goes in `mob.hpp`. We also define the methods we'll be using here.
  5. #ifndef MOB_H
  6. #define MOB_H
  7. #include <AnimatedSprite2D.hpp>
  8. #include <Godot.hpp>
  9. #include <RigidBody2D.hpp>
  10. class Mob : public godot::RigidBody2D {
  11. GODOT_CLASS(Mob, godot::RigidBody2D)
  12. godot::AnimatedSprite2D *_animated_sprite;
  13. public:
  14. void _init() {}
  15. void _ready();
  16. void _on_visible_on_screen_notifier_2d_screen_exited();
  17. static void _register_methods();
  18. };
  19. #endif // MOB_H

Now let’s look at the rest of the script. In _ready() we play the animation and randomly choose one of the three animation types:

GDScriptC#C++

  1. func _ready():
  2. var mob_types = $AnimatedSprite2D.sprite_frames.get_animation_names()
  3. $AnimatedSprite2D.play(mob_types[randi() % mob_types.size()])
  1. public override void _Ready()
  2. {
  3. var animatedSprite2D = GetNode<AnimatedSprite2D>("AnimatedSprite2D");
  4. string[] mobTypes = animatedSprite2D.SpriteFrames.GetAnimationNames();
  5. animatedSprite2D.Play(mobTypes[GD.Randi() % mobTypes.Length]);
  6. }
  1. // This code goes in `mob.cpp`.
  2. #include "mob.hpp"
  3. #include <RandomNumberGenerator.hpp>
  4. #include <SpriteFrames.hpp>
  5. void Mob::_ready() {
  6. godot::Ref<godot::RandomNumberGenerator> random = godot::RandomNumberGenerator::_new();
  7. _animated_sprite = get_node<godot::AnimatedSprite2D>("AnimatedSprite2D");
  8. _animated_sprite->set_playing(true);
  9. godot::PoolStringArray mob_types = _animated_sprite->get_sprite_frames()->get_animation_names();
  10. _animated_sprite->set_animation(mob_types[random->randi() % mob_types.size()]);
  11. }

First, we get the list of animation names from the AnimatedSprite2D’s frames property. This returns an Array containing all three animation names: ["walk", "swim", "fly"].

We then need to pick a random number between 0 and 2 to select one of these names from the list (array indices start at 0). randi() % n selects a random integer between 0 and n-1.

The last piece is to make the mobs delete themselves when they leave the screen. Connect the screen_exited() signal of the VisibleOnScreenNotifier2D node to the Mob and add this code:

GDScriptC#C++

  1. func _on_visible_on_screen_notifier_2d_screen_exited():
  2. queue_free()
  1. private void OnVisibleOnScreenNotifier2DScreenExited()
  2. {
  3. QueueFree();
  4. }
  1. // This code goes in `mob.cpp`.
  2. void Mob::_on_visible_on_screen_notifier_2d_screen_exited() {
  3. queue_free();
  4. }

This completes the Mob scene.

With the player and enemies ready, in the next part, we’ll bring them together in a new scene. We’ll make enemies spawn randomly around the game board and move forward, turning our project into a playable game.