Why does my enemy one hit me when I have 3 lives

Viewed 127

I am in the process of making a game in Unity and I have run into a problem. I created a heart system UI + script and and enemy + script. In my game, I have 3 lives but when I made the enemy attack me, he one hits me. Is there a way that I can have a delay between each attack.

Here are the scripts.

Enemy Script:

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

public class Enemy : MonoBehaviour
{

    public Transform attackPoint;
    public float attackrange = 0.5f;
    public LayerMask playerlayers;
    public float speed = 3f;
    private Transform target;

    IEnumerator Cooldown()
    {
        yield return new WaitForSeconds(3);
    }

    private void Update()
    {
        if (target != null)
        {
            float step = speed * Time.deltaTime;
            transform.position = Vector2.MoveTowards(transform.position, target.position, step);
            Collider2D[] hitplayers = Physics2D.OverlapCircleAll(attackPoint.position, attackrange, playerlayers);
            foreach (Collider2D player in hitplayers)
            {
                player.GetComponent<HeartSystem>().TakeDamage(1);
                StartCoroutine(Cooldown());
            }
        }
    }


    private void OnTriggerEnter2D(Collider2D other)
    {
        if (other.gameObject.tag == "Player")
        {
            target = other.transform;


        }
    }

    private void OnTriggerExit2D(Collider2D other)
    {

        if (other.gameObject.tag == "Player")
        {
            target = null;

        }
    }

    void OnDrawGizmosSelected()
    {
        if (attackPoint == null)
            return;

        Gizmos.DrawWireSphere(attackPoint.position, attackrange);
    }
}

And here is my health system script:

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

public class HeartSystem : MonoBehaviour
{
    public GameObject[] hearts;
    public int life;


    void Update()
    {
        if (life < 1)
        {
            Destroy(hearts[0].gameObject);
            SceneManager.LoadScene(SceneManager.GetActiveScene().buildIndex + 1);
        }
        else if (life < 2)
        {
            Destroy(hearts[1].gameObject);
        }
        else if (life < 3)
        {
            Destroy(hearts[2].gameObject);
        }
    }

    public void TakeDamage(int d)
    {
        life -= d;
    }
} 

I hope we can find a solution.

1 Answers

So from what i understood from your code: the enemy targets the player on collision and once the player is targeted it receives damage on update.

The problem may be caused by the fact that the update method runs more than once until the collision ends. That would mean that your cooldown is not working.

I don't understand the way your timer works but I can tell you how i usually do.

Let's say the cooldown is 1sec. After attacking the player the first time you get the current time, add 1 second to it and store it like "nextAttackTime". Next time the enemy tries to attack it will check if the current time is equal or higher to the "nextAttackTime".

Your way of doing the cooldown looks very elegant but if it really isn't working you can consider trying it the way i described. it may not be as elegant but it is reliable.

-----EDIT-----

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

public class Enemy : MonoBehaviour
{

    public Transform attackPoint;
    public float attackrange = 0.5f;
    public LayerMask playerlayers;
    public float speed = 3f;
    private Transform target;
    //First we will need a variable to store the time when the next attack will be possible, it starts with 0. We'll also create a public variable to define the cooldown duration
    private float nextAttackTime = 0f;
    public float attackCoolDown = 3f;

    IEnumerator Cooldown()
    {
        yield return new WaitForSeconds(3);
    }

    private void Update()
    {
        if (target != null)
        {
            float step = speed * Time.deltaTime;
            transform.position = Vector2.MoveTowards(transform.position, target.position, step);
            Collider2D[] hitplayers = Physics2D.OverlapCircleAll(attackPoint.position, attackrange, playerlayers);
            foreach (Collider2D player in hitplayers)
            {
                //then before dealing the damage we check if it is already time to attack again
                if(Time.time >= nextAttackTime){
                     player.GetComponent<HeartSystem>().TakeDamage(1);
                     //After dealing damage we reset the time for the next attack. The Time.time should return the time in seconds that the game has been running and we'll add 3 seconds to that to define the time for the next attack.
                     nextAttackTime = (Time.time + attackCoolDown);
                     //StartCoroutine(Cooldown());
                }
                
            }
        }
    }

So this is the editted code with the changes I suggested. I edited it right here in StackOverflow with no help of a code editor so there could be some typos.

Related