# 7. Combat Feel Pitfalls Part of [[Combat Feel and Hit Feedback]]. Prev: [[6. Worked Example Three-Hit Melee]]. ## Leftover Animator triggers `Attack` and `Hit` are consumed by a transition, but only if that transition runs. A death, a forced `CrossFade`, or a failed condition leaves the trigger set, and the next time you *can* transition you get a surprise swing. Reset triggers when leaving combat, on hit-react, and on death. ## One swing, many ticks Causes, in the order you will hit them: 1. Hitbox left enabled into recovery. 2. `OnTriggerEnter` plus a query both applying damage. 3. `attackInstanceId` minted once in `Awake` instead of in `Activate`. 4. Two hitbox colliders on the same weapon, both live. 5. The movement capsule is also a hurtbox, and the blade overlaps it *and* the child hurtbox (if you forgot the matrix, you can even hit yourself). Fix the pipeline, not the health bar. ## `OnTriggerEnter` on the enable frame If the blade is already inside the hurtbox when you enable it, there is no enter event. Use the active-window overlap query in [[3. Hitboxes and Hurtboxes]]. ## Animation events skipped by blends `CrossFade` / a long transition can start a clip *past* the `Anim_HitboxOn` time, so the box never turns on (or never turns off). Keep combat blends short, plant a StateMachineBehaviour fallback, or also gate the box on a state tag + normalized time. Details in [[6.Animation Events Reliable Patterns]]. ## `Time.timeScale` leaks Always restore in `finally`. Cancel with `destroyCancellationToken`. Do not time the freeze with `WaitForSeconds` or `Awaitable.WaitForSecondsAsync` (both scaled). Do not use a global freeze for a hit that can land on 20 enemies in one frame - switch to a local `Animator.speed` clock. Setting `timeScale` to 0 is a pause, not a hit-stop; at 0, `FixedUpdate` stops (official docs). Never set `timeScale` from Editor code and forget it: the Editor itself will feel paused. If you also scale `fixedDeltaTime` (the official slow-mo sample that keeps *real-time* physics), restore the saved value, not `0.02f` assumed. Designers change the project default. ## Input buffers on scaled time A combo buffer or dodge cooldown that uses `Time.time` during hit-stop will stall. Use `Time.unscaledTime` for input forgiveness; use scaled time for movement that should freeze. ## Audio pitching and music A global freeze can duck pitch on playing sources. Test with your mixer. The adaptive score in [[Music Mood Mixer]] should not hitch for 60 ms if you can avoid it - keep music sources on a path you have tested, or keep hit-stop short. ## Impulse on a VR rig Do not shake tracked eye cameras on Quest. See [[Cinemachine 3]] part 7 and [[Meta Quest 2]]. Juice the weapon, the enemy, the off-HMD UI - not the visor. ## `Renderer.material` on a crowd `material` instantiates. For many victims, use a `MaterialPropertyBlock` or a shader keyword. One dummy is fine. ## Knockback versus controllers Adding force to a `CharacterController` without an accumulated external velocity does nothing visible. Fighting a NavMeshAgent without `Warp` leaves the agent snapping back. Hook the motor you actually shipped ([[Character Controllers]], [[NavMesh in Unity 6 (AI Navigation 2.x)]]). ## Networking A client-side overlap is not authority. Confirm hits where [[Multiplayer with Netcode for GameObjects]] says they are confirmed. ## Tuning without a record If you cannot say "the cancel opens at 12 frames, i-frames are 8, hit-stop is 50 ms," you are guessing. Record Play Mode or count `normalizedTime`. Feel is a measurement with an aesthetic on top. ## Sources - `Time.timeScale` (6000.5): https://docs.unity3d.com/6000.5/Documentation/ScriptReference/Time-timeScale.html - [[6.Animation Events Reliable Patterns]] - [[3. Layers Matrix and Queries]]