, ,

Jak zrobić przeciwnika, który goni gracza w Godot 4?

·

Przeciwnik, który goni gracza, to jedna z najczęściej tworzonych mechanik w pierwszych projektach Godot. Taki przeciwnik może być szkieletem, potworem, robotem, strażnikiem albo dowolną inną postacią, która wykrywa gracza i porusza się w jego stronę.

W tym przykładzie stworzymy prostą wersję AI przeciwnika dla gry 2D. Przeciwnik będzie wykrywał gracza w określonym obszarze, a następnie będzie poruszał się w jego kierunku.

Przykładowa struktura sceny

Enemy (CharacterBody2D)
├── Sprite2D
├── CollisionShape2D
└── DetectionArea (Area2D)
└── CollisionShape2D

Enemy jest typu CharacterBody2D, ponieważ będzie poruszany skryptem i będzie korzystał z kolizji. DetectionArea odpowiada za wykrycie gracza.

Ustawienie grupy dla gracza

Najwygodniej oznaczyć gracza grupą player. W Godot można to zrobić w edytorze, w zakładce Node → Groups. Dodaj tam grupę:

player

Dzięki temu przeciwnik nie musi sprawdzać nazwy node’a. Wystarczy, że sprawdzi, czy wykryty obiekt należy do grupy player.

Skrypt Enemy.gd

extends CharacterBody2D

@export var speed: float = 120.0

var target: Node2D = null

func _ready() -> void:
$DetectionArea.body_entered.connect(_on_detection_area_body_entered)
$DetectionArea.body_exited.connect(_on_detection_area_body_exited)

func _physics_process(_delta: float) -> void:
if target == null:
velocity = Vector2.ZERO
move_and_slide()
return

var direction: Vector2 = global_position.direction_to(target.global_position)
velocity = direction * speed
move_and_slide()

func _on_detection_area_body_entered(body: Node) -> void:
if body.is_in_group(“player”):
target = body

func _on_detection_area_body_exited(body: Node) -> void:
if body == target:
target = null

Jak działa ten kod?

Gdy gracz wejdzie do DetectionArea, przeciwnik zapisuje go jako cel w zmiennej target. Od tego momentu w każdej klatce fizyki obliczany jest kierunek do gracza. Następnie przeciwnik ustawia swoją prędkość i wykonuje move_and_slide().

Gdy gracz wyjdzie z obszaru wykrywania, zmienna target zostaje ustawiona na null, a przeciwnik przestaje się poruszać.

Jak ustawić zasięg wykrywania?

Zasięg wykrywania zależy od kształtu CollisionShape2D wewnątrz DetectionArea. Najczęściej używa się CircleShape2D. Im większy promień, tym szybciej przeciwnik zauważy gracza.

Warto pamiętać, że zasięg wykrywania nie powinien być tym samym co zasięg ataku. Przeciwnik może wykrywać gracza z daleka, ale atakować dopiero wtedy, gdy znajdzie się bardzo blisko.

Dodanie zatrzymania przy graczu

W obecnej wersji przeciwnik będzie próbował wejść dokładnie na pozycję gracza. Można dodać minimalny dystans zatrzymania:

@export var stop_distance: float = 24.0

func _physics_process(_delta: float) -> void:
if target == null:
velocity = Vector2.ZERO
move_and_slide()
return

var distance: float = global_position.distance_to(target.global_position)

if distance <= stop_distance:
    velocity = Vector2.ZERO
    move_and_slide()
    return

var direction: Vector2 = global_position.direction_to(target.global_position)
velocity = direction * speed
move_and_slide()

Dzięki temu przeciwnik zatrzyma się przy graczu, zamiast cały czas próbować wejść w jego środek.

Co można dodać później?

- patrolowanie między punktami,

- powrót na pozycję startową,

- atak po wejściu w zasięg,

- animację biegu i postoju,

- różne typy przeciwników,

- reakcję na hałas,

- wykrywanie gracza tylko w polu widzenia.

Podsumowanie

Przeciwnik goniący gracza to bardzo dobra mechanika do nauki podstaw AI w Godot 4. Wystarczy CharacterBody2D, Area2D, sygnały wykrywania i proste obliczenie kierunku ruchu. Na tej podstawie można później budować bardziej zaawansowane zachowania przeciwników.

Poprzedni wpis:

Poprzedni poradnik:
Następny poradnik: