This game began as the final assignment for my Simulation and Game Development class. Initially this game was a linear top down zombie shooter in which the player had to traverse through various zones while fighting zombies in order to make it to the end.
Since graduation I have returned to this project completely revamping it into a wave based shooter with an economy and upgrade system. I have been using my work on this game to push myself to learn more about game development with the aim to turn this project into a complete game that I plan to publish for mobile.
Using this game I have learned about object pooling, scriptable objects, animation, lighting, post-processing, optimization for mobile and more.
From the early build to present
(Note this game is not targeted for WebGl, It is recommended to play the Windows or Android builds for best performance, or reduce window size)
UnityC#
The game makes use of a custom spawner that utilizes object pooling shared among all the enemy spawners. These spawners are customizable in the editor to cover any area. Enemies will only spawn when the player is in range and despawn after the player has left range for a set period of time.
private void Spawn()
{
spawnAttempts = 0;
do
{
//Track how many attempts are made to find a valid spawn position
spawnAttempts++;
//Create a random spawn point within the spawn zone
nextSpawnPosition = spawnAreaCenter + new Vector3(Random.Range(-spawnAreaSize.x / 2, spawnAreaSize.x / 2), 0, Random.Range(-spawnAreaSize.z / 2, spawnAreaSize.z / 2));
//Use a raycast sphere with the zombies radius to check that the spawn point is clear of other objects
ray = new Ray(transform.position + new Vector3(nextSpawnPosition.x, 10, nextSpawnPosition.z), Vector3.down);
//Start from Ray pos, radius, output hit, distance, layers to hit
isSpawnPointInvalid = Physics.SphereCast(ray, 0.5f, 12, nonSpawnableLayers);
//If there have been too many unsuccesful attempts to find a valid spawn pos return
if (spawnAttempts > spawnAttemptLimt)
{
Debug.Log($"{gameObject.name} had {spawnAttemptLimt} failed spawn attempts");
return;
}
} while (isSpawnPointInvalid);
//Spawn Zombie
PoolableObject instance = WaveManager.Instance.zombiePool.GetObject();
if (instance != null)
{
//Assign zombie stats
instance.GetComponent<ZombieHealth>().stats = stats;
instance.GetComponent<ZombieHealth>().enabled = true;
instance.GetComponent<ZombieMovement>().stats = stats;
//Set zombie as child to spawner
instance.transform.SetParent(transform, false);
//Move zombie to spawn point
instance.transform.localPosition = new Vector3(nextSpawnPosition.x, 0, nextSpawnPosition.z);
lastSpawnTime = Time.time;
}
WaveManager.Instance.EnemySpawned(1);
}
The game makes use of a custom event system that allows events to be created as scriptable objects. This method allows both the broadcaster and any listeners to be compleatly detached from each other.
The game contains five different resources, cash, wood, scraps, gas & energy. To get the differnt materials the player will have to play each level and survive as long as they can. At the camp the player has access to differnt shops to purchase upgrades ranging from health and defence upgrades to firing speed and damage upgrades with more planned for the future.
As the player purchases more upgrades, their cost will increase and eventually require different resources, thus in order to max out an upgrade the player will have to have unlocked access to each level.