
敵人在影片中的結構如下
Node2D ← 敵人根結點
├── AnimatedSprite2D ← 敵人動畫
└── Killzone ← 之前做的死亡區拿來應用
└── CollisionShape2D ← 碰撞判定
└── RayCast2D_Left ← 檢測前方是否有障礙物
└── RayCast2D_Right ← 檢測前方是否有障礙物
腳本
extends Node2D //腳本附加在 Node2D 上
const SPEED = 60
var direction = 1
@onready var ray_cast_2d_left: RayCast2D = $RayCast2D_Left
@onready var ray_cast_2d_right: RayCast2D = $RayCast2D_Right
@onready var animated_sprite_2d: AnimatedSprite2D = $AnimatedSprite2D
# Called when the node enters the scene tree for the first time.
func _ready() -> void:
pass # Replace with function body.
# Called every frame. 'delta' is the elapsed time since the previous frame.
func _process(delta: float) -> void:
if ray_cast_2d_right.is_colliding():
animated_sprite_2d.flip_h = true
direction = -1
if ray_cast_2d_left.is_colliding():
direction = 1
animated_sprite_2d.flip_h = false
position.x += SPEED * delta * direction
影片中的比較簡單,簡單就講就是一個無限播放的 AnimatedSprite2D ,身上掛載的死亡碰撞區塊 (關於死亡碰撞區為何不把 CollisionShape2D 放到 Killzone 其節點內,而是先把Killzone 放到主場景再把 CollisionShape2D 放到下一層,主要原因是這樣做法比較彈性,如果直接放到 Killzone 內,就無法重複利用),再搭配上 RayCast2D 判定是否碰走到底來判定是否把節點翻轉。
RayCast2D_Left:放在角色左邊,朝左偵測牆壁。
RayCast2D_Right:放在角色右邊,朝右偵測牆壁。
AnimatedSprite2D:角色的動畫控制器(用來左右翻轉角色圖片)。
if ray_cast_2d_right.is_colliding():
animated_sprite_2d.flip_h = true
direction = -1
如果右邊的 RayCast2D 偵測到碰撞:
- 翻轉動畫(角色往左看)。
- 設定
direction = -1
,開始往左移動。
position.x += SPEED * delta * direction
由於之前在平台製作是採用影格移動方式,但怪物可能會重複利用很多地方,這樣畫用影格製作就相當麻煩,所以這邊用程式碼建立怪物移動方式。
🔹 delta
是什麼?
在 Godot(或遊戲引擎)裡,delta
代表 「上一幀到現在這一幀的時間差」,單位是 秒。
🔹 為什麼要用 delta
?
因為遊戲的更新速度(FPS, 每秒幀數)不是固定的:
- 有時候遊戲跑得快(120 FPS,每幀 0.008 秒)。
- 有時候遊戲跑得慢(30 FPS,每幀 0.033 秒)。
如果你不用 delta
,只用固定數字去加位置,物體會在不同電腦上跑出不同速度。
錯誤(沒用 delta)
position.x += 5 # 每幀移動 5px
- 在 30 FPS → 1 秒 = 30 * 5 = 150 px
- 在 60 FPS → 1 秒 = 60 * 5 = 300 px
👉 不同 FPS,速度不同,遊戲就不穩定。
正確(有用 delta)
const SPEED = 300 # 每秒移動 300px
position.x += SPEED * delta
- 在 30 FPS (
delta ≈ 0.033
) → 每幀移動 ≈ 9.9 px → 1 秒移動 300 px - 在 60 FPS (
delta ≈ 0.016
) → 每幀移動 ≈ 4.8 px → 1 秒移動 300 px
👉 不論 FPS,最終速度一致。