Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. Dismiss Notice

Wave spawner errors

Discussion in 'Scripting' started by Flynn_Prime, May 15, 2017.

  1. Flynn_Prime

    Flynn_Prime

    Joined:
    Apr 26, 2017
    Posts:
    383
    Hi, I'm getting errors CS1502 and CS1503 for line 59. I'm trying to adapt a spawner that I made following a tutorial (which works correctly), as it did not have the ability to add various enemies (with different variables such as spawn count/rate etc.) I tried to overcome this by nesting a list within my wave array but i'm getting these errors. I'm not much of a scripter and still learning so please could someone identify my problem? I've posted both the initial script, and my adaptation below. Thanks in advance!

    Initial Script:

    Code (CSharp):
    1. using UnityEngine;
    2. using System.Collections;
    3. using System.Collections.Generic;
    4.  
    5. public class WaveController : MonoBehaviour {
    6.  
    7.     [System.Serializable]
    8.     public class Wave {
    9.         public string name;
    10.         public Transform enemy;
    11.         public int count;
    12.         public float spawnRate;
    13.     }
    14.  
    15.     public float timeBetweenWaves = 5f;
    16.  
    17.     private GameObject[] SpawnPoints;
    18.     public Wave[] Waves;
    19.  
    20.     public bool enemiesAlive = false;
    21.     public bool spawning = false;
    22.     private static float _waveCountdown = 0f;
    23.     public static float waveCountdown {
    24.         get { return _waveCountdown; }
    25.         set { _waveCountdown = Mathf.Clamp (value, 0, Mathf.Infinity); }
    26.     }
    27.  
    28.     public static int waveNumber = 1;
    29.  
    30.     int waveIndex = 0;
    31.  
    32.     void Start () {
    33.         waveNumber = 1;
    34.         waveCountdown = 5;
    35.  
    36.         SpawnPoints = GameObject.FindGameObjectsWithTag ("EnemySpawnPoint");
    37.  
    38.         InvokeRepeating ("WaveTracker", 0f, 1f);
    39.     }
    40.  
    41.     void WaveTracker () {
    42.         if (waveCountdown == 0 && !spawning) {
    43.             if (GameObject.FindGameObjectsWithTag ("Enemy").Length == 0) {
    44.                 enemiesAlive = false;
    45.                 waveCountdown = timeBetweenWaves;
    46.                 waveNumber++;
    47.             }
    48.         }
    49.     }
    50.  
    51.     void Update () {
    52.         waveCountdown -= Time.deltaTime;
    53.         if (waveCountdown == 0 && enemiesAlive == false) {
    54.             StartCoroutine ( SpawnWave ( Waves[waveIndex] ) );
    55.             return;
    56.         }
    57.     }
    58.  
    59.     public IEnumerator SpawnWave (Wave wave) {
    60.  
    61.         enemiesAlive = true;
    62.         spawning = true;
    63.  
    64.         yield return new WaitForSeconds (2f);
    65.  
    66.         for (int i = 0; i < wave.count; i++)
    67.         {
    68.             int spawnIndex = Random.Range (0, SpawnPoints.Length);
    69.             Transform enemy = Instantiate (wave.enemy, SpawnPoints[spawnIndex].transform.position, SpawnPoints[spawnIndex].transform.rotation) as Transform;
    70.             yield return new WaitForSeconds (1f/wave.spawnRate);
    71.         }
    72.         if (waveIndex < Waves.Length - 1) //Calls next wave
    73.         {
    74.             waveIndex++;
    75.         }
    76.         else
    77.         {
    78.             waveIndex = 0;
    79.         }
    80.  
    81.         spawning = false;
    82.     }
    83. }
    My adapted script:

    Code (CSharp):
    1. using UnityEngine;
    2. using System.Collections;
    3. using System.Collections.Generic;
    4.  
    5. public class WaveController : MonoBehaviour {
    6.  
    7.     [System.Serializable]
    8.     public class Wave {
    9.         List<WaveAction> actions;
    10.     }
    11.  
    12.     [System.Serializable]
    13.     public class WaveAction {
    14.         public string name;
    15.         public Transform enemy;
    16.         public int count;
    17.         public float spawnRate;
    18.     }
    19.  
    20.     public float timeBetweenWaves = 5f;
    21.  
    22.     private GameObject[] SpawnPoints;
    23.     public Wave[] Waves; //Creates array
    24.  
    25.     public bool enemiesAlive = false;
    26.     public bool spawning = false;
    27.     private static float _waveCountdown = 0f;
    28.     public static float waveCountdown {
    29.         get { return _waveCountdown; }
    30.         set { _waveCountdown = Mathf.Clamp (value, 0, Mathf.Infinity); }
    31.     }
    32.  
    33.     public static int waveNumber = 1;
    34.  
    35.     int waveIndex = 0;
    36.  
    37.     void Start () {
    38.         waveNumber = 1;
    39.         waveCountdown = 5;
    40.  
    41.         SpawnPoints = GameObject.FindGameObjectsWithTag ("EnemySpawnPoint");
    42.  
    43.         InvokeRepeating ("WaveTracker", 0f, 1f);
    44.     }
    45.  
    46.     void WaveTracker () {
    47.         if (waveCountdown == 0 && !spawning) {
    48.             if (GameObject.FindGameObjectsWithTag ("Enemy").Length == 0) {
    49.                 enemiesAlive = false;
    50.                 waveCountdown = timeBetweenWaves;
    51.                 waveNumber++;
    52.             }
    53.         }
    54.     }
    55.  
    56.     void Update () {
    57.         waveCountdown -= Time.deltaTime;
    58.         if (waveCountdown == 0 && enemiesAlive == false) {
    59.             StartCoroutine ( SpawnWave ( Waves[waveIndex] ) );
    60.             return;
    61.         }
    62.     }
    63.  
    64.     public IEnumerator SpawnWave (WaveAction wave) {
    65.  
    66.         enemiesAlive = true;
    67.         spawning = true;
    68.  
    69.         yield return new WaitForSeconds (2f);
    70.  
    71.         for (int i = 0; i < wave.count; i++)
    72.         {
    73.             int spawnIndex = Random.Range (0, SpawnPoints.Length);
    74.             Transform enemy = Instantiate (wave.enemy, SpawnPoints[spawnIndex].transform.position, SpawnPoints[spawnIndex].transform.rotation) as Transform;
    75.             yield return new WaitForSeconds (1f/wave.spawnRate);
    76.         }
    77.         if (waveIndex < Waves.Length - 1) //Calls next wave
    78.         {
    79.             waveIndex++;
    80.         }
    81.         else
    82.         {
    83.             waveIndex = 0;
    84.         }
    85.  
    86.         spawning = false;
    87.     }
    88. }
     
  2. Brathnann

    Brathnann

    Joined:
    Aug 12, 2014
    Posts:
    7,144
    What are the errors exactly? Don't just link codes, copy the error over.

    I see your issue. Your coroutine takes a waveaction but you're passing in a wave. So either your coroutine needs to take the wave or your parameter has to pass in the waveaction list from the wave you are getting.
     
  3. MD_Reptile

    MD_Reptile

    Joined:
    Jan 19, 2012
    Posts:
    2,663
    Your giving the coroutine method parameter as a "wave" type, but the method wants a "waveaction" type.
     
  4. Flynn_Prime

    Flynn_Prime

    Joined:
    Apr 26, 2017
    Posts:
    383
    Thanks for the replies. The errors are; "The best overload match for 'WaveController.SpawnWave(WaveController.WaveAction)' has some invalid arguments" and "Argument #1 cannot convert 'WaveController.Wave' expression to type 'WaveController.WaveAction'

    How do I pass in the waveaction list? I thought that's what I had done
     
  5. Brathnann

    Brathnann

    Joined:
    Aug 12, 2014
    Posts:
    7,144
    StartCoroutine ( SpawnWave ( Waves[waveIndex].actions[actionIndex] ) );
    Make actions public also.

    Updated as @MD_Reptile is correct for a single waveaction instead of the list.
     
    Last edited: May 15, 2017
  6. MD_Reptile

    MD_Reptile

    Joined:
    Jan 19, 2012
    Posts:
    2,663
    Waves [index].actions is a list of waveactions, so it'll actually be something like Waves [index].actions [actionIndex] that would need to be given as the parameter to the coroutine I think.
     
  7. Flynn_Prime

    Flynn_Prime

    Joined:
    Apr 26, 2017
    Posts:
    383
    Okay I think i'm getting there slowly. This is what I currently have:

    Code (CSharp):
    1.     if (actionIndex < WaveController.WaveAction.count - 1)
    2.         {
    3.             actionIndex++;
    4.         }
    5.         else
    6.         {
    7.             if (waveIndex < Waves.Length - 1) //Calls next wave
    8.             {
    9.                 waveIndex++;
    10.             }
    11.             else
    12.             {
    13.                 waveIndex = 0;
    14.             }
    15.         }
    I think that is correct (almost), but I get error CS0120: an object reference is required to access non-static member...

    I have tried
    Code (CSharp):
    1. gameObject.GetComponent<WaveController>().WaveAction.count
    , and a few other variations but they all throw up similar errors. What is the correct way to reference the list in this class? Thanks in advance[/code]
     
  8. WheresMommy

    WheresMommy

    Joined:
    Oct 4, 2012
    Posts:
    890
    Might be a stupid tip, but is count the right way to call it. Did you try Count instead? Could you post your current up to date script and tell us, on which line the error gets called.
     
  9. Flynn_Prime

    Flynn_Prime

    Joined:
    Apr 26, 2017
    Posts:
    383
    I just realised this too, so not stupid at all! count is one of my variables so it didn't even throw an error. But 'Count' is not recognised, so I imagine I am missing something up to 'Using...'. Here's my script currently:

    Code (CSharp):
    1. using UnityEngine;
    2. using System.Collections;
    3. using System.Collections.Generic;
    4.  
    5. public class WaveController : MonoBehaviour {
    6.  
    7.     [System.Serializable]
    8.     public class Wave {
    9.         public string name;
    10.         public List<WaveAction> actions;
    11.     }
    12.  
    13.     [System.Serializable]
    14.     public class WaveAction {
    15.         public string name;
    16.         public Transform enemy;
    17.         public int count;
    18.         public float spawnRate;
    19.     }
    20.  
    21.     public float timeBetweenWaves = 5f;
    22.  
    23.     private GameObject[] SpawnPoints;
    24.     public Wave[] Waves; //Creates array
    25.  
    26.     public bool enemiesAlive = false;
    27.     public bool spawning = false;
    28.     private static float _waveCountdown = 0f;
    29.     public static float waveCountdown {
    30.         get { return _waveCountdown; }
    31.         set { _waveCountdown = Mathf.Clamp (value, 0, Mathf.Infinity); }
    32.     }
    33.  
    34.     public static int waveNumber = 1;
    35.  
    36.     int waveIndex = 0;
    37.     int actionIndex = 0;
    38.  
    39.     void Start () {
    40.         waveNumber = 1;
    41.         waveCountdown = 5;
    42.  
    43.         SpawnPoints = GameObject.FindGameObjectsWithTag ("EnemySpawnPoint");
    44.  
    45.         InvokeRepeating ("WaveTracker", 0f, 1f);
    46.     }
    47.  
    48.     void WaveTracker () {
    49.         if (waveCountdown == 0 && !spawning) {
    50.             if (GameObject.FindGameObjectsWithTag ("Enemy").Length == 0) {
    51.                 enemiesAlive = false;
    52.                 waveCountdown = timeBetweenWaves;
    53.                 waveNumber++;
    54.             }  
    55.         }
    56.     }
    57.  
    58.     void Update () {
    59.         waveCountdown -= Time.deltaTime;
    60.         if (waveCountdown == 0 && enemiesAlive == false) {
    61.             StartCoroutine ( SpawnWave ( Waves[waveIndex].actions[actionIndex] ) );
    62.             return;
    63.         }
    64.     }
    65.  
    66.     public IEnumerator SpawnWave (WaveAction wave) {
    67.  
    68.         enemiesAlive = true;
    69.         spawning = true;
    70.  
    71.         yield return new WaitForSeconds (2f);
    72.  
    73.         for (int i = 0; i < wave.count; i++)
    74.         {
    75.             int spawnIndex = Random.Range (0, SpawnPoints.Length);
    76.             Transform enemy = Instantiate (wave.enemy, SpawnPoints[spawnIndex].transform.position, SpawnPoints[spawnIndex].transform.rotation) as Transform;
    77.             yield return new WaitForSeconds (1f/wave.spawnRate);
    78.         }
    79.         if (actionIndex < WaveController.WaveAction.Count - 1)
    80.         {
    81.             actionIndex++;
    82.         }
    83.         else
    84.         {
    85.             if (waveIndex < Waves.Length - 1) //Calls next wave
    86.             {
    87.                 waveIndex++;
    88.             }
    89.             else
    90.             {
    91.                 waveIndex = 0;
    92.             }
    93.         }
    94.  
    95.         spawning = false;
    96.     }
    97. }
    The only error I get for this is CS0117: 'WaveController.WaveAction does not contain a definition for Count.

    Not sure why this is because I thought Lists were a part of System.Collections.Generic?
     
  10. WheresMommy

    WheresMommy

    Joined:
    Oct 4, 2012
    Posts:
    890
    Okay, but your WaveAction class is not a list, it is a class. So what happens if you are calling count on lower case, whats the error there?
     
  11. Flynn_Prime

    Flynn_Prime

    Joined:
    Apr 26, 2017
    Posts:
    383
    Same line except a no object reference error instead.

    But I have a list made from the wave action class. Is that not the same thing? Maybe the problem is it think I am referencing the class instead. But in that case, how can I reference the list instead?

    EDIT: I'll try WaveController.Wave.WaveAction.Count when I get the chance. Think that may be correct way to reference the list.
     
    Last edited: May 15, 2017
  12. WheresMommy

    WheresMommy

    Joined:
    Oct 4, 2012
    Posts:
    890
    So as far as I can see, the actions is the list, so the actions do have Count. Actions is the list of waveactions. So, if you are trying to call the wave in that list, you have to call actions[0] for the first item for example.
     
  13. Flynn_Prime

    Flynn_Prime

    Joined:
    Apr 26, 2017
    Posts:
    383
    Cheers for the reply again. I already set actionIndex = 0 before my methods, and call on that first. Then it should iterate through the list via actionIndex++
     
  14. Brathnann

    Brathnann

    Joined:
    Aug 12, 2014
    Posts:
    7,144
    It might be this.

    Code (CSharp):
    1. if (actionIndex < WaveController.WaveAction.Count - 1)
    2.         {
    3.             actionIndex++;
    4.         }
    I'm thinking you want to check

    Code (CSharp):
    1. Waves[waveIndex].actions.Count
    instead. If you're going through the actionlist per wave, that makes more sense.
     
  15. Flynn_Prime

    Flynn_Prime

    Joined:
    Apr 26, 2017
    Posts:
    383
    And is that because you have to specify you are checking that list within the array rather than just the list itself? Sounds promising, I'll let you know the results. Cheers
     
  16. Flynn_Prime

    Flynn_Prime

    Joined:
    Apr 26, 2017
    Posts:
    383
    I tried this. I set up 3 waves; Wave 1: 5 x Enemy1, Wave 2: 5x Enemy2, Wave3: 5x Enemy1 + 5xEnemy2.

    It goes through waves 1 and 2 with no problem. Then on wave 3 the first 5x Enemy1's spawn fine, but then it goes to Wave 4 and spawns 5x Enemy2. These should have spawned at the same time, and in the same wave.

    After the final wave finishes it doesn't loop back round anymore either, so I've broken it even further it appears. It continues to countdown new waves one after the other whilst generating multiple error code:

    ArgumentOutOfRangeException: Argument is out of range.
    Parameter name: index
    System.Collections.Generic.List`1[WaveController+WaveAction].get_Item (Int32 index) (at /Users/builduser/buildslave/mono/build/mcs/class/corlib/System.Collections.Generic/List.cs:633)
    WaveController.Update () (at Assets/_MyProject/Scripts/Spawning/WaveController.cs:65)
     
  17. Brathnann

    Brathnann

    Joined:
    Aug 12, 2014
    Posts:
    7,144
    Honestly, your script seems really complicated for what it's suppose to do, which I suspect is part of the bugs you are encountering. (and also why debugging it is a bit difficult).

    Argument out of range means you're trying to access an index in your list that doesn't exist. So if you have 10 items in your list and you want to access item 11 (or index 10), you'll get that error.
     
  18. Flynn_Prime

    Flynn_Prime

    Joined:
    Apr 26, 2017
    Posts:
    383
    Managed to fix the error. It now loops through everything, with all enemies. But it still counts seperate enemies as a new wave (so as above, Wave3 gets split into 2 seperate waves). New code:

    Code (CSharp):
    1. if (actionIndex < Waves [waveIndex].actions.Count - 1) { //Calls next action
    2.             actionIndex++;
    3.         } else {
    4.             actionIndex = 0;
    5.             if (waveIndex < Waves.Length - 1) { //Call next wave
    6.                 waveIndex++;
    7.             } else {
    8.                 waveIndex = 0;
    9.             }
    10.         }
     
  19. Flynn_Prime

    Flynn_Prime

    Joined:
    Apr 26, 2017
    Posts:
    383
    Hmm, to be honest this was one of the simpler spawners that I have seen, hence why I chose to work with it. I have seen simpler but with limited capability in terms of waves and spawning multiple enemy types. It's my lack of knowledge of lists and arrays that is causing me the trouble. A lot of what I am doing is trial and error
     
  20. Flynn_Prime

    Flynn_Prime

    Joined:
    Apr 26, 2017
    Posts:
    383
    Fixed it. The problem was the arguments for the end of a wave. Just had to re-adjust them a little:

    Code (CSharp):
    1. void WaveTracker () {
    2.         if (waveCountdown == 0 && !spawning) {
    3.             if (GameObject.FindGameObjectsWithTag ("Enemy").Length == 0) {
    4.                 enemiesAlive = false;
    5.                 if (actionIndex == 0) {
    6.                     waveCountdown = timeBetweenWaves;
    7.                     waveNumber++;
    8.                 }
    9.             }  
    10.         }
    and:

    Code (CSharp):
    1. if (actionIndex < Waves [waveIndex].actions.Count - 1) { //Calls next action
    2.             actionIndex++;
    3.         } else {
    4.             actionIndex = 0;
    5.             if (waveIndex < Waves.Length - 1) { //Call next wave
    6.                 waveIndex++;
    7.             } else {
    8.                 waveIndex = 0;
    9.                 //multiplier *= 2f; //Used for difficulty increase
    10.             }
    11.         }
    Sorry for the bombardment during this. I will try and simplify this in the future. Hopefully it can help someone else along the way too...
     
    Last edited: May 15, 2017
  21. WheresMommy

    WheresMommy

    Joined:
    Oct 4, 2012
    Posts:
    890
    So from what i have seen, waveIndex starts at 0, your Count starts at 0, so you are saying for example:
    Lets say, you got a count of 5, and you are starting with wave 1 which is codewise 0, that means, if I add 5 waves to it, it says 4 < 5-1, which cant work, right? You should start with waveIndex of 1 to be clear with the actual name of your waves. Just a thought.

    Another question. How do you create your waves? Do you have a screenshot or something of that?
     
  22. WheresMommy

    WheresMommy

    Joined:
    Oct 4, 2012
    Posts:
    890
    Oh, too late :D oh, if you figured it out, great :)
     
  23. Flynn_Prime

    Flynn_Prime

    Joined:
    Apr 26, 2017
    Posts:
    383
    Aha, thanks for the input again anyway, it's always appreciated. What you say is a good idea either way actually, as it just avoids confusion. My next aim is to make it so Enemy1 and Enemy2 spawn together as currently, you have to kill all of Enemy1 before Enemy2 will spawn (even though they are the same wave).
     
  24. WheresMommy

    WheresMommy

    Joined:
    Oct 4, 2012
    Posts:
    890
    That should not be a big of a problem. Did you Debug.Log this part to see if it gets called at all? Because that would explain, why the next wave gets called.

    Code (CSharp):
    1. if (actionIndex < WaveController.WaveAction.Count - 1)
    2.         {
    3.             actionIndex++;
    4.         }
     
  25. WheresMommy

    WheresMommy

    Joined:
    Oct 4, 2012
    Posts:
    890
    Okay, you are calling the wrong wave. WaveController.WaveAction calls just the class, not the actual object that has been created. Seems like there is some confusion in your head ;) You just create like a structure in your script. In the inspector you then create placeholders for this structure and fill them with your stuff. And so you can access them with their position inside your array.

    As you are passing the wav variable into the function, you can use its actions array to check the count.

    Code (CSharp):
    1. if (actionIndex < wave.actions.Count - 1)
    2.         {
    3.             actionIndex++;
    4.         }
     
  26. Flynn_Prime

    Flynn_Prime

    Joined:
    Apr 26, 2017
    Posts:
    383
    Tried this before, and it didn't work. I think you misunderstand the issue I'm having now though; the waves are working fine. They increment as they are supposed to, and the correct enemies spawn.

    But say on Wave1 I have two 'actions' (Enemy1 and Enemy2). Enemy2 will not spawn until after all of Enemy1 are dead. Trying to figure a work around now as I think it's due to the positioning of 'spawning = false', although I fear everything we have discussed may have been in vain as it could also be the way in which I am incrementing 'actions' rather than calling on all actions simultaneously...
     
  27. Flynn_Prime

    Flynn_Prime

    Joined:
    Apr 26, 2017
    Posts:
    383
  28. WheresMommy

    WheresMommy

    Joined:
    Oct 4, 2012
    Posts:
    890
    Ohh, got ya. So you want your actions to take place after an amount of time not when the action before is done. I think, what someone else said before, your spawn thing is quite complicated in the thought of maintenance and expandability. You should have a function that handles your waves, like when is what wave called. And then you should have a function that handles the actions inside those waves. So if the wave gets called, iterate through the actions, set the delays etc. etc.
     
  29. Flynn_Prime

    Flynn_Prime

    Joined:
    Apr 26, 2017
    Posts:
    383
    Back to the drawing board then I guess :D . Thanks again bud
     
  30. AlejandroBoss10

    AlejandroBoss10

    Joined:
    Sep 1, 2017
    Posts:
    7
    I know that this is a pretty old thread, but were you able to get it so that all of the enemies spawned at the same time?
     
  31. Flynn_Prime

    Flynn_Prime

    Joined:
    Apr 26, 2017
    Posts:
    383
    In all honesty, I can't remember. I was just playing around with different bits at this point. The code I was writing wasn't very good at all. I have just started writing another game and will need to make a spawner for it at some point soon. I'll keep you in the loop if you wish. Also, feel free to pm me your script and any dramas and I'll help where I can.
     
    MD_Reptile likes this.