Problems with IEnumerator and WaitForSeconds

Hi I have been using Unity for under a month now, but I’ve got a lot of progress so far in 3D tank game which I am currently developing. I have a player tank and two very horrible AI. :sweat_smile: I set up a particle system called explosion in my C# script, and when health drops to 0 on the health bar I want it to play the particle system, wait a few seconds for the explosion to finish, and then respawn with full health by changing transform.position on the tank. So far I have not been able to get WaitForSeconds to work:

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

public class HealthChange : MonoBehaviour {

    public float health;
    public Slider healthBar;
    public ParticleSystem explosion;
    private bool running;

    void Start () {
        running = true;
    }

    IEnumerator waitacouple() {
        yield return new WaitForSeconds (5);
    }

    void OnCollisionEnter (Collision col) {
        if (col.gameObject.tag == "Bullet") {
            health -= 1;
            healthBar.value = health;
            Destroy (col.gameObject);
            if (health == 0 && running == true) {
                explosion.Play();
                StartCoroutine ("waitacouple");
                health = 1000;
                transform.position = new Vector3 (60, 10, 60);
            }
        }
    }
}

Starting a coroutine is kind of like starting a thread. It doesn’t wait for the coroutine to finish. Try moving the respawn into the waitacouple method.

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class HealthChange : MonoBehaviour {
    public float health;
    public Slider healthBar;
    public ParticleSystem explosion;
    private bool running;
    void Start () {
        running = true;
    }
    IEnumerator waitacouple() {
        yield return new WaitForSeconds (5);
        health = 1000;
        transform.position = new Vector3 (60, 10, 60);
    }
    void OnCollisionEnter (Collision col) {
        if (col.gameObject.tag == "Bullet") {
            health -= 1;
            healthBar.value = health;
            Destroy (col.gameObject);
            if (health == 0 && running == true) {
                explosion.Play();
                StartCoroutine ("waitacouple");
            }
        }
    }
}
1 Like

Adding onto the goodness that @MaxGuernseyIII posted above, I recommend a few changes:

Instead of testing for health == 0, you should test for health <= 0. Even though you are only doing integers now, the health variable is a float, and hence it could be changed in the future so that it isn’t holding integer numbers, and then it may not test positively for zero.

As for your StartCoroutine call, it is better to use this construct:

 StartCoroutine( waitacouple());

instead of the version that takes a string. The above construct enables you to pass arbitrary arguments into the coroutine, such as (perhaps) an amount of time to wait, location to respawn, etc. (should you choose to do something like that).

Hope you get it sorted out and get your tanks blasting and spawning soon!

2 Likes

Thanks a lot! It worked! :smile:

Kurt Dekker - Thanks for the help! My first language was python and I knew about <=, but somehow it did not occur to me to use it in C#. :roll_eyes: Thanks for the syntax information! Now my next challenge is getting the AI to be not only Artificial, but Intelligent. :stuck_out_tongue:

Cool… this is where the fun really begins, in my opinion!

But definitely keep it simple, as often simple and random gives great gameplay. The tendency with AI is to try and overthink it, when in fact a lot less will actually give a more-amusing gameplay experience.

1 Like