Search code examples
c#unity-game-engineraycasting

Trying to get enemy to deal damage every set seconds (Unity)


I am creating a 3D Shooter and I am trying to make an enemy deal damage to the player every set seconds. I have made the enemy deal damage with a raycast but it deals the damage way too fast.

I thought using yield return new WaitForSeconds(2) would take 1 damage away from the player every 2 seconds but it deals damage to the player a lot faster.

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

public class EnemyMove : MonoBehaviour
{
    public Transform target;
    public Transform player;
    public float enemySpeed;
    public int moveTrigger = 1;
    public int isAttacking;

    public float distanceFromPlayer;

    void Update()
    {
        distanceFromPlayer = Vector3.Distance(target.transform.position, player.transform.position);

        if (distanceFromPlayer <= 10 && moveTrigger == 1)
        {
            transform.LookAt(target);
            StartCoroutine(EnemyDamage());
        }
        if (distanceFromPlayer <10 && moveTrigger == 1 && distanceFromPlayer >3)
        {
            transform.Translate(Vector3.forward * enemySpeed * Time.deltaTime);
        }
    }

    IEnumerator EnemyDamage()
    {
        RaycastHit PlayerHit;
        if (Physics.Raycast(target.transform.position, target.transform.forward, out PlayerHit))
        {
            Debug.Log(PlayerHit.transform.name);
            Target target = PlayerHit.transform.GetComponent<Target>();
            if (target != null)
            {
                yield return new WaitForSeconds(2);
                GlobalHealth.playerHealth -= 1;
                yield return null;
            }
        }
    }
}

Solution

  • As mentioned in other answers, you are starting a new coroutine each frame. You should do all your waiting and looping inside your coroutine, as execution exits and re-enters your coroutine from the yeild statment. This is how you would write this to work

    // in update
    if (distanceFromPlayer <= 10 && moveTrigger == 1){
            transform.LookAt(target);
            if(!isAttacking)
                StartCoroutine(EnemyDamage());
    }
    

    IEnumerator EnemyDamage()
    {
        isAttacking = true;
        while(distanceFromPlayer <= 10){ // in range
            RaycastHit PlayerHit;
            if (Physics.Raycast(target.transform.position, target.transform.forward, out PlayerHit)){
                Target target = PlayerHit.transform.GetComponent<Target>();
                if (target != null){
                    GlobalHealth.playerHealth -= 1;
                    yield return new WaitForSeconds(2);      
                }
            }
        }
        isAttacking = false; // out of range
        yield return null;
    }