Unity Zombie Game Complete Guide
Unity Zombie Game Complete Guide
Development Guide
Joel's Adventure: 6 Chapter Zombie Apocalypse Story
Table of Contents
1. Game Overview
2. Chapter Breakdown
3. Core Scripts
7. Troubleshooting
1. Game Overview
Story Synopsis:
Joel is a high school student who suddenly finds himself in a zombie apocalypse. Together with his
crush Andria, he must survive through 6 intense chapters, fighting zombies, escaping dangerous
situations, and ultimately finding safety at a ship factory by the sea.
Game Features:
Day/night cycle
Mechanics:
Mechanics:
Soldier AI assistance
Vehicle entry cutscene
Chapter 3: Boot Camp
Mechanics:
Vehicle driving
Fuel management
Day/night cycle
Wake up at 7 AM
Refuel jeep
Mechanics:
Time-based events
Long-distance driving
City exploration
Looting mechanics
Resource management
Chapter 5: Betrayal
Mechanics:
Cutscene trigger
Chapter 6: Escape
Location: Knight King Gang Base & Ship Factory
Key Events:
Mechanics:
Stealth elements
Final confrontation combat
Multiple enemy types (zombies + humans)
3. Core Scripts
3.1 PlayerController.cs
using UnityEngine;
[Header("Camera Settings")]
public Transform cameraTransform;
public float mouseSensitivity = 2f;
public float verticalLookLimit = 80f;
[Header("Combat")]
public int maxHealth = 100;
private int currentHealth;
void Start()
{
controller = GetComponent<CharacterController>();
currentHealth = maxHealth;
// Lock cursor
Cursor.lockState = CursorLockMode.Locked;
Cursor.visible = false;
}
void Update()
{
HandleMovement();
HandleCamera();
HandleJump();
}
void HandleMovement()
{
isGrounded = controller.isGrounded;
if (isGrounded && velocity.y < 0)
{
velocity.y = -2f;
}
// Get input
float horizontal = Input.GetAxis("Horizontal");
float vertical = Input.GetAxis("Vertical");
// Sprint
float currentSpeed = Input.GetKey(KeyCode.LeftShift) ? sprintSpeed : moveSpeed;
// Apply gravity
velocity.y += Physics.gravity.y * Time.deltaTime;
controller.Move(velocity * Time.deltaTime);
}
void HandleCamera()
{
// Mouse input
float mouseX = Input.GetAxis("Mouse X") * mouseSensitivity;
float mouseY = Input.GetAxis("Mouse Y") * mouseSensitivity;
void HandleJump()
{
if (Input.GetButtonDown("Jump") && isGrounded)
{
velocity.y = Mathf.Sqrt(jumpForce * -2f * Physics.gravity.y);
}
}
if (currentHealth <= 0)
{
Die();
}
}
void Die()
{
Debug.Log("Player Died!");
// Add death logic here
// Example: Reload scene or show game over screen
}
Usage Instructions:
3.2 ZombieAI.cs
using UnityEngine;
using UnityEngine.AI;
[Header("Combat")]
public int damage = 10;
public float attackCooldown = 1.5f;
public int maxHealth = 50;
void Start()
{
agent = GetComponent<NavMeshAgent>();
animator = GetComponent<Animator>();
player = GameObject.FindGameObjectWithTag("Player")?.transform;
currentHealth = maxHealth;
timer = wanderTimer;
}
void Update()
{
if (currentState == State.Dead) return;
switch (currentState)
{
case State.Idle:
HandleIdle();
break;
case State.Patrolling:
HandlePatrol();
break;
case State.Chasing:
HandleChase();
break;
case State.Attacking:
HandleAttack();
break;
}
void HandleIdle()
{
animator?.SetBool("isWalking", false);
timer += Time.deltaTime;
void HandlePatrol()
{
animator?.SetBool("isWalking", true);
NavMeshHit hit;
if (NavMesh.SamplePosition(randomDirection, out hit, wanderRadius, 1))
{
agent.SetDestination(hit.position);
}
}
}
void HandleChase()
{
animator?.SetBool("isWalking", true);
if (player)
{
agent.SetDestination(player.position);
}
}
void HandleAttack()
{
animator?.SetBool("isWalking", false);
animator?.SetTrigger("Attack");
agent.SetDestination(transform.position);
if (player)
{
Vector3 direction = (player.position - transform.position).normalized;
Quaternion lookRotation = Quaternion.LookRotation(new Vector3(direction.x, 0,
transform.rotation = Quaternion.Slerp(transform.rotation, lookRotation, Time.
void AttackPlayer()
{
if (player)
{
PlayerController playerController = player.GetComponent<PlayerController&g
if (playerController)
{
playerController.TakeDamage(damage);
}
}
}
if (currentHealth <= 0)
{
Die();
}
}
void Die()
{
currentState = State.Dead;
animator?.SetTrigger("Die");
agent.enabled = false;
Destroy(gameObject, 3f);
}
}
Required Components:
NavMeshAgent
Animator (with animations: Idle, Walk, Attack, Hit, Die)
Capsule Collider
Tag as "Enemy"
Animator Parameters:
Bool: isWalking
Trigger: Attack
Trigger: Hit
Trigger: Die
3.3 WeaponSystem.cs
using UnityEngine;
[Header("Weapon Type")]
public bool isAutomatic = true;
[Header("References")]
public Camera playerCamera;
public Transform shootPoint;
public ParticleSystem muzzleFlash;
public GameObject impactEffect;
void Start()
{
currentAmmo = maxAmmo;
}
void Update()
{
if (isReloading) return;
// Shooting
if (isAutomatic)
{
if (Input.GetButton("Fire1"))
{
Shoot();
}
}
else
{
if (Input.GetButtonDown("Fire1"))
{
Shoot();
}
}
// Reload
if (Input.GetKeyDown(KeyCode.R) && currentAmmo < maxAmmo)
{
Reload();
}
}
void Shoot()
{
if (Time.time < nextFireTime) return;
if (currentAmmo <= 0)
{
Debug.Log("Out of ammo!");
return;
}
nextFireTime = Time.time + fireRate;
currentAmmo--;
// Visual effects
if (muzzleFlash) muzzleFlash.Play();
// Raycast
RaycastHit hit;
if (Physics.Raycast(playerCamera.transform.position, playerCamera.transform.forwa
{
Debug.Log("Hit: " + hit.transform.name);
// Impact effect
if (impactEffect)
{
GameObject impact = Instantiate(impactEffect, hit.point, Quaternion.LookR
Destroy(impact, 2f);
}
}
}
void Reload()
{
if (reserveAmmo <= 0) return;
isReloading = true;
Debug.Log("Reloading...");
Invoke("CompleteReload", 2f);
}
void CompleteReload()
{
int ammoNeeded = maxAmmo - currentAmmo;
int ammoToReload = Mathf.Min(ammoNeeded, reserveAmmo);
currentAmmo += ammoToReload;
reserveAmmo -= ammoToReload;
isReloading = false;
Debug.Log("Reload complete!");
}
}
Setup:
using UnityEngine;
using UnityEngine.AI;
void Start()
{
agent = GetComponent<NavMeshAgent>();
animator = GetComponent<Animator>();
if (!player)
{
player = GameObject.FindGameObjectWithTag("Player")?.transform;
}
}
void Update()
{
if (!player) return;
animator?.SetBool("isWalking", false);
}
else
{
// Stay in place
agent.SetDestination(transform.position);
animator?.SetBool("isWalking", false);
}
}
}
3.5 InventorySystem.cs
using UnityEngine;
using System.Collections.Generic;
[System.Serializable]
public class InventoryItem
{
public string itemName;
public int quantity;
public Sprite icon;
[Header("Inventory")]
public List<InventoryItem> items = new List<InventoryItem>();
public int maxSlots = 20;
void Awake()
{
if (instance == null)
{
instance = this;
DontDestroyOnLoad(gameObject);
}
else
{
Destroy(gameObject);
}
}
if (existingItem != null)
{
existingItem.quantity += quantity;
Debug.Log($"Added {quantity} {itemName}(s). Total: {existingItem.quantity}");
return true;
}
Debug.Log("Inventory full!");
return false;
}
if (item.quantity <= 0)
{
items.Remove(item);
}
How to Use:
// Add items
InventorySystem.instance.AddItem("Food", 5);
InventorySystem.instance.AddItem("Ammo", 30);
// Remove items
InventorySystem.instance.RemoveItem("Food", 1);
Grenade.cs:
using UnityEngine;
[Header("Effects")]
public GameObject explosionEffect;
public AudioClip explosionSound;
void Start()
{
rb = GetComponent<Rigidbody>();
Invoke("Explode", explosionDelay);
}
void Explode()
{
if (hasExploded) return;
hasExploded = true;
// Play sound
if (explosionSound)
{
AudioSource.PlayClipAtPoint(explosionSound, transform.position);
}
Destroy(gameObject);
}
void OnDrawGizmosSelected()
{
Gizmos.color = Color.red;
Gizmos.DrawWireSphere(transform.position, explosionRadius);
}
}
GrenadeThrower.cs:
using UnityEngine;
void Update()
{
if (Input.GetKeyDown(KeyCode.G))
{
ThrowGrenade();
}
}
void ThrowGrenade()
{
if (grenadeCount <= 0)
{
Debug.Log("No grenades left!");
return;
}
grenadeCount--;
if (rb)
{
Vector3 throwDirection = throwPoint.forward + Vector3.up * throwUpwardForce;
rb.AddForce(throwDirection.normalized * throwForce, ForceMode.VelocityChange)
}
3.7 VehicleController.cs
using UnityEngine;
[Header("Vehicle Settings")]
public float motorForce = 1500f;
public float brakeForce = 3000f;
public float maxSteerAngle = 30f;
public float maxSpeed = 100f;
[Header("Fuel System")]
public float maxFuel = 100f;
public float currentFuel = 100f;
public float fuelConsumption = 0.1f;
void Update()
{
if (currentFuel <= 0)
{
Debug.Log("Out of fuel!");
return;
}
GetInput();
HandleMotor();
HandleSteering();
ConsumeFuel();
}
void GetInput()
{
float verticalInput = Input.GetAxis("Vertical");
float horizontalInput = Input.GetAxis("Horizontal");
frontLeftWheel.brakeTorque = currentBrakeForce;
frontRightWheel.brakeTorque = currentBrakeForce;
rearLeftWheel.brakeTorque = currentBrakeForce;
rearRightWheel.brakeTorque = currentBrakeForce;
}
void HandleSteering()
{
frontLeftWheel.steerAngle = currentSteerAngle;
frontRightWheel.steerAngle = currentSteerAngle;
}
void ConsumeFuel()
{
if (Mathf.Abs(currentMotorForce) > 0)
{
currentFuel -= fuelConsumption * Time.deltaTime;
currentFuel = Mathf.Max(0, currentFuel);
}
}
Vehicle Setup:
using UnityEngine;
using UnityEngine.UI;
using TMPro;
[Header("Player Reference")]
public PlayerController player;
void Update()
{
if (player)
{
int currentHealth = player.GetCurrentHealth();
if (healthBar)
{
healthBar.value = (float)currentHealth / player.maxHealth;
}
if (healthText)
{
healthText.text = $"Health: {currentHealth}/{player.maxHealth}";
}
}
}
}
4.2 AmmoUI.cs
using UnityEngine;
using TMPro;
[Header("Weapon Reference")]
public WeaponSystem weapon;
void Update()
{
if (weapon && ammoText)
{
ammoText.text = $"{weapon.currentAmmo} / {weapon.reserveAmmo}";
}
}
}
4.3 GameManager.cs
using UnityEngine;
using UnityEngine.SceneManagement;
[Header("Game State")]
public bool isPaused = false;
public int currentChapter = 1;
[Header("UI References")]
public GameObject pauseMenu;
public GameObject gameOverScreen;
void Awake()
{
if (instance == null)
{
instance = this;
DontDestroyOnLoad(gameObject);
}
else
{
Destroy(gameObject);
}
}
void Update()
{
if (Input.GetKeyDown(KeyCode.Escape))
{
TogglePause();
}
}
if (pauseMenu)
{
pauseMenu.SetActive(isPaused);
}
Time.timeScale = 0f;
Cursor.lockState = CursorLockMode.None;
Cursor.visible = true;
}
4.4 SceneTransition.cs
using UnityEngine;
using UnityEngine.SceneManagement;
using System.Collections;
void Start()
{
if (fadeCanvasGroup)
{
StartCoroutine(FadeIn());
}
}
IEnumerator FadeIn()
{
float elapsedTime = 0f;
fadeCanvasGroup.alpha = 0f;
}
IEnumerator FadeOut()
{
float elapsedTime = 0f;
fadeCanvasGroup.alpha = 1f;
}
}
4.5 Collectible.cs
using UnityEngine;
[Header("Rotation")]
public bool rotateItem = true;
public float rotationSpeed = 50f;
void Update()
{
if (rotateItem)
{
transform.Rotate(Vector3.up * rotationSpeed * Time.deltaTime);
}
}
case CollectibleType.Grenade:
GrenadeThrower grenadeThrower = player.GetComponent<GrenadeThrower>
if (grenadeThrower)
{
grenadeThrower.AddGrenades(quantity);
Debug.Log($"Collected {quantity} grenade(s)");
}
break;
case CollectibleType.Food:
if (InventorySystem.instance)
{
InventorySystem.instance.AddItem("Food", quantity);
}
break;
}
Destroy(gameObject);
}
}
5. Setup Instructions
2. Install TextMeshPro
Assets/
├── Scripts/
│ ├── Player/
│ ├── Enemy/
│ ├── Weapons/
│ ├── UI/
│ └── Managers/
├── Prefabs/
│ ├── Characters/
│ ├── Enemies/
│ ├── Weapons/
│ └── Items/
├── Scenes/
├── Materials/
├── Audio/
└── UI/
Name: "Player"
Tag: "Player"
2. Add Components:
Character Controller
PlayerController script
GrenadeThrower script
3. Create Camera:
1. Import Model:
Capsule Collider
ZombieAI script
Tag as "Enemy"
3. Setup Animator:
4. Save as Prefab:
Drag configured zombie to Prefabs folder
Agent Height: 2
Click "Bake"
5.5 UI Setup
Health Bar:
Ammo Display:
Pause Menu:
6. Implementation Tips
Environments:
Sound Effects:
Freesound.org
Unity Asset Store (free audio packs)
Mixkit.co
Weapons & Effects:
Blood/hit particles
Linear gameplay
Introduces mechanics
Polish this last
Performance Optimization
Zombie AI:
Occlusion culling
Bake lighting
Code:
Common Controls
WASD - Movement
Mouse - Look around
Shift - Sprint
7. Troubleshooting
Solutions:
Solutions:
Solutions:
✓ Bake NavMesh
✓ Check follow distance values
Solutions:
Next Steps
1. Create Chapter 1 scene (school classroom)
Additional Resources
YouTube Tutorials:
Unity Learn:
AI Navigation Documentation
Asset Sources:
Pro Tips
Final Notes
This guide provides all the essential scripts and setup instructions needed to create your zombie
survival game. Remember that game development is iterative - start with the basics, test thoroughly,
and gradually add complexity.