Hi,

I have run into a little wall. I have some balls spawning from random locations. Once one ball is destroyed another ball is instantiated. when the player knocks the balls into a goal they get points and this goes on for set time. At the end of the round I want to advance to a harder round with smaller targets, higher points needed etc…

where I am drawing problems is advancing into a new round. I have no problem with hard coding if that is what needs to be done but I am sure there is an easy way to do this. I am using a trigger to start the round for round one…thank you for anyone who can help and I can handle everything once I understand how to advance rounds.

public class HeadSpawner1 : MonoBehaviour {

public GameObject[] targetArea; 
public GameObject[] balls;
public Transform[] spawnLocal;
public Transform startingLocal; 
public float speed; 
public float spawnWait;
public float destroyTimer;
public int startWait;
public bool stop;
private GameObject inPlayBall;
private GameObject inTarget; 
public GameObject starter; 
private GameObject hasStarted; 

public Text timerText; 
public float t; 


Vector3 relativePos; 
int ranNum; 

void Start () {
    
    hasStarted = Instantiate (starter, startingLocal.transform.position, startingLocal.transform.rotation) as GameObject;

}
    
void Update () {

    if(hasStarted == null && t >= 0 ){
        
    t -= Time.deltaTime; 
    string minutes = ((int)t / 60).ToString (); 
    string seconds = (t % 60).ToString ("f0"); 
    timerText.text = minutes + ":" + seconds; 

    StartCoroutine (SpawnerRound1 ());

    }

    if (t <= 0) {
        timerText.text = "Round Over";
        StopCoroutine (SpawnerRound1 ());
    }
}

void OnTriggerEnter(Collider RoundStarter){

    if(RoundStarter.tag == "TriggerStart" ){
        Destroy (hasStarted); 
    }

}
    
     

IEnumerator SpawnerRound1(){
    yield return new WaitForSeconds (startWait);

    if (inPlayBall == null) {
     

    
        ranNum = Random.Range (0, 3); 
        inPlayBall = Instantiate (balls [ranNum], spawnLocal [ranNum].transform.position, Quaternion.identity) as GameObject;
        relativePos = targetArea[ranNum].transform.position - inPlayBall.transform.position;  

        inPlayBall.GetComponent<Rigidbody> ().velocity = relativePos;
        Destroy(inPlayBall, destroyTimer);

        yield return new WaitForSeconds (destroyTimer + 2 );
    }
}

}

One quick thing I missed…I want the player to advance based on score

Hey @revolution5,

I’ve made an example scene for you with a round system according to your code.

(Don’t forget to check out the code for you specifically below the following concept code)

The basic concept is this:

You have a game cycle, within that
game cycle, you loop through multiple
rounds. You can wait for each phase of
the round by starting coroutines
inside coroutines, as shown below.

using UnityEngine;
using System.Collections;

public class RoundSystemSimple : MonoBehaviour {

    [Range( 1, 5 )] // Makes the number of rounds a slider from 1 to 5.
    public int m_numberOfRounds = 3; // Indicate number of rounds, 3 by default.

    [Header( "Duration Settings" )]
    public float m_startWait = 3f;
    public float m_roundDurationInSeconds = 5f; // 5 seconds, try 180 for 3 minutes (set in inspector).
    public float m_endWait = 2f;

    // Holder Variables.
    private int m_currentRound = 1;
    private float m_currentRoundTimeRemaining;
    private WaitForSeconds m_waitShortly = new WaitForSeconds( 0.01f );

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

    private IEnumerator RoundSystem()
    {
        // Lasts X rounds.
        while( m_currentRound <= m_numberOfRounds )
        {
            yield return StartCoroutine( StartRound() );
            yield return StartCoroutine( RoundBusy() );
            yield return StartCoroutine( EndRound() );
            m_currentRound++;
        }
    }

    private IEnumerator StartRound()
    {
        // Do Round Start Stuff.
        m_currentRoundTimeRemaining = m_roundDurationInSeconds;
        yield return m_waitShortly;
    }

    private IEnumerator RoundBusy()
    {
        while( m_currentRoundTimeRemaining > 0f )
        {
            // Do Round Busy Stuff. (Using clamp to prevent dirty values like -0.0123 upon round ending)
            m_currentRoundTimeRemaining = Mathf.Clamp( m_currentRoundTimeRemaining - Time.deltaTime, 0, m_roundDurationInSeconds );
            yield return m_waitShortly;
        }
    }

    private IEnumerator EndRound()
    {
        // Do Round End Stuff.
        yield return new WaitForSeconds( m_endWait );
    }
}

The full code adjusted to your needs is this:

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

public class RoundSystemExample : MonoBehaviour
{
    [Range(1,5)] // Makes the number of rounds a slider from 1 to 5.
    public int m_numberOfRounds = 3; // Indicate number of rounds, 3 by default.

    [Header("Duration Settings")]
    public float m_startWait = 3f;
    public float m_roundDurationInSeconds = 5f; // 5 seconds, try 180 for 3 minutes (set in inspector).
    public float m_endWait = 2f;

    [Header("Has Started")]
    public GameObject m_starterPrefab;
    public Transform m_startingLocation;
    public GameObject hasStarted; // Public so it can be set if wished for.

    [Header("Ball Settings")]
    public float m_initialBallSpeed = 5f;
    public float m_ballRespawnWait = 3f; // Currently Unused.

    [Header("Timer Display")]
    public Text m_timerText;

    [Header("Force Stop")]
    public bool m_stop;

    // Lists of different targetAreas, balls and spawn locations.
    [Header("Lists")]
    public List<GameObject> m_targetAreas = new List<GameObject>();
    public List<GameObject> m_balls = new List<GameObject>();
    public List<Transform> m_spawnLocations = new List<Transform>();

    // Active Objects.
    private GameObject inPlayBall;
    private GameObject inTarget;

    // Holder Variables.
    private int m_currentRound = 1;
    private float m_currentRoundTimeRemaining;
    private WaitForSeconds m_waitShortly = new WaitForSeconds( 0.01f );
    private Vector3 m_relativePos;
    private int m_ranNum;

    void Start()
    {
        if (hasStarted == null)
        {
            hasStarted = Instantiate( m_starterPrefab, m_startingLocation.position, m_startingLocation.rotation ) as GameObject;
        }

        StartCoroutine( RoundSystem() );
    }

    private IEnumerator RoundSystem()
    {
        Debug.Log( "Awaiting has started to become null" );

        while ( hasStarted != null )
        {
            yield return m_waitShortly;
        }

        Debug.Log( "HasStarted became null, Starting RoundSystem." );

        // Lasts X rounds.
        while (m_currentRound <= m_numberOfRounds && !m_stop)
        {
            // Just a friendly debug, could be used for UI call. (Add else for normal rounds)
            if( m_currentRound == m_numberOfRounds )
            {
                Debug.Log( "Final Round!" );
            }

            yield return StartCoroutine( StartRound() );
            yield return StartCoroutine( RoundBusy() );
            yield return StartCoroutine( EndRound() );
            m_currentRound++;
        }
    }

    private IEnumerator StartRound()
    {
        // Do Start Round Stuff.
        float startWaitCurrent = m_startWait;

        while (startWaitCurrent > 0)
        {
            startWaitCurrent -= Time.deltaTime;
            m_timerText.text = "Round " + m_currentRound + " Starting in " + Mathf.RoundToInt( startWaitCurrent ).ToString();
            yield return m_waitShortly;
        }

        // If you don't want text display stuff, just use:
        // yield return new WaitForSeconds( m_startWait ); // Round start delay.


        if( !m_stop )
        {
            m_currentRoundTimeRemaining = m_roundDurationInSeconds;

            if( inPlayBall == null )
            {
                // Your adjusted code.
                inPlayBall = Instantiate( _getRandomFromList( m_balls ), _getRandomFromList( m_spawnLocations ).position, Quaternion.identity ) as GameObject;
                m_relativePos = _getRandomFromList( m_targetAreas ).transform.position - inPlayBall.transform.position;
                inPlayBall.GetComponent<Rigidbody>().velocity = m_relativePos;
            }
        }
    }

    private IEnumerator RoundBusy()
    {
        while (m_currentRoundTimeRemaining > 0f && !m_stop)
        {
            // Do Round Busy Stuff. (Using clamp to prevent dirty values like -0.0123 upon round ending)
            m_currentRoundTimeRemaining = Mathf.Clamp( m_currentRoundTimeRemaining - Time.deltaTime, 0, m_roundDurationInSeconds);
            _updateText();
            yield return m_waitShortly;
        }
    }

    private IEnumerator EndRound()
    {
        // Do Round End Stuff.
        m_timerText.text = (m_currentRound >= m_numberOfRounds) ? "Game Over" : "Round Over";
        Destroy( inPlayBall );
        yield return new WaitForSeconds( m_endWait );
    }

    // Using your code, changed from .ToString("f0") to .ToString( "00" ); force two digits for seconds at all times.
    private void _updateText()
    {
        string minutes = ( ( int ) m_currentRoundTimeRemaining / 60 ).ToString();
        string seconds = ( m_currentRoundTimeRemaining % 60 ).ToString( "00" );
        m_timerText.text = minutes + ":" + seconds;
    }

    // Applied generic method, gets random item from list.
    private T _getRandomFromList<T>(List<T> list)
    {
        if (list == null)
        {
            Debug.Log( "List is null, make sure list = new List<>(); was called somewhere" );
            return default( T );
        }
        else if (list.Count == 0)
        {
            Debug.Log( "List is empty, fill it first." );
            return default( T );
        }
        
        // Return a random item from the list.
        return list[ Random.Range( 0, list.Count ) ];
    }
}

I hope this helps you out! It took me a while, but it was fun to make, so thank you for your question! :slight_smile:

If it did help you out, please accept this answer, it’d be much appreciated!

Best of luck! If you need anything else, let me know!