Player is taking damage when not touching enemy

I’m trying to code an enemy the will deal damage to the player when it touches the player but it deals damage no matter what or where you are in comparison to the enemy (It seems to deal damage when the distance between the player and enemy changes). I have no idea why it isn’t working properly.

Here is the code for my player controller

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

public class PlayerControl : MonoBehaviour
{
    [Header("Horizontal Movement Settings")]
    [SerializeField] private float walkSpeed = 1f;
    [Space(5)]

    [Header("Advanced Movement Settings")]
    [SerializeField] private float dashSpeed;
    [SerializeField] private float dashTime;
    [SerializeField] private float dashCooldown;
    [Space(5)]

    [Header("Advanced Jump Settings")]
    private float jumpBufferCounter = 0f;  
    [SerializeField] private float jumpBufferFrames;
    private float coyoteTimeCounter = 0f;  
    [SerializeField] private float coyoteTime;
    private int airJumpCounter = 0;
    [SerializeField] int maxAirJumps;
    [Space(5)]

    [Header("Ground Check Settings")]
    [SerializeField] private float jumpHeight = 45f; 
    [SerializeField] private Transform groundCheckPoint;
    [SerializeField] private float groundCheckY = 0.2f;
    [SerializeField] private float groundCheckx = 0.5f;
    [SerializeField] private LayerMask whatIsGround;
    [Space(5)]

    [Header("Attacking")]
    [SerializeField] float timeBetweenAttack;
    float timeSinceAttack; 
    bool attack = false;
    [SerializeField] float damage;
    [SerializeField] Transform SideAttackTransform;
    [SerializeField] Transform UpAttackTransform;
    [SerializeField] Transform DownAttackTransform;
    [SerializeField] Vector2 SideAttackArea;
    [SerializeField] Vector2 UpAttackArea;
    [SerializeField] Vector2 DownAttackArea;
    [SerializeField] LayerMask attackableLayer;
    [Space(5)]

    [Header("Health")]
    public int health;
    public int maxHealth;
    [Space(5)]

    [Header("Recoil")]
    [SerializeField] int recoilXSteps = 5;
    [SerializeField] int recoilYSteps = 5;
    [SerializeField] float recoilXSpeed = 100;
    [SerializeField] float recoilYSpeed = 100;
    int stepsXRecoiled;
    int stepsYRecoiled;

    public PlayerStatesList pState;
    public static PlayerControl Instance;
    private Rigidbody2D rb;
    Animator anim;
    private float xAxis, yAxis;
    private bool canDash = true;
    private bool dashed;
    private float gravity;

    public global::System.Single WalkSpeed { get => walkSpeed; set => walkSpeed = value; }

    private void Awake()
    {
        if(Instance != null && Instance != this)
        {
            Destroy(gameObject);
        }
        else
        {
            Instance = this;
        }
        Health = maxHealth;
    }

    void Start()
    {
        pState = GetComponent<PlayerStatesList>();

        rb = GetComponent<Rigidbody2D>();

        anim = GetComponent<Animator>();

        gravity = rb.gravityScale;
    }

    void OnDrawGizmosSelected()
    {
        // Draw a yellow cube at the transform position
        Gizmos.color = Color.red;
        Gizmos.DrawWireCube(SideAttackTransform.position, SideAttackArea);
        Gizmos.DrawWireCube(UpAttackTransform.position, UpAttackArea);
        Gizmos.DrawWireCube(DownAttackTransform.position, DownAttackArea);
    }

    // Update is called once per frame
    void Update()
    {
        UpdateJumpVariables();
        GetInputs();

        if (pState.dashing) return;
        Move();
        Jump();
        StartDash();
        Flip();
        Attack();
        Recoil();

        if (isTouchingEnemy)
        {
            TakeDamage(1);
        }
    }

    void GetInputs()
    {
        xAxis = Input.GetAxisRaw("Horizontal");
        yAxis = Input.GetAxisRaw("Vertical");        
        attack = Input.GetMouseButtonDown(0);
    }

    void Flip()
    {
        if (xAxis < 0)
        {
            transform.localScale = new Vector2(-Mathf.Abs(transform.localScale.x), transform.localScale.y);
            pState.lookingRight = false;
        }
        else if (xAxis > 0)
        {
            transform.localScale = new Vector2(Mathf.Abs(transform.localScale.x), transform.localScale.y);
            pState.lookingRight = true;
        }
    }

    private void Move()
    {
        rb.linearVelocity = new Vector2(walkSpeed * xAxis, rb.linearVelocity.y);
    }

    void StartDash()
    {
        if (Input.GetButtonDown("Dash") && canDash && !dashed)
        {
            StartCoroutine(Dash());
            dashed = true;
        }

        if (Grounded())
        {
            dashed = false;
        }
    }

    IEnumerator Dash()
    {
        canDash = false;
        pState.dashing = true;
        rb.gravityScale = 0;
        rb.linearVelocity = new Vector2(transform.localScale.x * dashSpeed, 0);
        yield return new WaitForSeconds(dashTime);
        rb.gravityScale = gravity;
        pState.dashing = false;
        yield return new WaitForSeconds(dashCooldown);
        canDash = true;
    }

    void Attack()
    {
        timeSinceAttack += Time.deltaTime;
        if (attack && timeSinceAttack >= timeBetweenAttack)
        {
            timeSinceAttack = 0;
            anim.SetTrigger("Attacking");

            if(yAxis <= 0 && Grounded())
            {
                Hit(SideAttackTransform, SideAttackArea, ref pState.recoilingX, recoilXSpeed);
            }
            else if(yAxis < 0)
            {
                Hit(UpAttackTransform, UpAttackArea, ref pState.recoilingY, recoilYSpeed);
            }
            else if(yAxis > 0 && !Grounded())
            {
                Hit(DownAttackTransform, DownAttackArea, ref pState.recoilingY, recoilYSpeed);
            }
        }
        else
        {
            anim.ResetTrigger("Attacking");
        }
    }

    private void Hit(Transform _attackTransform, Vector2 _attackArea, ref bool _recoilDir, float _recoilStrength)
    {
        Collider2D[] objectsToHit = Physics2D.OverlapBoxAll(_attackTransform.position, _attackArea, 0, attackableLayer);
        List<Enemy> hitEnemies = new List<Enemy>();

        if (objectsToHit.Length > 0)
        {
            Debug.Log("Hit");
            _recoilDir = true;
        }

        for (int i = 0; i < objectsToHit.Length; i++)
        {
            Enemy e = objectsToHit[i].GetComponent<Enemy>();
            if (e && !hitEnemies.Contains(e))
            {
                e.EnemyHit(damage, (transform.position - objectsToHit[i].transform.position).normalized, _recoilStrength);
                hitEnemies.Add(e);
            }
        }
    }

    void Recoil()
    {
        if (pState.recoilingX)
        {
            if (pState.lookingRight)
            {
                rb.linearVelocity = new Vector2 (-recoilXSpeed, 0);
            } 
            else
            {
                rb.linearVelocity = new Vector2 (recoilXSpeed, 0);
            }
        }

       if (pState.recoilingY)
       {
            if (yAxis < 0)
            {
                rb.gravityScale = 0;
                rb.linearVelocity = new Vector2 (rb.linearVelocity.x, recoilYSpeed);
            }
            else
            {
                rb.gravityScale = 0;
                rb.linearVelocity = new Vector2 (rb.linearVelocity.x, -recoilYSpeed);
            }
            airJumpCounter = 0;
       }
       else
       {
            rb.gravityScale = gravity;
       }

       //stop recoil
       if (pState.recoilingX && stepsXRecoiled < recoilXSteps)
       {
            stepsXRecoiled++;
       }
       else
       {
            StopRecoilX();
       }

       if (pState.recoilingY && stepsYRecoiled < recoilYSteps)
       {
            stepsYRecoiled++;
       }
       else
       {
            StopRecoilY();
       }

       if (Grounded())
       {
            StopRecoilY();
       }
    }

    void StopRecoilX()
    {
        stepsXRecoiled = 0;
        pState.recoilingX = false;
    }

    void StopRecoilY()
    {
        stepsYRecoiled = 0;
        pState.recoilingY = false;
    }

    public void TakeDamage(float _damage)
    {
        if (!pState.invincible)
        {
            Health -= Mathf.RoundToInt(_damage);
            StartCoroutine(StopTakingDamage());
        }
    }

    IEnumerator StopTakingDamage()
    {
        pState.invincible = true;
        yield return new WaitForSeconds(1f);
        pState.invincible = false;
    }

    private bool isTouchingEnemy = false;

private void OnTriggerEnter2D(Collider2D collision)
{
    if (collision.CompareTag("Enemy")) // Assuming enemies are tagged as "Enemy"
    {
        isTouchingEnemy = true;
        TakeDamage(1); // Decrease health by 1
    }
}

private void OnTriggerExit2D(Collider2D collision)
{
    if (collision.CompareTag("Enemy"))
    {
        isTouchingEnemy = false;
    }
}

    public int Health
    {
        get { return health; }
        set
        {
            if (health != value)
            {
                health = Mathf.Clamp(value, 0, maxHealth);
            }
        }
        
    }

    public bool Grounded()
    {
        if(Physics2D.Raycast(groundCheckPoint.position, Vector2.down, groundCheckY, whatIsGround) 
            || Physics2D.Raycast(groundCheckPoint.position + new Vector3(groundCheckx, 0, 0), Vector2.down, groundCheckY, whatIsGround)  
            || Physics2D.Raycast(groundCheckPoint.position + new Vector3(-groundCheckx, 0, 0), Vector2.down, groundCheckY, whatIsGround))
        {
            return true;
        }
        else
        {
            return false;
        }
    }

    void Jump()
    {
        if (!Input.GetButton("Jump") && rb.linearVelocity.y > 0)
        {
            rb.linearVelocity = new Vector2(rb.linearVelocity.x, 0);

            pState.jumping = false;
        }
        if (rb.linearVelocity.y <= 0)
        {
            pState.jumping = false;
        }
        if (!pState.jumping)
        {
            if (jumpBufferCounter > 0 && coyoteTimeCounter > 0)
            {
                rb.linearVelocity = new Vector3(rb.linearVelocity.x, jumpHeight);

                pState.jumping = true;
            }
            else if(!Grounded() && airJumpCounter < maxAirJumps && Input.GetButtonDown("Jump"))
            {
                pState.jumping = true;

                airJumpCounter++;

                rb.linearVelocity = new Vector3(rb.linearVelocity.x, jumpHeight);
            }
        }
        
    }

    void UpdateJumpVariables()
    {
        if (Grounded())
        {
            pState.jumping = false;
            coyoteTimeCounter = coyoteTime;
            airJumpCounter = 0;
        }
        else
        {
            coyoteTimeCounter -= Time.deltaTime;
        }

        if (Input.GetButtonDown("Jump"))
        {
            jumpBufferCounter = jumpBufferFrames;
        }
        else
        {
            jumpBufferCounter = jumpBufferCounter - Time.deltaTime * 10;
        }
    }
}

here is my code for the generic enemy

using UnityEngine;

public class Enemy : MonoBehaviour
{

    [SerializeField] protected float health;
    [SerializeField] protected float recoilLength;
    [SerializeField] protected float recoilFactor;
    [SerializeField] protected bool isRecoiling = false;

    [SerializeField] protected PlayerControl player;
    [SerializeField] protected float speed;
    
    [SerializeField] protected float damage;

    protected float recoilTimer;
    protected Rigidbody2D rb;

    // Start is called once before the first execution of Update after the MonoBehaviour is created
    protected virtual void Start()
    {

    }

    protected virtual void Awake()
    {
        rb = GetComponent<Rigidbody2D>();
        player = PlayerControl.Instance;
    }

    // Update is called once per frame
    protected virtual void Update()
    {
        if (health <= 0)
        {
            Destroy(gameObject);
        }
        if (isRecoiling)
        {
            if (recoilTimer < recoilLength)
            {
                recoilTimer += Time.deltaTime;
            }
            else
            {
                isRecoiling = false;
                recoilTimer = 0;
            }
        }
        
    }

    public virtual void EnemyHit(float _damageDone, Vector2 _hitDirection, float _hitForce)
    {
        health -= _damageDone;
        if (!isRecoiling)
        {
            rb.AddForce(-_hitForce * recoilFactor * _hitDirection);
            isRecoiling = true;
        }
    }

    protected void OnTriggerStay2D(Collider2D _other)
    {
        if(_other.CompareTag("Player") && !PlayerControl.Instance.pState.invincible);
        {
            Attack();
        }
    }

    protected virtual void Attack()
    {
        PlayerControl.Instance.TakeDamage(damage);
    }
}

her is code for the specific enemy

using UnityEngine;

public class Zombie : Enemy
{
    // Start is called once before the first execution of Update after the MonoBehaviour is created
    protected override void Start()
    {
        rb.gravityScale = 12f;
    }

    protected override void Awake()
    {
        base.Awake();
    }

    // Update is called once per frame
    protected override void Update()
    {
        base.Update();
        if (!isRecoiling)
        {
            transform.position = Vector2.MoveTowards(transform.position, new Vector2(PlayerControl.Instance.transform.position.x, transform.position.y), speed * Time.deltaTime);
        }
    }

    public override void EnemyHit(float _damageDone, Vector2 _hitDirection, float _hitForce)
    {
        base.EnemyHit(_damageDone, _hitDirection, _hitForce);
    }
}

and here is my player state manager

using UnityEngine;

public class PlayerStatesList : MonoBehaviour
{
    public bool jumping = false;
    public bool dashing = false; 
    public bool recoilingX, recoilingY;
    public bool lookingRight;
    public bool invincible;
}

Since you didn’t say how all this gets called and more importantly, what ACTUAL lines are being being called (Eg, what line is executing and from where… remember code is nice but setup matters), all I can say is…

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.

First off im very exited that i got a reply from the legendary kurt-dekkar

Second thank you for providing feedback

Third i totally forgot to explain my code:

In the enemy code the on trigger stay2D coroutine is supposed to detect when the enemy touches the player and run the attack couroutine which runs the takeDamage co routine in player control

Fourth i will continue to try to debug on my own just a little help will be much appreciated

Also I fixed it. I tried putting the collision detection in the player control script rather than the enemy sript and it works fine.

1 Like