- Home /
[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?"
Answer by Bunny83 · Nov 29, 2020 at 02:03 PM
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.
ps: Please do not call "a method" "a void". You wouldn't call "a cat" "a small" just because it's a small cat because no one would know what you're talking about while the usage of the void type is kinda restricted most people probably can infer that you talk about a method, but there are also void pointers (which are rarely used in C# but still exist). The "void" in front of the method declaration just specifies that this method does not have a return type (void / invalid).
So this:
int Some$$anonymous$$ethod()
{
return 0;
}
is a method returning an int, while this:
void SomeOther$$anonymous$$ethod()
{
}
is a method that doesn't return anything. I know I'm fighting against windmills as in the recent years I've come across countless of example of this misleading usage, even in some "tutorial" videos. Though I thought I should bring it up from time to time -.- (hope dies last)
sorry for calling method a void, i corrected it in the title
also thanks! your solution worked flawlessly, i've been on this for 2 days, i can't thank you enough.
Answer by Envans · Nov 29, 2020 at 12:36 PM
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);
}
}
}
Just an aside. That isn't a global variable It's a member of the ZombieAttack
class.
You are right!, but what I meant was global variable in the ZombieAttack class such that it can be used in any function of the class or anywhere in the class, if you define the variable in a function that variable is local and cant be used anywhere else except that function, so in that sense it is a "global" variable. I think the OP being new in game developing would better understand the term "global" variable rather than using confusing definitions.
Your answer
Follow this Question
Related Questions
Enemy raycast detection 0 Answers
Programming an enemy to shoot upwards 1 Answer
Enemy AI Script Acting Abnormal 0 Answers
AI script works, when we add a blocked function it stops working HELP 0 Answers