Knockback don't work

Hi everyone, I’m implementing knockback in a 2D game in Unity, but I’m having a physics problem where the player and enemies are launched upwards instead of backwards. I’ve already made several changes and checked the animations, I’ve also disabled all movement updates during knockback and increased the force. Does anyone know what the problem might be? Here’s the knockback code and a video showing what’s happening.

using System;
using System.Collections;
using UnityEngine;

namespace Greentale {
    public class KnockBack : MonoBehaviour {
        [SerializeField] private float _knockbackDuration = 0.25f;
        [SerializeField] private float _horizontalForce = 15f;
        [SerializeField] private float _verticalPop = 5f;
        private float _normalGravityScale;

        [Header("Feel")]
        [SerializeField] private AnimationCurve _decayCurve = AnimationCurve.EaseInOut(0, 1, 1, 0);

        public bool IsBeingKnockedBack {get; private set;}
        private Rigidbody2D _rigidBody;
        private WaitForFixedUpdate waitFixed;
        private Coroutine knockbackCoroutine;
        public Action OnKnockbackStart; 
        public Action OnKnockbackEnd;


        private void Awake() {
            _rigidBody = GetComponent<Rigidbody2D>();
            _normalGravityScale = _rigidBody.gravityScale;
            waitFixed = new();
        }
        public void CallKnockback(Vector2 damageSourcePosition) {

            float horizontal = transform.position.x - damageSourcePosition.x;
            Vector2 knockDir = new Vector2(Mathf.Sign(horizontal), 0f);

            if (knockbackCoroutine != null) {
                StopCoroutine(knockbackCoroutine);
            }
            knockbackCoroutine = StartCoroutine(KnockBackAction(knockDir));
        }

        public IEnumerator KnockBackAction(Vector2 direction) {
            IsBeingKnockedBack = true;
            OnKnockbackStart?.Invoke();

            _rigidBody.gravityScale = _normalGravityScale;
            _rigidBody.velocity = Vector2.zero;

            float elapsed = 0f;
            float startHorizontalVelocity = direction.x * _horizontalForce;

            _rigidBody.velocity = new Vector2(startHorizontalVelocity, _verticalPop);
            Debug.Log($"[KNOCKBACK INÍCIO] Velocidade aplicada: {_rigidBody.velocity}");

            while (elapsed < _knockbackDuration) {
                elapsed += Time.fixedDeltaTime;
                float t = elapsed / _knockbackDuration;

                float currentHorizontal = startHorizontalVelocity * _decayCurve.Evaluate(t);
                _rigidBody.velocity = new Vector2(currentHorizontal, _rigidBody.velocity.y);
                Debug.Log($"[KNOCKBACK RODANDO] Tempo: {t:F2} | Vel X Alvo: {currentHorizontal:F2} | Vel X Real do Rigidbody: {_rigidBody.velocity.x:F2}");


                yield return waitFixed;
            }

            _rigidBody.velocity = new Vector2(0f, _rigidBody.velocity.y);

            IsBeingKnockedBack = false;
            OnKnockbackEnd?.Invoke();
            Debug.Log("[KNOCKBACK FIM]");
        }

    }
}

It would be useful if you included what debugging you’ve done and what the output was as it’s obviously impossible to do this simply by looking at code.

If it’s moving up then you should be outputting the “horizontal” and “knockDir” you calculated (which shouldn’t be using Transforms BTW, use the Rigidbody2D positions as those are the real positions of the bodies).

In the end, a Dynamic body will move with the linear-velocity you set and the only thing that will change it will be collisions, gravity, forces you apply and damping so it should be pretty easy determine which is causing it.

You can see the velocity in the inspector in the “Info” panel. You can also turn-on gizmos in the project settings to show contact points/normals etc.

While this is in progress knocking you back, are you disabling the normal control inputs?

Usually during special movements (knockback, dash, roll, etc.) you inhibit or suspend the normal controller so you can have exact control of the knockback’s movement.

Either way, it just sounds like you wrote a bug… and that means… time to start debugging!

By debugging you can find out exactly what your program is doing so you can fix it.

Use the above techniques to get the information you need in order to reason about what the problem is.

You can also use Debug.Log(...); statements to find out if any of your code is even running. Don’t assume it is.

Once you understand what the problem is, you may begin to reason about a solution to the problem.

Remember with Unity the code is only a tiny fraction of the problem space. Everything asset- and scene- wise must also be set up correctly to match the associated code and its assumptions.

Sorry, I wrote the post before leaving, and I didn’t take any screenshots of the console.

Here is the speed it tells me.

the enemy’s rigidbody while in knockback

I also checked the enemy’s state machine code, but it uses their movement script, and it still passes the check in update and fixedUpdate.

protected void Update() {
            if (_knockback != null && _knockback.IsBeingKnockedBack) {
                return;
            }
            UpdateTimers();
            HandleInput();
            CollisionChecks();
            CheckDirectionToFace();
            JumpCheck();
            ApplyGravity();
        }

        protected virtual void FixedUpdate() {
            if (_knockback != null && _knockback.IsBeingKnockedBack) {
                return;
            }
            Run(1);
        }

I checked if there might be another script stopping or overwriting the movement, but so far I haven’t found anything. I’ll try debugging other scripts to see if I can find something that’s altering the speed.

What script actually moves your player normally? That’s the one you have to worry about stopping, otherwise the very next frame will “wipe out” the knockback effect.

You’re almost certainly fighting between:

  • the physics system
  • your normal “make the player move” code
  • this knockback code
  • (and possibly even something else)

Debug, debug, debug, find out what is happening by logging and isolating.

Hi everyone, after some testing, I discovered that the problem is with the rootmotion in Animator. I’ll adjust the animations to fix it. Thanks for all the help.