[SOLVED] using var from another method?

i’m making a small top down open world zombie game and testing out if a player is in range of the zombie and if true then the zombie can attack the player.

|

i need the script to not be taxing as much as possible because worst case scenario the server has to render 460 zombies.

|

as far as i understand it (which is not much), raycast is taxing so i started testing other methods, this is the code i’m trying to test, i haven’t tested the rest so it won’t work as it is but wanted to include it to give an idea of what i’m trying to do

using UnityEngine;
using System.Collections;

public class ZombieAttack : MonoBehaviour
{
    public Transform zombieTransform;
    public int damage = 1;
    public float attackRange = 0.7f;
    public GameObject hitEffect;
    public LayerMask player;



    void Start()
    {
        StartCoroutine(attack());
    }


    public void Update()
    {
        //want the var in update to check constantly if the player is in range or not
        var attackingZone = Physics2D.OverlapCircle(zombieTransform.position, attackRange, player);
    }

    IEnumerator attack()
    {
        while (attackingZone)
        {
            //Calling "Health" class on the player
            Health playerHealth = attackingZone.transform.GetComponent<Health>();
            if (playerHealth = null)
            {
                yield break;
            }
            else
            {
                //play animation here
                //wait 0.2 seconds
                playerHealth.TakeDamage(damage);
            }
            //this is just a place holder piece of code for now
            Instantiate(hitEffect, Vector2.zero, Quaternion.identity);
            //2 seconds till the zombie can attack again
            yield return new WaitForSeconds(2f);
        }
    }
}

|

so now my question is “what is the least taxing way/code i can do this with? and if this code is good then how do i make it work?”

Make the attackingZone a global variable like this

using UnityEngine;
using System.Collections;
 
public class ZombieAttack : MonoBehaviour
 {
     public Transform zombieTransform;
     public int damage = 1;
     public float attackRange = 0.7f;
     public GameObject hitEffect;
     public LayerMask player;

     private Collider2D attackingZone;
 
 
     void Start()
     {
         StartCoroutine(attack());
     }
 
 
     public void Update()
     {
         //want the var in update to check constantly if the player is in range or not
         attackingZone = Physics2D.OverlapCircle(zombieTransform.position, attackRange, player);
     }
 
     IEnumerator attack()
     {
         while (attackingZone)
         {
             //Calling "Health" class on the player
             Health playerHealth = attackingZone.transform.GetComponent<Health>();
             if (playerHealth = null)
             {
                 yield break;
             }
             else
             {
                 //play animation here
                 //wait 0.2 seconds
                 playerHealth.TakeDamage(damage);
             }
             //this is just a place holder piece of code for now
             Instantiate(hitEffect, Vector2.zero, Quaternion.identity);
             //2 seconds till the zombie can attack again
             yield return new WaitForSeconds(2f);
         }
     }
 }

what is the least taxing way/code i
can do this with?

Uhm if you don’t need the “attackingZone” information anywhere else than inside your attack coroutine, why don’t you put that line inside your coroutine? Of course if you want to use it for some other thing inside Update, Envans solution would work fine.

Note that your current code would not work at all because you start the coroutine in Start which runs before Update. So when the coroutine is started you certainly don’t have any information yel. Since your while loop terminates when you have no overlap, the coroutine would terminate immediately.

If this behaviour should control the zombie attack behaviour, you should use something like this without any Update method:

IEnumerator attack()
{
    var waitForNextScan = new WaitForSeconds(0.1f);
    var attackCooldown = new WaitForSeconds(2f);
    while (true)
    {
        yield return waitForNextScan;
        var target = Physics2D.OverlapCircle(zombieTransform.position, attackRange, player);
        if (target == null)
            continue;
        Health playerHealth = target.GetComponent<Health>();
        if (playerHealth == null)
            continue;
        playerHealth.TakeDamage(damage);
        Instantiate(hitEffect, Vector2.zero, Quaternion.identity);
        yield return attackCooldown;
    }
}

This will check every 0.1 seconds if the zombie has anything in range. If not, we wait for 0.1 seconds. If something is in range then we check if the “thing” in range has a Health script on it. If not we just jump back up and wait another 0.1 seconds. However if we made it through so we do have a Health script on the target, we apply the attack and wait for the specified cool down time before we try attacking again.

Note that if you want a faster reaction time of the zombie, you may lower the “waitForNextScan” time or replace it with “null” if you want it scan for the player every frame. However as you asked for the least taxing way, doing roughly 10 checks per second should be enough.

Don’t forget to remove the Update method completely. Even an empty Update method requires CPU time.

Finally I would recommend you refactor your “attack” method and name it “Attack” to use default convention and be consistent.