Coroutine sequence not running properly

Hi hi,

I have a basic Enemy AI script for moving and firing using vector3 coordinates and bools. I’m trying to mangle coroutine sequences so they run in the right order and after a lot of consulting these forums (thanks all!)

I’ve managed to get the movement working in sequence (and the sequence does loop successfully), however the fire coroutine is not instantiating a new bullet after first initiation (the second one will just return nothing, etc). I’m thinking it’s because my sequence isn’t resetting the bool to make sure the bullet only fires once. Can’t for the life of me figure out why though!

Any help would be much appreciated. I’ve tried to annotate it where possible (as I am a C# newbie so I need to remind myself constantly!), so apologies if this code is a bit scrappy.

using UnityEngine;
using System.Collections;

public class EnemyAI001 : MonoBehaviour
{

    //Me and you
    public GameObject iEnemy;
    public GameObject youPlayer;
    //So I can face you
    public Vector3 playernose;
    //How fast I travel to my destination
    public float approachSpeed;
    //How fast I travel on my pre-scripted path after arriving from my origin
    public float movementSpeed;
    //My Gun
    public GameObject weapon;
    //My Bullet
    public Rigidbody enemyBullet;
    //Control the amount I shoot
    public bool bulletAlive = false;
    //Control how fast I shoot
    public float bulletSpeed = 1f;

    //Vectors for travel, and bools to dictate which sequence to run
    //Origin Vector3 and Bools
    Vector3 foclc = new Vector3(0, 0, 150);
    bool originBool = true;
    bool originBoolCapsule()
    {
        return originBool && !firstBool && !secondBool && !finalBool;
    }

    //Destination Vector3 and Bools
    Vector3 x0y5z30 = new Vector3(0, 5, 30);
    bool firstBool = false;
    bool firstBoolCapsule()
    {
        return !originBool && firstBool && !secondBool && !finalBool;
    }

    //Second Destination Vector3 and Bools
    Vector3 x20y10z15 = new Vector3(20, 10, 15);
    bool secondBool = false;
    bool secondBoolCapsule()
    {
        return !originBool && !firstBool && secondBool && !finalBool;
    }

    //Final Destination Vector3 and Bools
    Vector3 xm20y0z45 = new Vector3(-20, 0, 45);
    bool finalBool = false;
    bool finalBoolCapsule()
    {
        return !originBool && !firstBool && !secondBool && finalBool;
    }

    // Assign my identity on Start
    void Start ()
    {
        iEnemy = this.gameObject;
	}

    public void Update()
    {
        //Keep Looking at Player 
        playernose = new Vector3(youPlayer.transform.position.x, youPlayer.transform.position.y, youPlayer.transform.position.z);
        iEnemy.transform.LookAt(playernose);

        //If I've just spawned
        if (originBoolCapsule())
        {
            StartCoroutine(OriginRunSquence());
        }

        //If I've reached my first destination, fire and move to my next one
        else if (firstBoolCapsule())
        {
            StartCoroutine(RunSquence1());
        }

        //If I've reached my second destination, fire and move to my next one
        else if (secondBoolCapsule())
        {
            StartCoroutine(RunSquence2());
        }

        //If I've reached my final destination, fire and loop back to the start
        else if (finalBoolCapsule())
        {
            StartCoroutine(RunSquence3());
        }

    }

    //Used for movement from spawn tofirst destination
    public IEnumerator OriginRunSquence()
    {
        yield return StartCoroutine(moveToDestination());
    }

    //Used for sequencing first movement and firing and any other coroutines.
    public IEnumerator RunSquence1()
    {

        yield return StartCoroutine(fire());

        yield return new WaitForSeconds(1.0f);

        yield return StartCoroutine(firstMove());

    }

    //Used for sequencing second movement and firing and any other coroutines.
    public IEnumerator RunSquence2()
    {
        yield return StartCoroutine(fire());

        yield return new WaitForSeconds(1.0f);

        yield return StartCoroutine(secondMove());
    }

    //Used for sequencing final movement and firing and any other coroutines.
    public IEnumerator RunSquence3()
    {
        yield return StartCoroutine(fire());

        yield return new WaitForSeconds(1.0f);

        yield return StartCoroutine(finalMove());
    }

    //Fire bool and fire coroutine

    private void reloadBullet()
    {
        bulletAlive = false;
    }

    public IEnumerator fire()
    {
        if (bulletAlive == false)
        {
            //I'm loading up a bullet
            Rigidbody newenemyBullet = Instantiate(enemyBullet, weapon.transform.position, weapon.transform.rotation) as Rigidbody;

            //I'm firing a bullet
            newenemyBullet.AddForce(iEnemy.transform.forward * bulletSpeed, ForceMode.VelocityChange);

            bulletAlive = true;
            yield return new WaitForSeconds(0.5f);
        }

        else if (bulletAlive == true)
        {
            yield break;
        }
    }

    //Coroutine sequences

    //Move to the destination from spawn
    public IEnumerator moveToDestination()
    {
        if (iEnemy.transform.position != x0y5z30)
        {
            //Move me
            iEnemy.transform.position = Vector3.Lerp(iEnemy.transform.position, x0y5z30, approachSpeed * Time.deltaTime);
            yield return new WaitForSeconds(0.5f);
        }

        if (iEnemy.transform.position.z <= 30.5)
        {
            //Snap me
            iEnemy.transform.position = x0y5z30;
            yield return new WaitForSeconds(1);
            originBool = false;
            firstBool = true;
            yield break;
        }

    }

    //My first move after arriving at my destination
    public IEnumerator firstMove()
    {
        if (iEnemy.transform.position != x20y10z15)
        {
                //Move me
                iEnemy.transform.position = Vector3.Lerp(iEnemy.transform.position, x20y10z15, movementSpeed * Time.deltaTime);
                yield return new WaitForSeconds(0.5f);
        }

        if (iEnemy.transform.position.z <= 15.2)
        {
                //Snap me
                iEnemy.transform.position = x20y10z15;
                yield return new WaitForSeconds(1);
                originBool = false;
                firstBool = false;
                secondBool = true;
                finalBool = false;
                yield break;
        }
    }

    //My second move
    public IEnumerator secondMove()
    {
        if (iEnemy.transform.position != xm20y0z45)
        {
                //Move me
                iEnemy.transform.position = Vector3.Lerp(iEnemy.transform.position, xm20y0z45, movementSpeed * Time.deltaTime);
                yield return new WaitForSeconds(0.5f);
                //Debug.Log("Working");
        }

        if (iEnemy.transform.position.z >= 44.8)
        {
                //Snap me
                iEnemy.transform.position = xm20y0z45;
                yield return new WaitForSeconds(1);
                originBool = false;
                firstBool = false;
                secondBool = false;
                finalBool = true;
                yield break;
        }
    }

    //The last scripted move in my behaviour pattern
    public IEnumerator finalMove()
    {
        if (iEnemy.transform.position != x0y5z30)
        {
                //Move me
                iEnemy.transform.position = Vector3.Lerp(iEnemy.transform.position, x0y5z30, movementSpeed * Time.deltaTime);
                yield return new WaitForSeconds(0.5f);
        }

        if (iEnemy.transform.position.z <= 30.2)
        {
                //Snap me
                iEnemy.transform.position = x0y5z30;
                yield return new WaitForSeconds(1);
                originBool = true;
                firstBool = false;
                secondBool = false;
                finalBool = false;
                yield break;
        }
    }
}

In answer to your question it appears that you never call the function reloadBullet(), so your fire function always goes through to the else if portion.

public IEnumerator fire()
         {
         if (bulletAlive == false)
         {
             ....
             //Only gets called the first time
         } 
         else if (bulletAlive == true)
         {
             //Gets called all remaining times
             yield break;
         }
     }

One note, I would suggest using enums and a switch case in your update instead of your complex booleans. It would also make it easier to add more moves in the future if you wanted.

public enum Sequence{origin, first, second, final}

 public class EnemyAI001 : MonoBehaviour
 {
    public Sequence currentStep = Sequence.origin;
    ...
    Update()
    {
        ...
        switch(currentStep)
        {
             case(Sequence.origin):
             StartCoroutine(OriginRunSquence());
             break;
             case(Sequence.first);
             ...
        }
    }

Then instead of having to change 4 bools just assign the next enum in the switch case you want to run.

 public IEnumerator firstMove()
 {
     ... 
     if (iEnemy.transform.position.z <= 15.2)
     {
             //Snap me
             iEnemy.transform.position = x20y10z15;
             yield return new WaitForSeconds(1);

             // instead of these:
             //originBool = false;
             //firstBool = false;
             //secondBool = true;
             //finalBool = false;

             // it would just be this:
             currentStep = Sequence.second;

             yield break;
     }
 }