W ostatnich dwóch wpisach zajęliśmy się kwestiami paska życia oraz systemu punktów życia. Teraz czas na zadawanie obrażeń 😉
System ataku pozwala graczowi zadawać obrażenia przeciwnikom. Może to być atak mieczem, uderzenie pięścią, strzał z broni, zaklęcie albo dowolna inna akcja bojowa. W tym artykule stworzymy prosty system ataku w Godot 4, który wykrywa przeciwników w zasięgu i zadaje im obrażenia.

Najważniejsze jest to, aby system ataku nie był na sztywno połączony tylko z jednym przeciwnikiem. Gracz powinien móc zaatakować dowolny obiekt, który posiada system zdrowia.
Przykładowa struktura gracza
Player (CharacterBody2D)
├── Sprite2D
├── CollisionShape2D
└── AttackArea (Area2D)
└── CollisionShape2D
AttackArea to obszar ataku. Jeżeli przeciwnik znajduje się wewnątrz tego obszaru, może zostać trafiony.
Skrypt AttackArea.gd
Utwórz skrypt AttackArea.gd i przypisz go do node’a AttackArea.
extends Area2D
@export var damage: int = 10
@export var attack_cooldown: float = 0.4
var targets: Array[Node] = []
var can_attack: bool = true
func _ready() -> void:
body_entered.connect(_on_body_entered)
body_exited.connect(_on_body_exited)
func _on_body_entered(body: Node) -> void:
if body.has_node("HealthComponent"):
targets.append(body)
func _on_body_exited(body: Node) -> void:
targets.erase(body)
func attack() -> void:
if not can_attack:
return
if targets.is_empty():
return
can_attack = false
for target in targets:
if not is_instance_valid(target):
continue
if target.has_node("HealthComponent"):
var health_component = target.get_node("HealthComponent")
health_component.take_damage(damage)
await get_tree().create_timer(attack_cooldown).timeout
can_attack = true
Jak działa ten system?
Gdy przeciwnik wejdzie w obszar AttackArea, zostaje dodany do tablicy targets. Gdy wyjdzie z obszaru, zostaje z niej usunięty. Dzięki temu gracz zawsze wie, które obiekty znajdują się w zasięgu ataku.
Funkcja attack() sprawdza, czy atak jest aktualnie możliwy. Jeżeli tak, przechodzi po wszystkich celach w zasięgu i zadaje im obrażenia przez wywołanie funkcji take_damage() w komponencie zdrowia.
Wywołanie ataku ze skryptu gracza
W skrypcie gracza trzeba odwołać się do node’a AttackArea.
extends CharacterBody2D
@onready var attack_area: Area2D = $AttackArea
func _process(_delta: float) -> void:
if Input.is_action_just_pressed("attack"):
attack_area.attack()
W ustawieniach projektu należy wcześniej dodać akcję attack w Project Settings → Input Map. Można przypisać do niej na przykład lewy przycisk myszy, spację albo klawisz F.
Dlaczego potrzebny jest cooldown?
Bez ograniczenia czasowego gracz mógłby zadawać obrażenia w każdej klatce gry. To oznaczałoby, że przeciwnik mógłby zginąć natychmiast. Zmienna attack_cooldown określa, jak często można wykonać kolejny atak.
Jak dodać animację ataku?
Jeżeli gracz posiada AnimatedSprite2D, można podczas ataku odtworzyć animację:
@onready var animated_sprite: AnimatedSprite2D = $AnimatedSprite2D
func _process(_delta: float) -> void:
if Input.is_action_just_pressed("attack"):
animated_sprite.play("attack")
attack_area.attack()
W bardziej rozbudowanej wersji obrażenia powinny być zadawane dopiero w konkretnym momencie animacji, na przykład wtedy, gdy miecz faktycznie trafia przeciwnika.
Co można rozbudować?
- różne typy broni,
- różne zasięgi ataku,
- atak tylko w kierunku patrzenia gracza,
- obrażenia krytyczne,
- odrzucenie przeciwnika,
- efekty cząsteczkowe,
- dźwięk uderzenia,
- blokowanie ataku podczas animacji.
Podsumowanie
Prosty system ataku w Godot 4 można stworzyć z pomocą Area2D, sygnałów wejścia i wyjścia oraz komponentu zdrowia. To dobry fundament pod bardziej rozbudowany system walki, który można później rozwijać o broń, animacje, efekty i różne typy przeciwników.
Linki do zewnętrznych artykułów:
https://cgarchives.com/build-a-dynamic-combat-system-in-godot-4
