# Attack Steering

> Attack Steering makes an attack turn to its target, close the gap and stop short of it instead of running into it, through windows you mark on the montage and the UPC Attack Approach component.

Markdown version of https://rigbak.com/docs/universal-player-combat/attack-steering, a page of the Universal Player Combat documentation. Link that page when citing it.

## Set it up (5 minutes)

1. **Mark the wind-up on an attack montage**

   Open an attack montage animated on the spot, with no root motion. On a notify track, right-click at the wind-up's start, pick **Add Notify State > UPC Approach Window**, and drag its end to where the swing begins: the start of the montage's **UPC Melee Trace Window**, the window that sweeps the weapon for hits ([Melee Trace](https://rigbak.com/docs/universal-player-combat/melee-trace#the-montage-window)). Leave **Approach Target Name** on `Target`.

   **Timeline: AM_MyAttack** (1.2 s long). Tracks:

   - **Notifies**: UPC Approach Window (0.1 s to 0.45 s); UPC Melee Trace Window (0.45 s to 0.7 s)

   *The approach window covers the wind-up; the character arrives as the swing begins.*
2. **Play it from the action graph**

   Put the montage on a node's **Play Montage** payload in the character's action graph ([Action Graph](https://rigbak.com/docs/universal-player-combat/action-graph#choose-what-a-node-plays)). An attack takes its target as its node starts and steers only from an action graph node.
3. **Check that the style steers**

   In the character's combat style ([Combat Styles](https://rigbak.com/docs/universal-player-combat/combat-styles)), the **Targeting** fragment needs a Targeting Config and **Steering** on **Toward Target**, its default. The style writes to the **ApproachComponent** and **TargetingComponent** UPC Character Base carries; add **UPC Attack Approach** and **UPC Targeting** to any other character.

   In **CombatStyle_MyStyle**, under Fragments, Index [ 1 ]: Targeting, set:

   | Property | Value |
   | --- | --- |
   | Steering | Toward Target (replaces Distance Only) |
4. **Press Play and attack from a few steps away**

   Stand about 3.5 m from an enemy, such as the dummy from the [Targeting](https://rigbak.com/docs/universal-player-combat/targeting) quick start, and attack: the character turns toward it, glides in over the wind-up, and swings the stop distance short of it. The stop distance is 150 cm, the component's default since this style has no Approach fragment, unless the drawn weapon or the window sets its own ([order](https://rigbak.com/docs/universal-player-combat/attack-steering#where-the-stop-distance-comes-from)); the demo's bare hands stop 25 cm short.

---

## Pick how attacks steer

Three separate controls shape an attack: **Attack Facing** turns the body as the attack starts, **Steering** (set by the style's Targeting fragment on the UPC Attack Approach component) decides whether the attack closes on its target, and **Keep Distance** stops its travel short of enemies. Each works without the others.

Off: Plays where it was aimed. The swing travels its own 160 cm and lands beside the target.

*Plays where it was aimed. The swing travels its own 160 cm and lands beside the target.*

Toward Target: Turns to the target and closes in, landing the stop distance short of it.

*Turns to the target and closes in, landing the stop distance short of it.*

Distance Only: Goes where the body faces, as animated, and stops short of the enemy its path runs into. The target off to the side is left alone.

*Goes where the body faces, as animated, and stops short of the enemy its path runs into. The target off to the side is left alone.*

*Seen from above, the character starting at the dashed circle and facing up the page. The dashed ring marks the stop distance around the body an attack stops short of; blue is where the attack ends and the arrow the way it faces.*

**Toward Target** (default) glides each attack in through a UPC Approach Window or warps it through a UPC Skew Warp, both set up below. **Distance Only** and **Off** keep the animation's own travel; Distance Only also warps a dash to the gap ([Distance Only and gap closers](https://rigbak.com/docs/universal-player-combat/attack-steering#distance-only-and-gap-closers)), Off warps nothing. Steering **Off** leaves the other two controls running: with Attack Facing **Aim** and Keep Distance on, the body still snaps to the camera's aim as the attack starts ([Attack Facing](https://rigbak.com/docs/universal-player-combat/attack-steering#turn-the-body-as-an-attack-starts)) and the attack's travel still stops short of an enemy in its path ([Keep Distance](https://rigbak.com/docs/universal-player-combat/attack-steering#keep-distance-stop-short-of-enemies)).

An attack keeps the target it took as it started (the [Targeting](https://rigbak.com/docs/universal-player-combat/targeting) pick or the held lock); each hit of a combo picks again.

---

## Close the gap on a swing animated on the spot

Drag a **UPC Approach Window** across the wind-up. While it runs, the character turns toward the target and glides into range; a target already in range only turns it.

**Details panel: UPC Approach Window** (anim notify, in AM_UPC_TwoHanded_SingleAttack)

**Category: Approach**

| Property | Value |
| --- | --- |
| Move by Offset | false |
| Offset Direction | (-1, 0, 0) (greyed out) |
| Offset Distance | 50 (greyed out) |
| Approach Target Name | Target |
| Mode | Move and Face |
| Stop Distance Override | -1 (advanced) |
| Max Approach Distance Override | -1 (advanced) |
| Facing Interp Speed Override | -1 (advanced) |
| Facing Speed by Angle Override | None (advanced) |
| Override Speed Limit | false (advanced) |
| Speed Limit Override | Unlimited (advanced, greyed out) |
| Max Approach Speed Override | 600 (advanced, greyed out) |
| Override Block Movement Input | false (advanced) |
| Block Movement Input Override | false (advanced, greyed out) |
| Override Moving Target | false (advanced) |
| Moving Target Override | Lead (advanced, greyed out) |
| Lead Strength Override | -1 (advanced) |
| Time Mapping Curve Override | Curve_UPC_EaseInOut (advanced) |

*The two-handed attack's window, which eases its glide in and out. Every override left at -1 or unset takes the UPC Attack Approach component's matching Default; Stop Distance Override falls to the weapon's Attack Stop Distance first.*

| Setting | Does |
| --- | --- |
| **Approach Target Name** | Keep `Target`, the name the component stores the attack's target under. A Motion Warping window uses a different name, `UPCTarget`, below. |
| **Mode** | **Move and Face** (default), **Face Only** to turn without moving, **Move Only** to glide without turning. |
| **Move by Offset** | Moves **Offset Distance** along **Offset Direction**, in the character's own space, instead of steering: a step back on a block. |
| **Stop Distance Override**, **Max Approach Distance Override** | How far short this attack stops, and the farthest target it glides to. A value left at -1 falls through: for Stop Distance, the drawn weapon's Attack Stop Distance, else the style's [Approach fragment](https://rigbak.com/docs/universal-player-combat/combat-styles#approach-how-far-an-attack-travels) default (the component's without one); for Max Approach Distance, the style's default ([order](https://rigbak.com/docs/universal-player-combat/attack-steering#where-the-stop-distance-comes-from)). The attack's own Stop Distance on its Play Montage node wins over the window's. |

### Step forward at nothing

A **UPC Approach Or Move Window** with no target in reach moves **Move Distance** (50 cm) along **Move Direction** (ahead) instead, so a punch at empty air still lunges.

**Details panel: UPC Approach Or Move Window** (anim notify, in AM_UPC_Unarmed_Combo)

**Category: Approach**

| Property | Value |
| --- | --- |
| Move Direction | (1, 0, 0) |
| Move Distance | 40 |

*Its other fields are the UPC Approach Window's. Move Direction and Move Distance gray out under Move by Offset and under Face Only.*

---

## Close the gap on a swing with root motion

1. Give the character a **Motion Warping** component.
2. Add the engine's **Motion Warping** notify state across the stretch of the montage that travels.
3. Set its **Root Motion Modifier** to **UPC Skew Warp** and its **Warp Target Name** to `UPCTarget`.

In **Motion Warping**, under Config, set:

| Property | Value |
| --- | --- |
| Root Motion Modifier | UPC Skew Warp |
| Warp Target Name | UPCTarget (replaces None) |
| Stop Distance Override | -1 |

*The UPC Skew Warp lands the stop distance short of the target, facing it; Stop Distance Override sets the distance for this window.*

---

## Distance Only and gap closers

Pair **Distance Only** with **Attack Facing** set to **Aim**, so each attack first turns to where the camera looks. An enemy beside the path or behind the character does not stop it.

A dash closes the gap through a **UPC Gap Closer Warp** as its Motion Warping window's Root Motion Modifier (Warp Target Name `UPCTarget`): it lands the stop distance in front of the first enemy the body's facing line runs into, or plays its own travel with none on the line. Under Toward Target it lands as a UPC Skew Warp does; under Off it warps nothing.

---

## Keep Distance: stop short of enemies

**Keep Distance**, on for the UPC Attack Approach component, stops the character's travel the stop distance short of its target and of any targetable enemy in its path, whether the travel comes from root motion, a warp or a glide; the animation plays on. The enemies are those the Targeting Config's scan finds and its **Target Teams** admits. A move toward an enemy already that close holds; a move away or past it goes through. Only attack montages stop: one with a **UPC Melee Trace Window**, an Approach Window on `Target`, or a UPC Skew Warp or UPC Gap Closer Warp window. A dodge or a hit reaction plays as authored.

**Make Room** steps an attack back first when it starts closer than the stop distance to the enemy it aims at: the character moves straight back to the stop distance over the style's [Make Room Seconds](https://rigbak.com/docs/universal-player-combat/combat-styles#approach-how-far-an-attack-travels), and Keep Distance holds the swing there. That enemy is the target the attack steers at under Toward Target, else the targetable enemy deepest inside the stop distance that the facing line runs into. A wall or another body behind cuts the step short, the enemy never moves, and the body keeps its facing. Make Room Seconds starts at 0, off; the demo's Freeflow and Over Shoulder styles use 0.15. A move's own **Make Room Seconds** on its Play Montage node takes over for that attack: 0 turns the step off, above 0 turns it on under any style.

### Where the stop distance comes from

Asked first. Asked last.

1. **The move** (Stop Distance on the attack's Play Montage node, under Spacing): Counts at 0 or more, for the whole attack. -1, the default, passes the choice down. The demo's shield bash keeps 25 cm with the sword drawn.
2. **The window playing right now** (Stop Distance Override on a UPC Approach Window, UPC Approach Or Move Window, UPC Skew Warp or UPC Gap Closer Warp): Counts at 0 or more. -1, the default, passes the choice down. When two windows cover the same moment, the one that started later counts.
3. **The weapon in hand** (Attack Stop Distance on the item's Equippable fragment): Read from the item whose moves the character is using. -1, the default, passes the choice down. The demo's bare hands stop 25 cm short.
4. **The combat style** (Stop Distance on the style's Approach fragment): Written onto the UPC Attack Approach component's Default Stop Distance as the style applies. 150 cm when nothing sets it.

The same distance serves the glide, the warp's landing and Keep Distance, measured between the two capsules.

With a style at 150, a sword at 100 and a last hit whose window sets 0, the first hits stop 100 cm short and the last reaches contact; a window's override counts only while it plays. A move's own **Stop Distance** counts for the whole attack, so give a short move beside a long weapon its own: the demo's shield bash, drawn beside the sword, keeps 25 cm rather than the sword's 75.

---

## Turn the body as an attack starts

**Attack Facing**, set by the style's [Rotation fragment](https://rigbak.com/docs/universal-player-combat/combat-styles#rotation-how-the-body-turns) (**Aim**, **Movement**, **Lock Target** or **None**), snaps the body as an attack starts, when the section being played carries a UPC Melee Trace Window, an Approach Window or a Motion Warping window on `UPCTarget`. With Attack Facing on **Aim**, Steering on **Toward Target** and an enemy left of the camera's center, one attack runs:

1. **It starts:** the body snaps to the camera's aim, or to a held lock.
2. **Its Approach Window plays:** the body turns toward the target and glides in.
3. **It swings:** the body keeps the facing the window left, whatever the stick does, until the combo's next hit takes over.

---

## Debug it

```
UPC.Debug.Steering.Draw 1    // Warps in green, approach windows in orange, a ring at the stop distance
UPC.Debug.Approach 1         // The approach above each character; each window's decision and each attack's stop distance, with its source, in the log
Log LogUPCApproach Verbose   // The rest of the approach log
```

**Debug Overlay Approach** on one component shows that character alone.

<details>
<summary>Glides in detail (Advanced)</summary>

- **Moving Target**: **Lead** (default) aims where the target is heading, smoothest against a strafing enemy; **Chase** where it stands; **Committed** where it stood as the window opened, missing a target that stepped away. **Lead Strength** (1) sets how far ahead Lead aims.
- **Speed Limit**: **Unlimited** (default) spreads the distance across the window, so a large gap closes in a blink and a short one at a crawl. **Fixed Speed** travels at **Max Approach Speed** (600 cm/s) and lands short of a target too far for the window. **Character's Max Speed** reads like running.
- A window on a root motion swing makes up only the ground the swing falls short by; on a player's character, prefer Motion Warping there.
- A glide leaves height to gravity and closes on a higher target from the side; give an attack that should leap root motion or a warp.
- On the server a player's target can land after a window opened; the window then steers at it from where the character stands, taking over from an Approach Or Move Window's step.
- **Report Glide as Movement Input** (on) hands a glide's direction to the movement input, so the animation graph plays a walk or a run.
- **Ease Facing Back** turns a camera-following body back to the camera after an attack lets its facing go, at **Facing Hand Back Rate** degrees per second (0: the character's own turn rate).

</details>

<details>
<summary>How an attack takes its target (Advanced)</summary>

- A section with only a **UPC Melee Trace Window** turns and keeps its distance, and steers at no one.
- Under Distance Only an attack takes the first targetable enemy its facing line runs into, else the soft target, passing over a dead enemy.
- A body Keep Distance has counted keeps counting until the montage ends, even limp, so a killing blow's follow-through does not run into it.
- **On Attack Turned** fires with the turn in degrees, positive to the right, for an Animation Blueprint to hide a large snap behind a root offset blended out over about a tenth of a second.
- **Compute Warp Transform** answers where a warp lands; override it in a child class for a landing rule of your own, such as a flank. **Get Effective Stop Distance** reads the stop distance in force, and **Get Steering Target** the target an attack steers at.

</details>

<details>
<summary>The UPC Attack Approach component (Advanced)</summary>

**Details panel: ApproachComponent** (component, in BP_UPC_Character)

**Category: UPC > Approach > Attack Steering**

| Property | Value |
| --- | --- |
| Steering Mode | Toward Target |
| Attack Facing | None |
| Make Room Seconds | 0 |
| Warp Target Name | UPCTarget |
| Approach Target Name | Target |

**Category: UPC > Approach > Defaults**

| Property | Value |
| --- | --- |
| Default Stop Distance | 150 |
| Default Max Approach Distance | 750 |
| Default Facing Interp Speed | 12 |
| Default Facing Speed by Angle | None |
| Default Time Mapping Curve | None |
| Speed Limit | Unlimited |
| Max Approach Speed | 600 (greyed out) |
| Moving Target | Lead |
| Lead Strength | 1 |
| Report Glide as Movement Input | true |
| Block Movement Input | false |
| Ease Facing Back | true |
| Facing Hand Back Rate | 0 |

**Category: UPC > Approach > Keep Distance**

| Property | Value |
| --- | --- |
| Keep Distance | On |

**Category: UPC > Approach > Debug (collapsed until clicked)**

| Property | Value |
| --- | --- |
| Debug Overlay Approach | false |

*At its defaults. A combat style writes Steering Mode (Targeting fragment), Attack Facing (Rotation fragment), Make Room Seconds and the Defaults (Approach fragment) as it applies.*

Its windows match **Warp Target Name** (`UPCTarget`) and **Approach Target Name** (`Target`) and fall back to its **Defaults**, which the style's Approach fragment writes. Without a Targeting component it still turns attacks as Attack Facing says and steers nothing.

</details>

<details>
<summary>The demo</summary>

- `AM_UPC_Unarmed_Combo` carries an Approach Or Move Window on every punch (glides to an enemy within 4 m, else steps 40 to 65 cm); `AM_UPC_Sword_Combo` a UPC Skew Warp window per hit; `AM_UPC_Unarmed_Strike_Dash` a UPC Gap Closer Warp.
- Freeflow steers Toward Target, Over Shoulder Distance Only with Attack Facing Aim, and Soulslike Off.

</details>

<details>
<summary>Steering in multiplayer (Multiplayer)</summary>

- A player's attack sends its target and the body's facing with the attack, and the server steers it the same way. Between attacks the server steers at the target the player last reported.
- **Steering Mode**, **Attack Facing** and the Targeting Config do not replicate. Set Steering Mode and the config on every machine (another player's view stops an attack where the server did only under the same values) and Attack Facing on the server and the player's machine; a style's fragments on Every Machine do both. The server turns the body only when its own Attack Facing says to, then takes the facing the player sent.
- Keep Distance runs on the server, the player's machine and the copies others show, and the server sends the copies the attack's target, so against a still target all stop in one place. Against a target moving along the attack line, stops differ by its speed over a round trip.
- An attack whose start reaches the server late, after a lost packet, starts the server's glide late, and the player can see one correction toward it.
- A move's own Stop Distance is read on the player's machine and the server. Another player's view of the character stops that attack at the distance -1 would give and follows the server's position updates.
- **Make Room**: the player's machine predicts the step back with the attack, and the server works out its own by the same rule. While the step runs, the character base's **UPC Character Movement** has the server take the player's stepped position, so an attack reaching the server late does not pull the player back toward the enemy. Make Room Seconds does not replicate; the style's Approach fragment on Every Machine sets it on both.

</details>

<details>
<summary>C++</summary>

- `UUPCAttackApproachComponent` subclasses `UUPCApproachComponent` and turns `KeepDistance` on. It answers the drawn weapon's Attack Stop Distance through `GetFallbackStopDistance()` (read through `IUPCAttackReachProvider`, which the equipment manager implements) and the Targeting component's candidates through `GatherKeepDistanceBodies()`.
- An action graph node's ability pins its attack through `IUPCActionSteeringProvider::PinAttack`, handing it the move's Stop Distance, Make Room Seconds and turn to the stick in `FUPCAttackPinOptions`, and lets it go through `ReleaseAttackPin`; the ability finds the component with `FindComponentByInterface`.
- `ComputeWarpTransform` is a `BlueprintNativeEvent` (`ComputeWarpTransform_Implementation(AActor* Target)`).
- The Approach Or Move Window answers the approach's `GetMoveWithoutTarget(FVector&, float&)`; a window subclass of your own can answer it the same way.

</details>

<details>
<summary>Troubleshooting (Advanced)</summary>

**When an attack does not steer**

| Symptom | Cause |
| --- | --- |
| No turn and no glide. | Steering is Off, the config picks no target, the attack plays from an ability rather than an action graph node, or the window's name differs from the component's. |
| A turn but no glide. | The target stands beyond Max Approach Distance, or the window's Mode is Face Only. |
| A root motion attack overshoots or spins. | The warp is the engine's Skew Warp, its name is not `UPCTarget`, or the character has no Motion Warping component. |
| It stops too far away. | The move's **Stop Distance**, a weapon's **Attack Stop Distance** or a window's **Stop Distance Override** exceeds the style's Stop Distance. |
| A short move beside a long weapon backs off and misses, such as a shield bash beside a sword. | The move takes the weapon's Attack Stop Distance; set the move's own **Stop Distance** on its Play Montage node. |
| It slides into the enemy. | The enemy's UPC Targetable is missing or off, its capsule lets characters through, or the character has no Targeting Config. |
| A Distance Only dash plays its own travel. | Its warp is a UPC Skew Warp, or no enemy stands on the body's facing line. |

</details>

---

Previous page: [Targeting](https://rigbak.com/docs/universal-player-combat/targeting). Next page: [Camera](https://rigbak.com/docs/universal-player-combat/camera)
