Creating the enemy¶
Nadszedł czas, aby stworzyć przeciwników, których nasz gracz będzie musiał unikać. Ich zachowanie nie będzie zbyt skomplikowane: przeciwnicy będą pojawiać się losowo na krawędziach ekranu i poruszać w losowym kierunku po linii prostej, a następnie usuwać się, gdy "wyjdą" poza granicę ekranu po przeciwnej stronie.
Stworzymy scenę ``Mob``(Przeciwnik), której będziemy mogli tworzyć instancje, czyli powielać ją dowolną razy, tworząc niezależnych przeciwników w grze.
Konfiguracja węzła¶
Kliknijmy Scena -> Nowa scena i stwórzmy podane węzły:
RigidBody2D (o nazwie
Mob
): ref: 'AnimatedSprite <class_AnimatedSprite>'
Nie zapomnij ustawić dzieci tak, aby nie mogły być wybierane, tak jak zrobiliśmy to w przypadku sceny z graczem.
In the RigidBody2D properties, set Gravity Scale
to 0
, so the mob will not fall downward. In addition, under the
CollisionObject2D section, click the Mask
property and uncheck the first
box. This will ensure the mobs do not collide with each other.

Skonfigurujmy AnimatedSprite tak, jak zrobiliśmy to dla gracza. Tym razem mamy 3 animacje: fly
, swim
i walk
. W folderze "art" mamy po dwie grafiki dla każdej z animacji.
Ustawmy "Prędkość (FPS)" na 3
dla każdej z animacji.

Set the Playing
property in the Inspector to "On".
Będziemy wybrać jedną z tych animacji losowo, stąd nasi przeciwnicy będą w jakiś sposób różnorodni.
Like the player images, these mob images need to be scaled down. Set the
AnimatedSprite
's Scale
property to (0.75, 0.75)
.
Podobnie jak w przypadku sceny Player
, dodaj CapsuleShape2D
dla kolizji. Aby wyrównać kształt kolizji z grafiką przeciwnika, należy ustawić właściwość Rotation Degrees``(Kąt obrotu) na ``90
pod Node2D
.
Zapisz scenę.
Skrypt wroga¶
Add a script to the Mob
like this:
extends RigidBody2D
public class Mob : RigidBody2D
{
// Don't forget to rebuild the project.
}
// Copy `player.gdns` to `mob.gdns` and replace `Player` with `Mob`.
// Attach the `mob.gdns` file to the Mob node.
// Create two files `mob.cpp` and `mob.hpp` next to `entry.cpp` in `src`.
// This code goes in `mob.hpp`. We also define the methods we'll be using here.
#ifndef MOB_H
#define MOB_H
#include <AnimatedSprite.hpp>
#include <Godot.hpp>
#include <RigidBody2D.hpp>
class Mob : public godot::RigidBody2D {
GODOT_CLASS(Mob, godot::RigidBody2D)
godot::AnimatedSprite *_animated_sprite;
public:
void _init() {}
void _ready();
void _on_VisibilityNotifier2D_screen_exited();
static void _register_methods();
};
#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:
func _ready():
$AnimatedSprite.playing = true
var mob_types = $AnimatedSprite.frames.get_animation_names()
$AnimatedSprite.animation = mob_types[randi() % mob_types.size()]
public override void _Ready()
{
var animSprite = GetNode<AnimatedSprite>("AnimatedSprite");
animSprite.Playing = true;
string[] mobTypes = animSprite.Frames.GetAnimationNames();
animSprite.Animation = mobTypes[GD.Randi() % mobTypes.Length];
}
// This code goes in `mob.cpp`.
#include "mob.hpp"
#include <RandomNumberGenerator.hpp>
#include <SpriteFrames.hpp>
void Mob::_ready() {
godot::Ref<godot::RandomNumberGenerator> random = godot::RandomNumberGenerator::_new();
random->randomize();
_animated_sprite = get_node<godot::AnimatedSprite>("AnimatedSprite");
_animated_sprite->_set_playing(true);
godot::PoolStringArray mob_types = _animated_sprite->get_sprite_frames()->get_animation_names();
_animated_sprite->set_animation(mob_types[random->randi() % mob_types.size()]);
}
First, we get the list of animation names from the AnimatedSprite's frames
property. This returns an Array containing all three animation names: ["walk",
"swim", "fly"]
.
Następnie uzyskujemy losową wartość pomiędzy 0
a 2
, aby na jej podstawie móc uzyskać nazwę znajdującą się na wylosowanym miejscu na liście (tablica zaczyna liczenie miejsc od 0
- to znaczy, że na naszej liście nazwa walk
kryje się pod wartością 0
, nazwa swim
pod 1
, zaś nazwa fly
pod 2
). Funkcja randi() % n
wybiera losową liczbę pomiędzy zerem, a n-1
.
Informacja
Należy użyć randomize()
, jeśli chcemy, aby sekwencja liczb "losowych" różniła się za każdym razem, gdy scena zostanie uruchomiona. Jednak z racji, że skorzystamy z randomize()
w naszej scenie Main
, nie jest to nam tutaj potrzebne.
Ostatnim krokiem jest zmuszenie przeciwników do samodzielnego usunięcia się po opuszczeniu ekranu. Trzeba podłączyć funkcję screen_exited()
z sygnałem Visibility
i dodać ten kod:
func _on_VisibilityNotifier2D_screen_exited():
queue_free()
public void OnVisibilityNotifier2DScreenExited()
{
QueueFree();
}
// This code goes in `mob.cpp`.
void Mob::_on_VisibilityNotifier2D_screen_exited() {
queue_free();
}
To kończy tworzenie sceny Mob.
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.