Contents:

Super Basic Zombie Spawner

For testing the base zombie, we shall be making a super basic zombie spawner. It will just take the amount of rows on the base Grid, and spawn a zombie randomly between a set amount of seconds.

IEnumerator spawnZombo()
    {
        while (zombieCounter < maxZombieCount)
        {
            yield return new WaitForSeconds(delayBetweenSpawns);

            Zombie newZombie = Instantiate(zombiePrefab, transform, false);
            newZombie.transform.position = new Vector3(gridGenerator.gridWidth + 5, 0.5f, Random.Range(0, gridGenerator.gridHeight));
            zombieCounter++;
        }
    }

Now we can test the system!

The test works but the colliders suck!

The test works but the colliders suck!

Much better collisions and a great demo test.

Much better collisions and a great demo test.

The Core Zombie Spawner

Now we are onto the big guns. Looking at the logic from the original game we can see that the Zombies spawned each Wave are always the same, but the locations can be random. Therefore, the Wave System we create must incorporate this into its logic.

Using Scriptable Objects again, we can create Waves that have the data of the Zombies stored as Segments.

[Serializable]
[CreateAssetMenu(fileName = "Wave", menuName = "PvZRemake/Wave/New Wave", order = 1)]
public class Wave : ScriptableObject
{
    public string waveNumber;
    public float delayBetweenSegments; //Uses this OR if the wave is defeated to trigger the next.

    [Header("Wave Data")]
    public WaveSegment[] waveSegments;
}

[Serializable]
public class WaveSegment
{
    public Zombie[] zombiesInSegment;
}

Now we have a Wave Scriptable Object we can populate to create waves and Segments of these waves, and place this into a future WaveController. Each Segment represents the Zombies that will spawn in that segment and are separated by the delayBetweenSegments variable. Now, we need to use this to make the logic for the actual spawning system.

Untitled

We will again be using Coroutines to control the spawning, and separate the elements utilising the time delay.

'While the Wave is active, we must iterate through each Segment and spawn the Zombies which have been designated within this. We can do this using a ‘foreach’ statement for the zombies inside of a ‘forloop’ for the Segments.

IEnumerator GenerateWaves(WaveSegment[] segments)
    {
        while (waveIsActive)
        {
            for (int i = 0; i < segments.Length; ++i)
            {
                Zombie[] segmentZombies = segments[i].zombiesInSegment;

                foreach (Zombie zombie in segmentZombies)
                {
                    Zombie zombieSpawned = Instantiate(zombie, transform, true);
                    zombieSpawned.transform.parent = transform;
                    zombieSpawned.transform.position = new Vector3(gridGenerator.gridWidth + 3, 0.5f, Random.Range(0, gridGenerator.gridHeight));
                }

                if (i >= segments.Length - 1) 
                { 
                    waveIsActive = false; 
                    break; 
                }

                yield return new WaitForSeconds(currentWave.delayBetweenSegments);

            }
        }

        while (!waveIsActive)
        {
            yield return null;
        }
    }

Now let’s test, we should expect the following for Wave 1-1: