Causing damage at intervals/returning a value. C#

You’re going to have to excuse what is most likely going to be a dumb question but I need a bit of help here. I’m dealing with a script where I want the player to suffer damage at a set interval.

Parts of the code I’m using important to this question:

public float DamDelay = 2.0f;
private PlayerHealth_Test playerHealth;...

playerHealth = Target.GetComponent<PlayerHealth_Test>();...

void Update(){

    if (parenting == true)
    {
    Invoke ("Damage", DamDelay);
    } 

} 

void damage(){
		
		
	playerHealth.CurrentHealth -= 1.0f;
	
		
}

I looked around the answers forum but the stuff I came upon (yield, WaitForSeconds and such) are for Javascript. Apparently Invoke is supposed to be close to that (and I’ve actually used Invoke before) so I ended up using that. The problem being, I don’t actually have a clue how to set up a return function in C# having never had to deal with such a thing before. It doesn’t help that the value I’m modifying is from another script. I know that by giving damage the void prefix it’s not going to return something by definition but again, no real idea how to return a value.

So if you’ll excuse the stupidity I could you some help figuring this out.

Please put in mind that the string in Invoke() is case sensitive, you wrote there “Damage” but you method name is “damage”.

Also you are mistaken,(yield, WaitForSeconds and such) are not for Javascript only, they work for C# as well. You just need to know how use them, I’ll give you an example:

    void someMethod()
    {
        StartCoroutine(damage());
    }

    IEnumerator damage()
    {
        yield return new WaitForSeconds(1);
        playerHealth.CurrentHealth -= 1.0f;
    }

but when you use coroutines you should know that if the script gone inactive for any reason it will stop.

I don’t know if you want the damage to happen every 2 seconds or you want to delay it 2 sec. if you want it to keep calling damage() then use InvokeRepeating() instead

You should never modify variables of another class. While the language may allow it, it is bad practice.

So what you should do instead, is inside the Player_Health component, have a method like this:

public void ApplyDamage(float howMuch){
	this.CurrentHealth -= howMuch;
}

Then, use the method when you need it:

playerHealth.ApplyDamage(1);

Then, if you need to add stuff like invincibility timers, etc, you can add them in the ApplyDamage routine.

As for the delay, if it’s because of an environmental effect, just start a couroutine and every time the coroutine comes up for execution again, just ApplyDamage again.

There are a few ways to go about this. One would be to use invoke, but then you need to use it only once, not every Update(), as it will call it every frame (with a starting delay of 2 seconds):

private bool invoked = false;

void Update() {
    if (!invoked) {
        Invoke("Damage", DamDelay);
        invoked = true;
    }
}

void Damage(){
    playerHealth.CurrentHealth -= 1.0f;
    invoked = false;
}

Another would be to use coroutines like @Jix suggested.

The third, and my personal favorite, is simple, no magic, you understand exactly what happens. Simply set the time in which you want the damage to happen (current time + DamDelay), and when the time comes, do the damage and reset the timer.

private nextDamage;

void Start() {
    nextDamage = Time.time + DamDelay;
}

void Update() {
    if (nextDamage <= Time.time) {
        nextDamage = Time.time + DamDelay;
        playerHealth.CurrentHealth -= 1.0f;
    }
}