Video summary

Combat Systems – Create a 2D RPG in Godot 4

Main summary

Key takeaways

Technology

This tutorial covers (Godot 4 core 2D RPG combat + AI)

This tutorial builds the core 2D RPG combat loop in Godot 4: enemy health/damage, hitbox & hurtbox setup, death effects/animation, directional attack hit detection, and then enemy AI that chases/returns using the navigation server while avoiding obstacles.


Combat mechanics and enemy setup

  • Create an enemy scene by duplicating player.tscn → enemy.tscn
    • Remove the player script
    • Add an enemy script
  • Replace the enemy sprite with a red warrior from an asset pack (for quick reuse in the tutorial)

Enemy combat stats

  • Implement exported hit_points (example: 180)
  • Add take_damage(damage_taken):
    • Subtracts hit points
    • Calls death() when hit points ≤ 0
    • death() initially frees the enemy (later replaced with a death animation effect)

Hitboxes, hurtboxes, and physics layer separation

Enemy hurtbox

  • Add an Area2D with a CollisionShape2D (capsule shape)
  • Rename it to hurt box
  • Set monitoring = off so it doesn’t “detect” other things
  • Purpose: it should only be “hit” by the player’s hitbox

Damage layer strategy (prevent friendly fire)

Introduce physics layers to separate who can affect whom:

  • Layer 5 = enemy damage
  • Layer 6 = player damage

This prevents cases like:

  • AOE damaging players when it shouldn’t
  • melee enemies damaging each other

Configure the enemy hurtbox to react on the correct layer (enemy damage).

Player hitbox (sword)

  • Add an Area2D hitbox to the player scene
  • Use a RectangleShape2D aligned to the sword blade
  • Disable layers entirely for existence (so it won’t be “found” by other areas)
  • Configure the hitbox to collide only via mask:
    • hitbox mask targets enemy damage layer
  • Key gameplay detail:
    • Hitbox monitoring is OFF by default
    • Enable it only during the swing via animation timing

Animation-driven hit detection (attack timing)

In the player’s AnimationPlayer:

  • Add tracks for the hitbox:
    • Toggle monitoring ON only at the slash moment
    • Keyframe hitbox position/rotation to follow the sword

Signal wiring

  • Connect hitbox’s area_entered to the player script
  • In the callback:
    • Call take_damage(attack_damage) on the detected enemy hurtbox owner
    • Example flow: area.get_owner().take_damage(attack_damage)

Damage tuning

  • Add exported attack_damage to player (example: 60)
  • With enemy 180 HP, the enemy dies after ~3 hits

Death animation as a separate scene/effect

  • Create a death.tscn effect scene:
    • A Node2D containing an animated Sprite2D (skull falling/sinking)
    • Driven by an AnimationPlayer
    • Use finished signal to clean up
  • Upgrade enemy script:
    • Export death_packed : PackedScene
    • Instantiate it on death
    • Spawn death effect at enemy position with a small Y offset
  • Add an effects container node to the map and retrieve it efficiently via @unique_name
    • Uses a hashed unique-name lookup instead of get_node(path)

Directional attacks and animation mirroring limits

  • Expand attack directions by duplicating animations to add attack left
    • (Up/down are mentioned as already handled)
  • Important note:
    • Don’t flip the entire animation tree
    • Flip only the sprite
    • Ensure hitbox position/rotation are correct per direction

Gameplay tuning note

Hitbox size/offset influences perceived fairness and range (it doesn’t have to match pixel-perfect animation tracing).


Enemy AI: states + chase/return logic

Enemy script includes a state enum-like flow:

  • idle
  • chasing (chase)
  • returning (back to spawn)
  • attack
  • dead

Per-physics-tick (~60 FPS) behavior

  1. If dead → do nothing
  2. If attacking → lock movement until done
  3. If within attack_range → switch to attack
  4. Else if within aggro_range → chase
  5. Else if far from spawn (> 32 px) → return to spawn
  6. Else → idle and update animation

AI stats introduced

  • Enemy speed (example: 128, slower than player so the player can kite)
  • Attack damage (example: 10)
  • Attack speed / cooldown (example: ~1 second)
  • Aggro range and attack range thresholds

Taking damage on the player side

Enemy detection

  • Enemy hurtbox detection connects enemy hitbox/area signal (area_entered) into the damage flow

Player script requirements

  • Add:
    • hit_points
    • take_damage(damage_taken)
    • death() (initially print("I died"), later replaced with full UI)

Object-oriented rationale (routing damage via functions)

Instead of directly decrementing player.hit_points from the enemy script, damage goes through an entry-point method:

  • The enemy calls the player/entity’s take_damage(...)
  • Or otherwise routes the request through the owner/method

Reason: encapsulation and maintainability—player can manage armor/status effects internally.


Enemy chase without getting stuck: NavigationAgent2D + NavigationMesh

The problem

Naively moving straight toward the player makes enemies collide with obstacles (trees/cliffs).

The solution

  • Add NavigationAgent2D to the enemy
  • Configure:
    • path postprocessing: edge-centered
    • avoidance: avoid other navigation agents (neighbor distance, radius, max speed)
    • debugging: enable showing path (custom color)

Movement implementation

  • When chasing:
    • nav_agent.target_position = player.global_position
  • When returning:
    • use stored spawn_point
  • Steering:
    • nav_agent.get_next_path_position() for next steering point
  • Velocity:
    • character velocity is driven accordingly
    • with avoidance, it uses the nav agent’s computed safe velocity via its velocity_computed signal

Building navigation regions on the tile map

  • Add a dedicated navigation tile layer (separate from physics layers)
  • Create a navigation mesh painter tile set (example resolution choices around 32x32)
  • Paint:
    • Green = navigable region
    • Red = blocked region

Tuning notes

  • Increase navigation resolution if enemies clip or can’t path around props
  • Turn off navigation where collision sizes make it infeasible (e.g., narrow passages around trees/cliffs)

Validation & common issue

  • With debug enabled, enemies show their paths
  • Initially, enemies may get stuck on water/shore collision
    • Fix by separating navigation/physics collision behavior
    • Adjust collision layers so the enemy is placed on a different collision layer (so navigation works while still colliding with the player)

Outcome stated

By the end of this episode, you get:

  • Working combat
    • hitbox-driven damage
    • death effect
  • Enemy chase/return AI
    • navigation meshes
    • avoidance enabled

Next episodes

  • Episode 4 next: player progression/leveling and an experience system
  • UI/game-over is referenced as later (after player death behavior is replaced with an end screen)

Main speakers / sources

  • Tutorial narrator / instructor (primary speaker)
    • Building a Godot 4 RPG combat system using code and editor walkthroughs
  • Godot Engine documentation concepts implicitly referenced:
    • NavigationAgent2D, NavigationMesh / tile navigation painting
    • Area2D signals (area_entered)
    • AnimationPlayer tracks
    • Physics layers & masks

Rate this summary

Your feedback will help improve summaries.

Improve this summary

Reprocess with a stronger model when the summary feels incomplete or inaccurate.

Pro

Translate summary in another language

Pro

Ask questions to this video

Chat for follow-up questions, clarifications, and source-backed answers.

Coming soon

Share this summary

Original video