
上一篇的敵人是用 Node2D 為基底製作,但是敵人在移動時不會根據地形有起伏效果,甚至只要沒有對到地圖會有浮空情況。

上圖紅圈就是用 Node2D 製作的,只要方到空中就會左右(碰到牆壁後返回)移動,而將其放到吊橋(吊橋的碰撞範圍有內凹,理論上要有高低起伏),就會出現經過吊橋時會浮在空中。
所以這邊進一步改造敵人結構,讓其可以受到物理引響,讓地人可以貼在地面上走。
新的結構如下
CharacterBody2D ← 專門用於通過腳本移動的角色的 2D 物理物體。
├── AnimatedSprite2D ← 敵人動畫
└── Killzone ← 之前做的死亡區拿來應用
└── CollisionShape2D ← 死亡判定
└── CollisionShape2D ← 碰撞判定
└── RayCast2D_Left ← 檢測前方是否有障礙物
└── RayCast2D_Right ← 檢測前方是否有障礙物
腳本
extends CharacterBody2D // 腳本掛在一個 CharacterBody2D 上
// CharacterBody2D 是 Godot 提供的「可控角色」節點,內建物理功能(掉落、偵測地板、牆壁等)。
@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
const JUMP_VELOCITY = -400.0
const SPEED2 = 60
var direction = 1
func _physics_process(delta: float) -> void:
# Add the gravity.
if not is_on_floor():
velocity += get_gravity() * delta
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
velocity.x = SPEED2 * direction
move_and_slide()
我將原本 Node2D 換成 CharacterBody2D 來感應物理,由於 CharacterBody2D 需要 CollisionShape2D 感應碰撞,所以要另外加入,之前在 Node2D 因為不需要物理判定,只有死亡區需要,至於其他就一樣。
ray_cast_2d_left → 左邊的偵測線(檢查左邊是否碰到牆)。
ray_cast_2d_right → 右邊的偵測線(檢查右邊是否碰到牆)。
animated_sprite_2d → 動畫節點(用來翻轉角色的朝向)。
func _physics_process(delta: float) -> void:
這個函式每一幀物理更新時執行一次,delta 是時間間隔(確保不同 FPS 下速度一致)。
if not is_on_floor():
velocity += get_gravity() * delta
如果角色 不在地板上 → 套用重力,加到 velocity。
這是 Godot 內建的角色掉落方式。
velocity.x = SPEED2 * direction
move_and_slide()
這行執行物理移動,處理掉落與地板的碰撞。
⚠️ 但因為水平移動用的是 position.x += ...,這邊的 move_and_slide() 其實只影響 垂直方向的重力,水平方向不會受到物理影響。
角色會受到重力影響,會掉到地板上。
水平移動靠 RayCast2D 偵測牆壁 → 撞到就轉向。
角色的圖片會根據方向翻轉。
水平方向的移動是 直接修改座標,不是透過物理引擎(所以會穿透 TileMap / 其他物件)。