Fighting Game · Features

Combat Systems, Defensive Options & Game Feel

A focused page within the Fighting Game Features documentation. The full map and every sibling page live in the Features hub.

7sections12 minread1diagram1table

On this page
flowchart LR Input[Player input frame] --> Ruleset[Ruleset legality and motion grammar] Ruleset --> Ability[Offense defense tag or assist ability] Ability --> Authority[Deterministic cost timing target and hit validation] Authority --> State[Confirmed combat state] State --> Feel[Hitstop shake slow motion tint audio and VFX] State --> Replay[Rollback replay and frame-data evidence] Authority --> Refusal[Illegal late unavailable or interrupted feedback]

The model separates authoritative combat from game-feel presentation. A cue may predict or dramatize an effect, but only confirmed deterministic state advances damage, meter, position, round, or replay truth.

This is the product-side view of the moment-to-moment fight: what a player actually does with the sticks and buttons, what defensive vocabulary the game hands them, and why a hit feels like Mortal Kombat in one match and like Street Fighter 6 in the next. The companion architecture page, ../architecture/combat-system-gas-frame-data-and-determinism.md, explains how the engine stays frame-deterministic enough to roll back and re-simulate; this page stays on the player's side of the screen and inventories the offensive systems, the defensive options library, and the game-feel layer as features, while pointing at the exact C++ and balance data that back each one.

The throughline is V2's whole reason for existing: per-ruleset feel from one shared combat core. A single fighter actor can be re-skinned into a 2D motion-input duelist, a Tekken juggle machine, a Soul Calibur weapon master, an MMA grappler, or a WWE worker — not by swapping engines, but by changing which attributes a move touches, which defensive options the ruleset enables, and which hitstop/shake curve plays on impact. Almost all of this is real, tested Unreal C++ under V2/ue/Source/V2Combat and V2/ue/Source/V2Gameplay, tuned by CSVs under V2/balance/feel/ and V2/balance/data/. For the full mode taxonomy, roster, and the rest of the scope this slots into, start at the feature hub: ../V2_features.md.

What ships, honestly#

The combat logic is substantive and broadly tested. The offensive and defensive resolution lives in UV2CombatResolver (V2Combat/Public/V2CombatResolver.h, an 823-line UBlueprintFunctionLibrary) plus a family of stateful UActorComponents — UV2ComboCounterComponent, UV2JuggleStateComponent, UV2BlockstringStateComponent — and the real per-call math sits in V2Combat/Private/V2CombatTypes.cpp, which is ~24,300 lines of domain logic (the matching header is ~15,800). Game feel is a real, CSV-driven catalog. The suite under V2/ue/Source/V2Tests carries 407 *.spec.cpp automation specs, including an 8,300-line Automation/Combat.Module.spec.cpp that exercises the resolver evaluators and combat components directly, plus dedicated Combat/GameFeelTuning.spec.cpp and Gameplay/CameraShake.spec.cpp suites.

Three honest qualifications. First, the resolver's evaluators are pure deterministic functions — each public Evaluate* call forwards to a Request.Evaluate() that checks windows and returns a result with a fail-loud reason tag. They compute the right answer; wiring them into live abilities, input, and animation is the GAS + sim-world job covered in the architecture companion. Second, the defensive options are opt-in per ruleset: every config struct (FV2CombatParryRulesetConfig, …) defaults to bEnabled = false, so the library exists in full but which family a given ruleset turns on is data, not a guarantee that all of them are live at once. Third, V2/balance/data/frame-data.csv is a 4-move sample that demonstrates the column schema, not a shipped frame database — the authoritative per-move numbers live in UV2MoveFrameData data assets. And as the architecture page flags, the editor-time validator that would forbid a designer from shipping a move with no property data is planned, not enforced. There are no .uasset binaries in the repo; this is a logic-and-data skeleton.

Offensive systems — the layered attack vocabulary#

V2 combat is layered, and the layers activate per ruleset. A player in an MK match never touches the 8-way-run weapon layer; a Soul Calibur player never sees the Drive gauge. One actor carries all of them; the ruleset decides which are armed.

The universal spine every move shares#

Underneath every layer is a move contract. Each move is a UV2MoveFrameData asset (V2Combat/Public/V2MoveFrameData.h, ~1,300 lines) wrapping a small honest FV2FrameData of StartupFrames / ActiveFrames / RecoveryFrames / OnHitAdvantage / OnBlockAdvantage plus juggle scaling. The sample frame-data.csv shows the shape a designer reads — e.g. Heavy Launcher at 18 startup / 3 active / 29 recovery, +38 on hit, −14 on block, 92 damage — the classic "huge reward, deeply punishable" launcher profile, versus a Cross-Up Kick at 11/4/17, −3 on block (barely minus, a safe pressure tool). That on-block number is the entire mind-game economy of a fighting game expressed as one integer.

Every move also carries an attack-property bitmask, EV2CombatAttackProperty, with exactly the eight bits the genre needs — Low, Mid, High, Overhead, Crossup, AntiAir, OTG, Unblockable — so the defender's block check, the crossup/anti-air logic, and the training-mode overlays all read the same source of truth. Hits resolve through a deterministic sweep (UV2CombatResolver::ResolveFixedFrameSweep) and a trade resolver (ResolveTradeEvents) whose EV2CombatTradeResolutionKind distinguishes a clean SimultaneousDamage trade from a CounterHitPriority win or a GuardImpactClash — the difference between "you both got hit," "you got counter-hit for extra damage," and "your weapons rang off each other."

Strikes, juggles, and the combo economy#

The headline offensive feature is the combo, and V2 models it as an economy, not a fixed string. UV2ComboCounterComponent tracks the live hit count and, crucially, starter proration: RegisterProratedCollisionEvent scales the whole combo by the move that started it (EV2CombatStarterProrationProfile), so a light-starter combo deals less than the same route off a launcher — the reason a "confirm" matters more than raw button mashing. It also knows the difference between techable and untechable hits and resets the counter for the right reason (EV2ComboCounterResetReason: Tech, WakeUp, BlockedHit, DamageScalingReset).

The juggle layer — Tekken culture — lives in UV2JuggleStateComponent. It registers a launcher, caps the air string (MaxJuggleHits default 12), and applies per-ruleset juggle damage scaling (EvaluateJuggleDamageScale, keyed on EV2ShaktiRulesetId), so the same number of air hits bleeds value differently in Tekken than in MK. It owns the tornado/screw state (RegisterTornado, one use by default), wall splat (single by default, up to 3 in rulesets that allow multi-wall-splat via DoesRulesetAllowMultiWallSplat), and stage transitions that move the fight to a new floor. Tekken's launcher kinematics are real numbers on the move asset — TekkenLaunchImpulse = (160, 0, 520), a 12-hit juggle cap, 0.92 starter scaling.

Pressure that doesn't combo is the blockstring, modelled by UV2BlockstringStateComponent: it accumulates blockstun, tracks the gap between blocked hits, and reports IsTrueBlockstring() — i.e. whether the defender is genuinely locked down or has a frame to escape. That single boolean is what separates "respect this string" from "mash a reversal here."

Supers, finishers, and counter-hit drama#

The spectacle layer is real too. UV2CombatResolver::BuildDefaultSuperMoveGrammar seeds the cinematic super catalog — SF Critical Art (Level 3), MK X-Ray, MK Fatal Blow, Tekken Rage Art, SC Critical Edge — each entry naming its cinematic sequence and slow-mo cue, and EvaluateSuperMoveActivation gates activation on the meter rules. These pair with the 21 typed GAS ability subclasses on the gameplay side (the nine UV2_Ability_* ruleset super variants — including the MK Fatal Blow's real "only under 30% health" gate) detailed in the architecture companion. Counter-hit and "big moment" emphasis are first-class evaluators: EvaluateCounterHit, MK's EvaluateKrushingBlow (a hidden-condition alt-hit with its own cinematic freeze), EvaluateWakeupAction for okizeme, and EvaluateComebackState for the low-HP rally. Tekken's full kit — Heat activation and Heat moves, Rage activation/Rage Art, Ki Charge, Power Crush armor, and stance switching — each has a dedicated resolver entry. Beyond striking, the same resolver carries the grapple/MMA/wrestling offensive surfaces (takedowns, ground-position transitions, ground-and-pound, submissions, pins, kickouts, object usage, and stipulation logic) and the Def Jam environmental finishers, Blazin' meter, and crowd momentum — each a real Evaluate* function, not a placeholder.

The defensive options library#

V2's standout system is that it doesn't ship one defense; it ships the genre's entire defensive vocabulary as a toggleable library, so each match plays in the defensive grammar of the family it's emulating. Every option is a real evaluator on UV2CombatResolver whose request struct enforces a timing window and returns a fail-loud reason tag — these are not stubs, they compute correctness and honestly reject bad input.

One resolver, many defenses#

Defensive option (lineage) Resolver entry What the player gets
Parry (3rd Strike) EvaluateParry Time the block on the hit-frame: no chip, attacker stunned, defender gains frames + meter
Just Defend (KOF / Garou) EvaluateJustDefend Perfect-frame block for 0 chip
Instant Block (Tekken) EvaluateInstantBlock Release-and-repress guard on first contact → reduced blockstun
Faultless Defense (Guilty Gear) EvaluateFaultlessDefense Meter-cost air/ground guard with extra pushback and chip mitigation
Push Block / Advancing Guard (MvC) EvaluatePushBlock Shove the attacker out of pressure at meter cost
Burst (Guilty Gear) EvaluateBurst One-shot (or burst-meter) panic button out of a combo
Counter Assault / Alpha Counter EvaluateCounterAssault Special out of blockstun to reverse the turn
Guard Cancel (KOF) EvaluateGuardCancel Cancel block into a roll/blowback at meter cost
Negative Penalty (KOF) EvaluateNegativePenalty Anti-turtle inactivity penalty
Hold / Strike / Throw triangle (DOA) EvaluateHoldStrikeThrow RPS reversal layer (also drives WWE clinch)
Super-armor / invuln frames EvaluateSuperDefenseFrames Armored or invincible windows on reversals
Guard Impact (Soul Calibur) EvaluateSoulCaliburGuardImpact Repel / Deflect / Resist weapon deflection
Reversal Edge (SCVI) EvaluateSoulCaliburReversalEdge Cinematic RPS clash at meter cost

The EvaluateParry implementation is representative of the whole library: it clamps the parry window (default 6 frames), computes the input-lead frames against the incoming hit, and only on a IsInputWithinParryWindow() success returns bParried = true, bNegatesChipDamage = true, the attacker's stun (default 18 frames), the defender's frame advantage (default +12), and a meter reward (default 10) — otherwise it returns one of a dozen precise rejection tags (Parry.Rejected.NotInWindow, …RulesetDisabled, …). Instant Block similarly verifies the release-then-repress ordering happened on first contact before granting reduced blockstun; Burst checks one-shot availability or burst-meter cost before it fires. The standard block path is split into its own trio — EvaluateBlock, EvaluateBlockChipDamage, EvaluateBlockPushback — so chip (which, per the architecture page, converts to SF6-style recoverable white health) and pushback are tunable independently of the block decision.

Throws, techs, and per-ruleset toggling#

The throw game is a defensive surface too: EvaluateThrowAttempt, EvaluateThrowTech, EvaluateCounterThrow, and EvaluateCrouchTech give the defender the genre's full anti-grab toolkit. SF6's Drive system rounds out the defensive menu on the gameplay side — EV2DriveGaugeAction carries DriveImpact, DriveParry, DriveRush, ODSpecial, and DriveReversal with real per-action costs (DriveReversalCost = 2.0), and the punishing Burnout state is modelled by FV2DriveBurnoutStateResult (doubled BurnoutChipDamageScalar).

What ties the library to the "per-ruleset feel" promise is that UV2CombatRulesetData carries a config struct for every optionParryConfig, JustDefendConfig, InstantBlockConfig, FaultlessDefenseConfig, PushBlockConfig, BurstConfig, CounterAssaultConfig, GuardCancelConfig, NegativePenaltyConfig, HoldStrikeThrowConfig — each with its own enable flag, window timings, costs, and per-fighter overrides (FV2CombatParryFighterWindow). A ruleset enables exactly the defenses that belong to its lineage; the rest stay dormant. Which rulesets light up which options, and how that meshes with tag-team assists and the Kameo partner system, is covered in ./rulesets-tag-and-kameo.md.

Game feel — hitstop, shake, slow-mo, tint#

A correct hit that feels limp is a failed feature. V2 centralizes game feel into one tunable catalog — UV2CombatRulesetData::BuildDefaultGameFeelCatalog() returns an FV2GameFeelCatalog (id GameFeel.Catalog.V2) — so every ruleset can hit differently from one shared system, and every value is a CSV a designer edits without a recompile.

Hitstop and hitlag — the "weight" of a hit#

Hitstop is the brief freeze on impact that sells force. The catalog's HitstopPolicy splits attacker and defender hitstop, adds a defender-only hitlag window, a counter-hit bonus (2–3 frames), a configurable block hitstop (default 4), and a crush/punish bonus — all authored per ruleset and per damage tier in V2/balance/feel/hitstop_curves.csv. The shipped rows make the identity differences concrete: MK.Heavy freezes 8 attacker / 10 defender / 8 hitlag with a 6-frame Sakkin, MK.Launcher goes to 9 / 12 / 9, while SF6.Heavy stays conservative at 6 / 7 / 5 and SC.WeaponClash rings at 7 / 9 / 6 — MK's "juicy and heavy," SF6's "crisp and quick," Soul Calibur's "steel-on-steel." Two columns matter for netplay: every row sets rollback_budget_excluded = true and resim_cosmetic_suppressed = true, which is why a heavy hit's freeze never blows the rollback budget and never re-triggers during re-simulation (the architecture page traces this through the sim world's if (HitstopFrames > 0) --HitstopFrames; else ++AnimationFrame;).

Camera shake, slow-mo, freeze, and tint#

V2/balance/feel/camera_shake_curves.csv defines 9 shake curves scaling from Small (base 0.20, reduced-motion ceiling 0.12) through Heavy, BoneShatter, WeaponClash, and Explosion up to KO (1.00 / 0.35) and Fatality (1.20 / 0.35) — and GameFeelTuning.spec.cpp asserts the ordering must hold (Fatality stronger than KO) and that every reduced-motion ceiling sits below its base intensity, so the accessibility clamp can never be louder than the default. At runtime UV2CameraShakeLibrary folds Perlin / spring / directional-impact patterns into one evaluation clamped to a 50-unit / 10-degree maximum.

slowmo_freeze_curves.csv tunes the dramatic pauses: a round-clinching KO slow-mo at 48 frames with a camera ride, a finisher freeze-frame at 18 frames with zoom and tint, Soul Calibur's Reversal-Edge clash at 18, MK's mid-combo launcher emphasis at 10, and ruleset-specific KO treatments (WWE broadcast KO at 54, UFC's realistic flash KO at 30) — every row exposing an accessibility_opt_out. Screen-state tints (counter-hit flash, low-HP vignette, comeback aura, and power-state tints for Devil / Soul Charge / Heat / Blazin' / Burnout) and the photo-mode tone curves round out the visual layer.

Tunability and accessibility#

The catalog's FV2GameFeelTunabilitySpec points at the exact CSV paths (V2/balance/feel/hitstop_curves.csv, …/camera_shake_curves.csv, …/slowmo_freeze_curves.csv, …/photo_mode_tone_curves.csv) and names an editor utility widget (EUW_GameFeelMovePreview) for previewing feel per move — and the spec adversarially rejects a catalog whose tunability path doesn't point at the canonical balance CSVs. Because the reduced-motion ceilings are the same data the accessibility surfaces read, "tone down screen shake" is not a separate code path; it's a clamp baked into the shared feel system. The full accessibility surface is in the UI/HUD/accessibility feature page set.

Control schemes and the accessibility ramp#

The same combat core serves both the execution purist and the newcomer. V2 ships Classic (full motion-input fidelity), Modern (assisted single-button specials, ranked-eligible), Dynamic (fully assisted, ranked-locked), and Easy combo/Fatality options. The balance tradeoff is real data, not a slogan: V2/balance/data/modern-vs-classic-balance.csv pins Modern's default damage scalar at 0.80 against Classic's 1.00, and already records a per-fighter tuning exception — Fighter.King Modern bumped to 0.82 because simplified grappler routes underperform Classic beyond the launch parity band. That's the control-scheme balance loop expressed as a tracked, designer-owned tuning row.

How it connects#

Combat is the hub the rest of V2 reads. The frame data, attack properties, and input-buffer windows feed the animation and motion-matching layer; the deterministic hit resolution and the tag-team/assist handshakes feed netplay; the combo, juggle, and blockstring components plus the golden-replay corpus feed the training, trials, and replay surfaces in ./mode-catalog-training-and-replay.md; and the per-ruleset feel definitions, defensive toggles, tag mechanics, and Kameo partner system are inventoried in ./rulesets-tag-and-kameo.md. For the engine-side treatment of every system named here — the GAS authority/sim-world split, the attribute sets, the gameplay-effect appliers, the determinism guardrails, and the state-hash desync signal — read the architecture companion, ../architecture/combat-system-gas-frame-data-and-determinism.md.