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

Tower Defence creep-spawning problems

Discussion in 'Scripting' started by cneeson, Nov 5, 2014.

  1. cneeson

    cneeson

    Joined:
    Nov 5, 2014
    Posts:
    3
    Hi all, I have been working on a small TD game for a while now and am struggling with a good way to spawn in my creeps after a delay (it is worth mentioning and probably obvious, that I am new to Unity.)

    The CreepManager class below uses a switch statement to determine which creep gameObject (from an array) is due to be spawned in. I believe the invoke delay is working but am unsure, the main problem lies in that instead of the switch statement starting the movement of each individual creep, one after they other, they all go at once and as a result clip through one another.

    I am aware that much of the code (particularly in the switch statement) and is optimized and untidy, but will be sorted out later after my core functionality is down.

    Help anyone could provide would be great and should you have any questions do not hesitate to ask! Thanks

    Code (CSharp):
    1. using UnityEngine;
    2. using System.Collections;
    3.  
    4. public class CreepManager : MonoBehaviour {
    5.  
    6.     public static bool beginNextRound;
    7.  
    8.     // Use this for initialization
    9.     void Start ()
    10.     {
    11.         beginNextRound = false;
    12.     }
    13.  
    14.     // Update is called once per frame
    15.     void Update ()
    16.     {
    17.         if(beginNextRound == true)
    18.         {
    19.             if(GameController.nextCreep <= 9)
    20.             {
    21.                 //spawn next creep
    22.                 Invoke("sendNextCreep", 4);
    23.             }
    24.         }
    25.         else
    26.         {
    27.             GameController.nextCreep = 0;
    28.         }
    29.     }
    30.  
    31.     void sendNextCreep()
    32.     {
    33.         switch(GameController.nextCreep)
    34.         {
    35.         case 0:
    36.             GameController.creepsOnMap[0].renderer.enabled = true;
    37.             GameController.creepsOnMap[0].GetComponent<Creep>().startMovement();
    38.             print ("creep" + GameController.nextCreep + " has started moving");
    39.             GameController.nextCreep = 1;
    40.             break;
    41.         case 1:
    42.             GameController.creepsOnMap[1].renderer.enabled = true;
    43.             GameController.creepsOnMap[1].GetComponent<Creep>().startMovement();
    44.             print ("creep" + GameController.nextCreep + " has started moving");
    45.             GameController.nextCreep = 2;
    46.             break;
    47.         case 2:
    48.             GameController.creepsOnMap[2].renderer.enabled = true;
    49.             GameController.creepsOnMap[2].GetComponent<Creep>().startMovement();
    50.             print ("creep" + GameController.nextCreep + " has started moving");
    51.             GameController.nextCreep = 3;
    52.             break;
    53.         case 3:
    54.             GameController.creepsOnMap[3].renderer.enabled = true;
    55.             GameController.creepsOnMap[3].GetComponent<Creep>().startMovement();
    56.             print ("creep" + GameController.nextCreep + " has started moving");
    57.             GameController.nextCreep = 4;
    58.             break;
    59.         case 4:
    60.             GameController.creepsOnMap[4].renderer.enabled = true;
    61.             GameController.creepsOnMap[4].GetComponent<Creep>().startMovement();
    62.             print ("creep" + GameController.nextCreep + " has started moving");
    63.             GameController.nextCreep = 5;
    64.             break;
    65.         case 5:
    66.             GameController.creepsOnMap[5].renderer.enabled = true;
    67.             GameController.creepsOnMap[5].GetComponent<Creep>().startMovement();
    68.             print ("creep" + GameController.nextCreep + " has started moving");
    69.             GameController.nextCreep = 6;
    70.             break;
    71.         case 6:
    72.             GameController.creepsOnMap[6].renderer.enabled = true;
    73.             GameController.creepsOnMap[6].GetComponent<Creep>().startMovement();
    74.             print ("creep" + GameController.nextCreep + " has started moving");
    75.             GameController.nextCreep = 7;
    76.             break;
    77.         case 7:
    78.             GameController.creepsOnMap[7].renderer.enabled = true;
    79.             GameController.creepsOnMap[7].GetComponent<Creep>().startMovement();
    80.             print ("creep" + GameController.nextCreep + " has started moving");
    81.             GameController.nextCreep = 8;
    82.             break;
    83.         case 8:
    84.             GameController.creepsOnMap[8].renderer.enabled = true;
    85.             GameController.creepsOnMap[8].GetComponent<Creep>().startMovement();
    86.             print ("creep" + GameController.nextCreep + " has started moving");
    87.             GameController.nextCreep = 9;
    88.             break;
    89.         case 9:
    90.             GameController.creepsOnMap[9].renderer.enabled = true;
    91.             GameController.creepsOnMap[9].GetComponent<Creep>().startMovement();
    92.             print ("creep" + GameController.nextCreep + " has started moving");
    93.             //closes the loop until next wave
    94.             GameController.nextCreep = 0;
    95.             beginNextRound = false;
    96.             break;
    97.         default:
    98.             print ("problem within CreepManager's switch statement!");
    99.             beginNextRound = false;
    100.             break;
    101.         }
    102.  
    103.  
    104.      
    105.     }
    106.  
    107. }
    108.  
     
  2. Fluzing

    Fluzing

    Joined:
    Apr 5, 2013
    Posts:
    815
    What I understand from your code, is that you already have all the creeps placed on the map and activate them when needed. Why not use Instantiate instead?
     
    JoeStrout likes this.
  3. JoeStrout

    JoeStrout

    Joined:
    Jan 14, 2011
    Posts:
    9,840
    Yes, @Fluzing is right, you should Instantiate a prefab for each creep rather than hiding and then activating them.

    But moreover, I will try to explain why they're all spawning at once... or nearly so. That Update() method fires 60 times per second or so. And on each call, you Invoke the sendNextCreep method. So on frame 0, you schedule sendNextCreep for 4 seconds later. Then on frame 1 (1/60th of a second later), you schedule sendNextCreep for 4 seconds later than that. Then again on frame 2, frame 3, etc... by the time 4 seconds have passed, you've scheduled 4*60=240 sendNextCreep calls!

    So. Beginners (and sometimes non-beginners too) often reach for Invoke or coroutines when wanting to delay or do something periodically in Unity. I think that's making life more complicated than it really should be. Here's what I recommend instead:

    Watch the clock. (And by "clock," I mean Time.time.)

    Just add a float property to your script called "nextThingTime" (name this according to whatever it does, like "nextSpawnTime" in your case). Set this to Time.time + 4 (or whatever) in your Start() method. Then in your Update method, you simply check whether that time has passed yet:

    Code (CSharp):
    1. void Update() {
    2.    if (Time.time > nextSpawnTime) {
    3.       SendNextCreep();
    4.       nextSpawnTime = Time.time + 4;
    5.    }
    6. }
    Simple, right? And very hard to mess up. You just have to be sure you reset your nextThingTime (whatever that is) whenever you do your next thing.
     
    cneeson likes this.
  4. cneeson

    cneeson

    Joined:
    Nov 5, 2014
    Posts:
    3
    Hi Fluzing thanks for your reply, indeed all of the creeps have been spawned in the same location on the map, this is the second solution I came up with for the spawning system because the first did involve instantiating each creep on the fly.

    The reason I abandoned this (it partially worked) was mainly due to frustration and the fact that my deadline is creeping closer and closer.

    This new one uses the same ten creeps for each wave, when they get to the base (or are destroyed), their position is reset to spawn again and meshRenderer switched off until next wave.

    Also sorry if difficult to understand :D
     
  5. slay_mithos

    slay_mithos

    Joined:
    Nov 5, 2014
    Posts:
    130
    Code (CSharp):
    1. void Update ()
    2.     {
    3.         if(beginNextRound == true)
    4.         {
    5.             if(GameController.nextCreep <= 9)
    6.             {
    7.                 //spawn next creep
    8.                 Invoke("sendNextCreep", 4);
    9.                 beginNextRound = false; //Do set it to "true" when you need to spawn an other round.
    10.             }
    11.         }
    12.         else
    13.         {
    14.             GameController.nextCreep = 0;
    15.         }
    16.     }
    The main problem I see in that code is that beginNextRound is true untill you spawned the last wave, meaning that it will keep spawning waves.

    You might also put the beginNextRound variable as a public static one in GameController, just like the "nextCreep" one, because I suspect that the logic for deciding when to send the wave is in GameController.
     
    cneeson likes this.