Enemy jiggles when knocked back

Hi! I have a problem with my 2D mobile game. There is a SeekPlayer() function that as it states - makes the enemy seek the player. There is also FollowPlayer() (when enemy finds the player, it starts chasing him). However when the enemy hits (collides) with the player, the enemy gets knocked back. However it makes the enemy jiggle (or vibrate - however u want to call it). I know that it’s because 2 forces are applied at the same time (FollowPlayer() is working simultaneously with the Knockback function). Here is the code of 2 functions that make it work.

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;

public class HealthManager : MonoBehaviour
{
    public Image healthBar;
    public float healthAmount = 100f;

    private Rigidbody2D enemyRb;
    private Rigidbody2D bossRb;

    void Start()
    {
        enemyRb = GameObject.FindGameObjectWithTag("enemy").GetComponent<Rigidbody2D>();
        bossRb = GameObject.FindGameObjectWithTag("Demon Wolf").GetComponent<Rigidbody2D>();
    }

    // Update is called once per frame
    void Update()
    {

    }

    // Obsługuje kolizje 2D
    private void OnCollisionEnter2D(Collision2D collision)
    {
        // Używamy 'collision.collider' do sprawdzenia kolizji z obiektem przeciwnika
        if (collision.gameObject.tag == "enemy")
        {
            NormalHealthLoss();
            PushEnemyBack(collision);
        }

        else if (collision.gameObject.tag == "Demon Wolf")
        {
            BossHealthLoss();
            PushBossBack(collision);
        }
    }

    void NormalHealthLoss()
    {
        float damage = 10f;
        healthAmount -= damage;

        // Ustawienie fillAmount paska zdrowia
        healthBar.fillAmount = healthAmount / 100f;

        if (healthAmount <= 0)
        {
            YouLost();
        }
    }

    void BossHealthLoss()
    {
        float damage = 20f;
        healthAmount -= damage;

        healthBar.fillAmount = healthAmount / 100f;

        if (healthAmount <= 0)
        {
            YouLost();
        }
    }

    void YouLost()
    {
        
    }

    void PushEnemyBack(Collision2D collision)
    {
        Vector2 pushDirection = collision.transform.position - transform.position;

        pushDirection.Normalize();

        if (enemyRb != null)
        {
            float pushStrength = 5f;
            enemyRb.AddForce(pushDirection * pushStrength, ForceMode2D.Impulse);

            enemyRb.drag = 0.6f;
        }
    }

    void PushBossBack(Collision2D collision)
    {
        Vector2 pushDirection = collision.transform.position - transform.position;

        pushDirection.Normalize();

        if (bossRb != null)
        {
            float pushStrength = 5f;

            bossRb.AddForce(pushDirection * pushStrength, ForceMode2D.Impulse);

            bossRb.drag = 0.7f;
        }
    }
}

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UIElements;

public class EnemyAI : MonoBehaviour
{
    public Transform Player;

    public float speed = 4f;
    private float followRange = 10.0f;
    public float seekRadius = 10.0f;
    // boole powpierdalac zeby nie scinalo enemy kurwa mac
    float mapMinY = -30f;
    float mapMaxY = 30f;
    float mapMaxX = 30;
    float mapMinX = -30;

    Vector2 targetPosition;

    bool IsPlayerVisible;
    bool isSeeking = false;

    void Start()
    {
        
    }

    // Update is called once per frame
    void Update()
    {
        float distance = Vector2.Distance(transform.position, Player.position);

        if (distance > followRange)
        {
            IsPlayerVisible = false;
            SeekPlayer();
        }

        else if (distance <= followRange)
        {
            IsPlayerVisible = true;
            FollowPlayer();
        }

    }


    void SeekPlayer()
    {
        // Wciąż musimy "szukać" w danym promieniu, nawet jeśli gracz nie jest w zasięgu.
        if (!isSeeking)
        {
            // Wygeneruj losowy punkt w promieniu seekRadius
            Vector2 randomDirection = new Vector2(
                Random.Range(-seekRadius, seekRadius),
                Random.Range(-seekRadius, seekRadius));

            // Ustaw nowy cel w zależności od kierunku
            targetPosition = (Vector2)transform.position + randomDirection;

            // Upewnij się, że cel jest w granicach mapy
            if (!IsWithinMapBounds(targetPosition))
            {
                // Jeśli cel wykracza poza mapę, ustaw go na dozwolonym obszarze
                targetPosition = new Vector2(Mathf.Clamp(targetPosition.x, mapMinX, mapMaxX), Mathf.Clamp(targetPosition.y, mapMinY, mapMaxY));
            }

            isSeeking = true;
        }

        // Ruch w stronę losowego celu
        if (Vector2.Distance(transform.position, targetPosition) > 0.5f) // Jeśli jesteśmy dalej niż 0.5 jednostki
        {
            transform.position = Vector2.MoveTowards(transform.position, targetPosition, speed * Time.deltaTime);
        }
        else
        {
            // Kiedy dotrzemy do celu, zresetuj isSeeking, żeby znowu poszukać nowego punktu
            isSeeking = false;
        }
    }
    void FollowPlayer()
    {
        if (IsPlayerVisible)
        {
            transform.position = Vector2.MoveTowards(transform.position, Player.position, speed * Time.deltaTime);
        }
    }


    bool IsWithinMapBounds(Vector2 position)
    {
        return position.x >= mapMinX && position.x <= mapMaxX &&
               position.y >= mapMinY && position.y <= mapMaxY;
    }

}

You don’t drive a Rigidbody2D by setting the Transform. You use the Rigidbody2D API to cause movement and it writes its position/rotation to the Transform. You’re completely bypassing physics by doing this. Also, physics doesn’t run per-frame by default, it runs during the FixedUpdate at 50Hz.

There’s plenty of tutorials around showing you the different methods on how to drive a Rigidbody2D with velocity, forces etc you might want to look into.

If you’re doing two opposing things (follow & knockback) then you need to deal with the logic of that in script.

I don’t know if i understand this part correctly but you mean that i should put the rigidbody2d mechanics in FixedUpdate and not in Update? Also, what kind of tutorial that would suite that exact topic would you recommend? Or maybe not even a single tutorial but a whole yt channel? thanks in advance <3

This forum isn’t best suited to show you how to use the basics of the physics system which is why I recommended following some starter tutorials based upon the fact that given what you’re doing, it’s not following the basics of physics movement.

Possibly but modifying the Transform isn’t “Rigidbody2D mechanics”. Setting the Transform isn’t physics movement, it’s saying when the physics system runs, instantly teleport the Rigidbody2D to this position. You should never do this.

How to move Rigidbody2D, basic character movement etc etc. Before trying to implement specific character dynamics like knockback, you need to get the basics down on how to use stuff. I’d say search for “Unity Rigidbody2D Movement” on Google/YouTube and ignore any that show you writing to the Transform. There’s also “knockback” tutorials on there too like this one. :slight_smile:

Thank you! I’ll go deeper into that topic and then try to fix my problem. I really appreciate your response

1 Like

No problem. Sorry I didn’t go into more detail but those video tutorials would do a far better job of explaining this stuff over my rambling text here on the forums. :wink:

btw, here’a nice simple one for the basics: https://youtu.be/w9NmPShzPpE?si=y-2jnG5IfHypC4wT

1 Like