top of page
Screenshot 2025-02-05 142031.png

Project Overview

Engine: Unity 2022.3.43f1

​

Programming Language: C#

 

​Role: Game Developer and Game Designer

 

Duration: 3 weeks

​

Status: Complete​​

In this short demo clip you spawn in a grave yard nightmare. As you're fending off against the undead with different weapons and power ups at your disposal, your only objective is to survive as long as you can.

​

Click here to Play!

Gameplay Video

Design and Development

Purpose

I wanted to learn how to develop a survival first-person shooter, drawing heavy inspiration from Call of Duty: Black Ops Zombies. This project allowed me to gain valuable experience in creating enemy AI within a 3D environment, as well as developing mechanics such as power-ups and a weapon shop where players can purchase guns off the wall to aid in survival. Beyond game design, this project helped me grow as a programmer, requiring me to implement unique gameplay mechanics to enhance player engagement. To achieve a polished aesthetic, I utilized 3D assets from the Unity Asset Store, ensuring a visually immersive experience.

Game Mechanics

The gameplay is designed from a first-person perspective, focusing on gun mechanics. Players begin with a standard weapon, and each time they successfully shoot an enemy, their score increases, prompting an update to the user interface. The concept revolves around a simple game loop: players shoot to earn points, utilize those points to purchase weapons or power-ups, and eliminate enemies to ensure their survival.

My primary objective regarding the weapon shed was to create a straightforward system that allows players to utilize points earned from defeating enemies as currency to acquire superior firearms, thereby enhancing their chances of survival. While I accomplished this goal, I encountered several challenges that needed to be addressed in the process.

image.png
image.png

BuyTimeStop() is a custom function I programmed to slow down the game by setting the Time.timeScale to 0.25. Once that has started a Coroutine is activated at the same time to start the countdown for when the powerup ends.

image.png

To enable the functionality of my weapon shed, I devised an interaction system that utilizes a Raycast to determine whether a Game Object possesses a specific tag. If this condition is met, the player is able to interact with the object directly in front of them. The reticle serves as a visual indicator of interactable objects by changing colors, providing a clear visual cue, along with UI text that guides the player towards purchasing or interacting with the game objects.

At first when I used the newly developed mechanic it was very inconsistent. Actions wouldn't work as intended because my approach to developing this was very broad. I had everything on one long page of a script. I then created a Interface Script "IInteractable" that I can call on in my custom "Interact Script". This helped with a better work flow for developing other game mechanics that would be necessary for this, and I was able to split up my code into others scripts for the other interactable objects. By doing so I made it easier to still interact with objects, but now each object had its own interaction. Specifically for when the player has to buy power ups from the power up stations.

image.png

Combat

The player starts off with a default rifle weapon. I made it so that each weapon had their own characteristics. The cannon weapon does the highest damage but doesn't have as fast a fire rate as the other weapons. Also while the starter default weapon gives you a decent amount of ammunition. The 2nd rifle on the wall has a higher fire rate and does more damage, and can store more ammo.

When the player presses the shoot button the script will first check to see if the NextTimeToFire is a greater value. If so that the weapon will spawn a projectile.

I needed a script that would not just spawn bullets but projectiles based on the weapon equipped. I programmed it so that only when there at least 1 bullet the player can shoot. The script calls on the getAmmo() function which returns the current ammo amount available to fire. I made key variables like the BulletfireRate and NextTimeToFire variables. This helped me to apply specific key differences between the weapons in terms of damage and the spawn speed of the bullets. 

image.png

Enemy AI

Another reason for this project was learning how to create Enemy AI in a 3D game. There were some successful outcomes and some that are still currently being worked on.

image.png

Hunt() is a custom function I made for directing the AI to constantly face and move towards the player during the game when spawned.

In the Update() method I have it so that the enemy can get the component of the ScoreManagerScript. This was important due to the nature of the combat being that when the bullets collide with any enemy object it will increase the score points. 

​

If the enemy is hit it will display a particle indicating the enemy was indeed hit. While that is happening it also will start a coroutine for the StopHitParticle(). This is just to turn of the particles after a couple of seconds.

image.png

Every time a bullet collides with a enemy ai hit becomes true. It not only loses hp, but after hit being true I programmed it so that hit particles go off to help show the player that the bullet did collide with the enemy. Also if the the enemy dies from a bullet attack the players kill score goes up and they receive 15 points.

This was one of my greatest challenges in this project. When I was developing the enemy wave system I had a list of key things that needed to happen:

- Spawns Enemy at a specific rate

- Stops Spawning after a certain value of enemies are in game

- Make sure that when all enemies are eliminated the round updates

​

The SpawnEnemies() function checks to see if CanSpawn is true and if the spawn time is less than the current time. I wanted to make it so that when I return to this project I can have the option to make the spawning more randomized. Not just spawning your everyday zombie but also potentially adding ghouls and or skeletons. I created a variable that gets the random enemy objects and puts them in a list. I then created a variable for keeping track of random spawn points that can be accessed and used. This way now when the enemy ai spawns it will appear at random spawn points through out the map.

image.png
image.png

Once all enemies are destroyed the game will then change rounds. I also made it so that the number of enemies increase along with their movement speed increases as well with each passing round.

Game UI

When it came to placement I wanted it to be out of the way, but still very easy to understand what each sections purpose was. The health was placed in the top left with 3 health bars indicating the amount of hits the player can take. I put the round change on the far right corner so players can easily see the changing rounds. I stacked the score and ammo in the bottom left because if the players gun is on the far bottom right of the screen it'll be easier to read where their is empty negative space in the left corner. 

image.png

Whenever a bullet is fired the subAmmo() function is called in the weapon script. It subtracts the bullets used and updates the current ammo count.

AmmoManager is responsible for keep track and updating the ammo in game. I programmed the script to be able to display the current and max ammo available for each weapon equipped.

image.png

RoundManagerScript holds all the base function needed for keeping track and updating rounds. When the game starts the round always starts on 1. When all enemies are defeated the AddRound() is called in the EnemyWaveSpawner script.

image.png
image.png
image.png

ReticleScript helps to change the color of the ui. Indicating if a object is interactable or not. If so then through this, it allows for the player to actually activate these interactions.

image.png
bottom of page