Creating the enemy¶
是時候來做一些讓玩家閃躲的敵人了。這些敵人的行為不會很複雜:怪物會隨機在螢幕的邊緣產生,接著隨機選一個方向來直線移動。
我們來建立一個 Mob
(怪物) 場景,我們利用這個場景來在遊戲中 實體化 多個獨立的怪物。
設定節點¶
點擊 [場景] -> [新增場景],然後新增下列節點:
RigidBody2D (設定名稱為
Mob
)
別忘了把子節點設定成無法選擇,跟剛剛在 Player 場景中一樣。
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.

接著像剛才設定玩家那樣,設定 AnimatedSprite 。這次有三種動畫: fly
(飛行)、 swim
(游泳) 與 walk
(行走)。每個動畫都有兩個圖片,放在 art 資料夾中。
將所有動畫的「速度 (FPS)」調整為 3
。

Set the Playing
property in the Inspector to "On".
接著我們會隨機選擇其中一個動畫來播放,這樣才不會讓所有怪物看起來都一樣。
Like the player images, these mob images need to be scaled down. Set the
AnimatedSprite
's Scale
property to (0.75, 0.75)
.
與 Player
場景中一樣,新增 CapsuleShape2D
來設定碰撞區域。你會需要將 Rotation Degrees
(旋轉角度)屬性設定為 90
才能將形狀對齊圖片(這個屬性在屬性面板中的「Transform」(變形)底下)。
保存場景。
敵人腳本¶
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"]
.
接著我們需要選擇 0
到 2
間的一個隨機數,用來從這個陣列中選擇名稱(陣列的索引從 0
開始)。 使用 randi() % n
可以從 0
到 n - 1
之間隨機選擇一個整數。
備註
要讓「隨機」產生的數字在每次執行場景的時候都不同的話,需要呼叫 randomize()
。我們之後會在 Main
場景中呼叫 randomize()
的,現在還不需要他。
最後我們來讓怪物在離開畫面後刪除自己。連接 VisibilityNotifier2D
節點的 screen_exited()
訊號,並新增這段程式碼:
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();
}
這樣就完成了 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.