Designing third-person melee combat: lock-on targeting, trace-based hit detection, blocking, dodge rolls, and dual-behavior enemy AI.
This project is a third-person melee combat prototype built entirely in Blueprints with Unreal Engine 5, developed following this Udemy course. It covers the core systems of action-RPG and souls-like combat: a lock-on targeting system, animation-driven hit detection via trace components, blocking, dodge rolls, and enemy AI with distinct melee and ranged behaviors. Together these systems form a complete combat framework that’s more architecturally demanding than any single mechanic in isolation.
You can watch the prototype in action here: YouTube
Lock-On Targeting System
The lock-on system is what distinguishes deliberate, skill-based melee combat from general third-person action. When the player locks onto a target, three things change simultaneously: the camera orients to keep the target in frame, the player’s movement becomes relative to the target rather than relative to the camera, and the character’s facing direction is locked toward the target regardless of movement direction.
Finding the lock-on target requires scanning nearby actors — typically a sphere overlap to find all valid targets within range, then selecting the one closest to the camera’s center axis (the most “in front of” the player). When multiple valid targets exist, the player can cycle between them with a directional input while locked on.
The camera behavior during lock-on is the most complex part. The camera needs to keep both the player character and the target visible, which means the spring arm length and the look-at offset must adjust based on the distance between them. A target that’s very close needs a shorter spring arm; a target at maximum lock-on range needs the camera pulled back. This distance-based spring arm adjustment is what prevents the camera from clipping through the player or losing the target off-screen during the engagement.
Releasing lock-on smoothly returns camera control to the player — an immediate snap feels jarring; a brief blend back to free camera control reads as intentional.
Trace Hit Components: Animation-Driven Hitboxes
The central technical challenge of melee combat is determining when a weapon actually hits. The naive approach uses a static collision volume on the weapon that fires overlap events continuously — but this produces hits even when the weapon is at rest, and can miss fast attacks that move the weapon significantly between physics ticks.
The correct approach is trace-based hit detection activated only during the attack frames of an animation. A Trace Hit Component stores the weapon’s position from the previous frame. During the active attack window — triggered by an animation notify — it sweeps from the previous position to the current position each tick, registering any targets the weapon passed through during that movement. This is sweep-based collision applied specifically to melee: it catches fast swings, fires no hits outside the active window, and scales correctly to any weapon size via configurable trace shape.
The animation notify system is what makes this architecture clean. The attack animation has two notifies: WeaponTraceStart (activates the trace component) and WeaponTraceStop (deactivates it). Outside of these notifies, the weapon deals no damage regardless of its position. This means the hitbox lifecycle is defined by the animator in the animation asset, not by gameplay code — the right separation of concerns.
A hit target registers only once per attack regardless of how many trace samples hit it during the swing, preventing multiple damage events from a single strike.
Blocking
Blocking is a defensive state that reduces or nullifies incoming damage when active. The player holds a block input, which transitions the character to a blocking animation state and enables the block flag. When a hit arrives while blocking, the damage is reduced or absorbed entirely, and a block reaction animation plays instead of a hit reaction.
The directional component of blocking — whether a block is effective depends on whether the attack comes from the front — requires checking the angle between the incoming hit direction and the player’s facing direction. An attack from behind bypasses the block; an attack from a wide lateral angle may partially bypass it. This angular check gives blocking a spatial dimension that rewards the player for keeping their front toward the threat.
Blocking is also the setup for parry in more complete combat systems: a block input timed precisely to the moment of impact returns a high-damage counterattack opportunity. This prototype implements basic blocking without the parry timing window, but the architecture supports extending it — the same damage event that checks the block flag can additionally check an active parry window.
Dodge Roll
The dodge roll is an invincibility-window mechanic: for the duration of the roll animation, the player takes no damage. This is implemented as a brief flag on the player character that disables the damage receive function — any hits during this window are silently ignored.
The roll direction is determined by the player’s current movement input at the moment the roll is triggered — no input rolls backward (a back-step dodge), directional input rolls in the corresponding direction. During the roll, movement input is consumed by the roll animation rather than feeding the character’s movement component.
The invincibility window needs to be tuned carefully — too long and the roll becomes a trivially safe panic button; too short and it feels unreliable. The active window is typically a subset of the total roll duration: the first and last frames are vulnerable, with invincibility applying only during the central frames of the roll animation.
Enemy AI: Melee and Ranged Behaviors
The two enemy types — melee and ranged — share the same Behavior Tree structure at the top level (patrol → detect → engage) but diverge in their engage behavior based on their attack type.
The melee enemy closes distance to the player and attacks when within striking range. Its engage state is a pursuit loop: move toward the player until within attack range, attack, then return to pursuit if the player moves away. The attack choice — which strike from its combo set — can be randomized or sequential, giving the enemy some unpredictability.
The ranged enemy maintains distance. Its engage state checks whether the player is within a preferred range band — close enough to hit, far enough to be safe — and moves forward or backward to stay within it. When in the preferred range, it attacks via a projectile aimed at the player’s current position. Strafing behavior — circling the player while at range — adds threat to ranged enemies without requiring complex pathfinding.
The combat AI design implication of having both types is that encounters become more interesting when they’re mixed. A melee enemy forces the player into close range where the ranged enemy’s projectiles are harder to dodge. This is emergent difficulty from combining two simple behaviors rather than from making either behavior more complex.
Combo System
The melee attack system supports combos — sequential inputs within a timing window that chain attacks rather than returning to idle between strikes. The combo state machine tracks the current attack in the sequence and whether the player pressed the attack input during the active combo window. If the input arrives within the window, the next attack in the chain fires immediately at the end of the current one; if not, the combo resets.
The combo window is defined by animation notifies — ComboWindowOpen and ComboWindowClose — placing the window timing in the animation asset where it belongs. The gap between ComboWindowClose and the end of the attack animation is the recovery period: the enemy can attack during this time, but the player cannot continue the combo.
Reflection
The melee combat system is the most mechanically complete of all the Blueprint projects. It’s the first one where the interaction between systems — lock-on influencing camera, animation notifies driving hitboxes, blocking gating damage, dodge providing invincibility — produces emergent gameplay complexity that exceeds what any single system could produce alone.
The trace hit component pattern in particular is one of the most transferable techniques from this project. It appears in virtually every action game with physical melee combat, and the architecture — animation-notify gated sweep traces with single-hit-per-attack deduplication — is the production standard for a reason: it’s correct, it’s cheap, and it keeps hit detection synchronized with visual feedback.
In C++, this maps to a UTraceHitComponent that stores the previous socket transform each tick, activates on a UFUNCTION called by an FAnimNotify, sweeps with SweepMultiByChannel, and filters the hit results against a set of already-hit actors cleared at attack start.
Leave a comment