0% found this document useful (0 votes)
240 views33 pages

Unity Zombie Game Complete Guide

The document is a comprehensive development guide for a Unity-based zombie survival game titled 'Joel's Adventure', featuring a six-chapter story where the protagonist, Joel, navigates a zombie apocalypse alongside his companion, Andria. It includes detailed chapter breakdowns, core gameplay mechanics, and complete C# scripts for player control, zombie AI, weapon systems, companion AI, and inventory management. Additionally, it provides setup instructions, implementation tips, and troubleshooting advice for developers.

Uploaded by

tjet06296
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
240 views33 pages

Unity Zombie Game Complete Guide

The document is a comprehensive development guide for a Unity-based zombie survival game titled 'Joel's Adventure', featuring a six-chapter story where the protagonist, Joel, navigates a zombie apocalypse alongside his companion, Andria. It includes detailed chapter breakdowns, core gameplay mechanics, and complete C# scripts for player control, zombie AI, weapon systems, companion AI, and inventory management. Additionally, it provides setup instructions, implementation tips, and troubleshooting advice for developers.

Uploaded by

tjet06296
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd

Unity Zombie Survival Game - Complete

Development Guide
Joel's Adventure: 6 Chapter Zombie Apocalypse Story

Complete C# Scripts, Setup Instructions, and Implementation Guide

Table of Contents
1. Game Overview
2. Chapter Breakdown
3. Core Scripts

4. UI & Management Scripts


5. Setup Instructions
6. Implementation Tips

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:

First-person shooter mechanics


Companion AI (Andria follows player)

Inventory system (food, guns, ammo, grenades)


Vehicle driving system

Multiple weapon types

Zombie AI with pathfinding


6 unique chapters with different environments

Day/night cycle

Fuel management system


2. Chapter Breakdown

Chapter 1: The Outbreak


Location: High School Classroom
Key Events:

Joel studying in class


Zombie breaks through window

Zombie attacks Andria (Joel's crush)

Joel becomes brave and kills the zombie


Player learns basic combat mechanics

Mechanics:

Player movement (WASD)


Basic melee combat
Health system introduction
Camera controls

Chapter 2: Chaos Unleashed

Location: School Hallways & Exterior


Key Events:

Army enters school


Students turn into zombies (chaos everywhere)
Joel protects Andria through hallways
Joel gets caught by zombie

Soldier rescues Joel and Andria


Escape via army van

Mechanics:

NPC companion (Andria follows player)

Wave-based zombie encounters

Soldier AI assistance
Vehicle entry cutscene
Chapter 3: Boot Camp

Location: Army Training Camp


Key Events:

Van arrives at camp (zoom out cutscene)

5 days of training montage

Learn weapons and combat


Zombie breach at camp

Bombs explode, chaos ensues


Joel and Andria gather survival supplies

Escape in jeep, drive 10km

Run out of fuel


Search houses for fuel
Find 30L fuel can

Sleep in house overnight

Mechanics:

Gun weapon system


Shooting mechanics
Inventory system (backpack)
Item collection (food, guns, ammo, bombs)

Vehicle driving
Fuel management
Day/night cycle

Chapter 4: The Journey


Location: Open Road & Los Santos City
Key Events:

Wake up at 7 AM
Refuel jeep

Travel towards second army camp (100km away)

Stop at Los Santos city


Loot city for supplies

Mechanics:

Time-based events

Long-distance driving
City exploration

Looting mechanics
Resource management

Chapter 5: Betrayal

Location: Destroyed Army Camp


Key Events:

Arrive at second camp (destroyed by zombies)


9 PM, dark environment

Someone hits Joel in the head


Joel collapses and blacks out

Mechanics:

Night lighting effects


Knockout/blackout sequence

Cutscene trigger

Chapter 6: Escape
Location: Knight King Gang Base & Ship Factory
Key Events:

Joel wakes up in jail cell


Andria beside him in cell
Learn about Knight King gang (thieves who looted everything)
Joel has hidden grenade

Throw grenade at night, creates hole

Zombies enter through hole


Escape jail using Andria's hairpin as lockpick

Retrieve stolen loot


Fight way through zombies and gang members

Reach ship factory by the sea

Sleep in factory room (safe zone)

Mechanics:

Jail cell interaction


Grenade throwing
Lock picking mechanic

Stealth elements
Final confrontation combat
Multiple enemy types (zombies + humans)

3. Core Scripts

3.1 PlayerController.cs

using UnityEngine;

public class PlayerController : MonoBehaviour


{
[Header("Movement Settings")]
public float moveSpeed = 5f;
public float sprintSpeed = 8f;
public float jumpForce = 5f;

[Header("Camera Settings")]
public Transform cameraTransform;
public float mouseSensitivity = 2f;
public float verticalLookLimit = 80f;

private CharacterController controller;


private Vector3 velocity;
private bool isGrounded;
private float verticalRotation = 0f;

[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");

// Calculate movement direction


Vector3 move = transform.right * horizontal + transform.forward * vertical;

// Sprint
float currentSpeed = Input.GetKey(KeyCode.LeftShift) ? sprintSpeed : moveSpeed;

controller.Move(move * currentSpeed * Time.deltaTime);

// 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;

// Rotate player horizontally


transform.Rotate(Vector3.up * mouseX);

// Rotate camera vertically


verticalRotation -= mouseY;
verticalRotation = Mathf.Clamp(verticalRotation, -verticalLookLimit, verticalLook
cameraTransform.localRotation = Quaternion.Euler(verticalRotation, 0f, 0f);
}

void HandleJump()
{
if (Input.GetButtonDown("Jump") && isGrounded)
{
velocity.y = Mathf.Sqrt(jumpForce * -2f * Physics.gravity.y);
}
}

public void TakeDamage(int damage)


{
currentHealth -= damage;
Debug.Log("Player Health: " + currentHealth);

if (currentHealth <= 0)
{
Die();
}
}
void Die()
{
Debug.Log("Player Died!");
// Add death logic here
// Example: Reload scene or show game over screen
}

public int GetCurrentHealth()


{
return currentHealth;
}
}

Usage Instructions:

1. Attach to player GameObject

2. Assign camera transform in Inspector


3. Add Character Controller component
4. Tag player as "Player"

3.2 ZombieAI.cs

using UnityEngine;
using UnityEngine.AI;

public class ZombieAI : MonoBehaviour


{
[Header("AI Settings")]
public float detectionRange = 10f;
public float attackRange = 2f;
public float wanderRadius = 10f;
public float wanderTimer = 5f;

[Header("Combat")]
public int damage = 10;
public float attackCooldown = 1.5f;
public int maxHealth = 50;

private Transform player;


private NavMeshAgent agent;
private Animator animator;
private float timer;
private float nextAttackTime;
private int currentHealth;

private enum State { Idle, Patrolling, Chasing, Attacking, Dead }


private State currentState = State.Idle;

void Start()
{
agent = GetComponent<NavMeshAgent>();
animator = GetComponent<Animator>();
player = GameObject.FindGameObjectWithTag("Player")?.transform;
currentHealth = maxHealth;
timer = wanderTimer;
}

void Update()
{
if (currentState == State.Dead) return;

float distanceToPlayer = player ? Vector3.Distance(transform.position, player.pos

switch (currentState)
{
case State.Idle:
HandleIdle();
break;
case State.Patrolling:
HandlePatrol();
break;
case State.Chasing:
HandleChase();
break;
case State.Attacking:
HandleAttack();
break;
}

// Check if player is in range


if (player && distanceToPlayer <= detectionRange)
{
if (distanceToPlayer <= attackRange)
{
currentState = State.Attacking;
}
else
{
currentState = State.Chasing;
}
}
else if (currentState == State.Chasing || currentState == State.Attacking)
{
currentState = State.Idle;
}
}

void HandleIdle()
{
animator?.SetBool("isWalking", false);
timer += Time.deltaTime;

if (timer >= wanderTimer)


{
currentState = State.Patrolling;
timer = 0;
}
}

void HandlePatrol()
{
animator?.SetBool("isWalking", true);

if (!agent.hasPath || agent.remainingDistance < 0.5f)


{
Vector3 randomDirection = Random.insideUnitSphere * wanderRadius;
randomDirection += transform.position;

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.

if (Time.time >= nextAttackTime)


{
AttackPlayer();
nextAttackTime = Time.time + attackCooldown;
}
}
}

void AttackPlayer()
{
if (player)
{
PlayerController playerController = player.GetComponent<PlayerController&g
if (playerController)
{
playerController.TakeDamage(damage);
}
}
}

public void TakeDamage(int damageAmount)


{
currentHealth -= damageAmount;
animator?.SetTrigger("Hit");

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;

public class WeaponSystem : MonoBehaviour


{
[Header("Weapon Settings")]
public int maxAmmo = 30;
public int currentAmmo;
public int reserveAmmo = 90;
public float fireRate = 0.1f;
public float damage = 25f;
public float range = 100f;

[Header("Weapon Type")]
public bool isAutomatic = true;

[Header("References")]
public Camera playerCamera;
public Transform shootPoint;
public ParticleSystem muzzleFlash;
public GameObject impactEffect;

private float nextFireTime = 0f;


private bool isReloading = false;

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);

// Check if hit zombie


ZombieAI zombie = hit.transform.GetComponent<ZombieAI>();
if (zombie)
{
zombie.TakeDamage((int)damage);
}

// 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:

1. Create child object "WeaponHolder" under Player


2. Attach this script

3. Assign main camera


4. Create shoot point (empty GameObject at barrel end)
5. Add muzzle flash particle effect (optional)
6. Create impact effect prefab (optional)

3.4 CompanionAI.cs (Andria)

using UnityEngine;
using UnityEngine.AI;

public class CompanionAI : MonoBehaviour


{
[Header("Follow Settings")]
public Transform player;
public float followDistance = 3f;
public float rotateAroundDistance = 1.5f;
public float rotationSpeed = 2f;

private NavMeshAgent agent;


private Animator animator;

void Start()
{
agent = GetComponent<NavMeshAgent>();
animator = GetComponent<Animator>();

if (!player)
{
player = GameObject.FindGameObjectWithTag("Player")?.transform;
}
}

void Update()
{
if (!player) return;

float distanceToPlayer = Vector3.Distance(transform.position, player.position);

if (distanceToPlayer > followDistance)


{
// Follow player
agent.SetDestination(player.position);
animator?.SetBool("isWalking", true);
}
else if (distanceToPlayer < rotateAroundDistance)
{
// Rotate around player when close
agent.SetDestination(transform.position);

Vector3 directionToPlayer = (player.position - transform.position).normalized


Quaternion lookRotation = Quaternion.LookRotation(directionToPlayer);
transform.rotation = Quaternion.Slerp(transform.rotation, lookRotation, Time.

animator?.SetBool("isWalking", false);
}
else
{
// Stay in place
agent.SetDestination(transform.position);
animator?.SetBool("isWalking", false);
}
}
}

Character Setup (Andria):

1. Import female character model


2. Add NavMeshAgent component

3. Add this script


4. Assign player reference
5. Tag as "Companion"

3.5 InventorySystem.cs

using UnityEngine;
using System.Collections.Generic;

[System.Serializable]
public class InventoryItem
{
public string itemName;
public int quantity;
public Sprite icon;

public InventoryItem(string name, int qty)


{
itemName = name;
quantity = qty;
}
}

public class InventorySystem : MonoBehaviour


{
public static InventorySystem instance;

[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);
}
}

public bool AddItem(string itemName, int quantity = 1)


{
// Check if item already exists
InventoryItem existingItem = items.Find(x => x.itemName == itemName);

if (existingItem != null)
{
existingItem.quantity += quantity;
Debug.Log($"Added {quantity} {itemName}(s). Total: {existingItem.quantity}");
return true;
}

// Add new item if space available


if (items.Count < maxSlots)
{
items.Add(new InventoryItem(itemName, quantity));
Debug.Log($"Added new item: {itemName} x{quantity}");
return true;
}

Debug.Log("Inventory full!");
return false;
}

public bool RemoveItem(string itemName, int quantity = 1)


{
InventoryItem item = items.Find(x => x.itemName == itemName);

if (item != null && item.quantity >= quantity)


{
item.quantity -= quantity;

if (item.quantity <= 0)
{
items.Remove(item);
}

Debug.Log($"Removed {quantity} {itemName}(s)");


return true;
}

Debug.Log($"Not enough {itemName} in inventory");


return false;
}

public bool HasItem(string itemName, int quantity = 1)


{
InventoryItem item = items.Find(x => x.itemName == itemName);
return item != null && item.quantity >= quantity;
}

public int GetItemCount(string itemName)


{
InventoryItem item = items.Find(x => x.itemName == itemName);
return item?.quantity ?? 0;
}
}

How to Use:

// Add items
InventorySystem.instance.AddItem("Food", 5);
InventorySystem.instance.AddItem("Ammo", 30);

// Remove items
InventorySystem.instance.RemoveItem("Food", 1);

// Check if has item


if (InventorySystem.instance.HasItem("Grenade", 1))
{
// Player has at least 1 grenade
}

3.6 Grenade.cs & GrenadeThrower.cs

Grenade.cs:

using UnityEngine;

public class Grenade : MonoBehaviour


{
[Header("Grenade Settings")]
public float throwForce = 20f;
public float explosionDelay = 3f;
public float explosionRadius = 5f;
public float explosionForce = 700f;
public int damage = 100;

[Header("Effects")]
public GameObject explosionEffect;
public AudioClip explosionSound;

private Rigidbody rb;


private bool hasExploded = false;

void Start()
{
rb = GetComponent<Rigidbody>();
Invoke("Explode", explosionDelay);
}

void Explode()
{
if (hasExploded) return;
hasExploded = true;

// Spawn explosion effect


if (explosionEffect)
{
Instantiate(explosionEffect, transform.position, Quaternion.identity);
}

// Play sound
if (explosionSound)
{
AudioSource.PlayClipAtPoint(explosionSound, transform.position);
}

// Damage nearby objects


Collider[] colliders = Physics.OverlapSphere(transform.position, explosionRadius)

foreach (Collider nearbyObject in colliders)


{
// Damage zombies
ZombieAI zombie = nearbyObject.GetComponent<ZombieAI>();
if (zombie)
{
zombie.TakeDamage(damage);
}

// Apply physics force


Rigidbody nearbyRb = nearbyObject.GetComponent<Rigidbody>();
if (nearbyRb)
{
nearbyRb.AddExplosionForce(explosionForce, transform.position, explosionR
}
}

Destroy(gameObject);
}

void OnDrawGizmosSelected()
{
Gizmos.color = Color.red;
Gizmos.DrawWireSphere(transform.position, explosionRadius);
}
}

GrenadeThrower.cs:

using UnityEngine;

public class GrenadeThrower : MonoBehaviour


{
[Header("Grenade Settings")]
public GameObject grenadePrefab;
public Transform throwPoint;
public float throwForce = 20f;
public float throwUpwardForce = 2f;

private int grenadeCount = 5;

void Update()
{
if (Input.GetKeyDown(KeyCode.G))
{
ThrowGrenade();
}
}

void ThrowGrenade()
{
if (grenadeCount <= 0)
{
Debug.Log("No grenades left!");
return;
}

grenadeCount--;

GameObject grenade = Instantiate(grenadePrefab, throwPoint.position, throwPoint.r


Rigidbody rb = grenade.GetComponent<Rigidbody>();

if (rb)
{
Vector3 throwDirection = throwPoint.forward + Vector3.up * throwUpwardForce;
rb.AddForce(throwDirection.normalized * throwForce, ForceMode.VelocityChange)
}

Debug.Log($"Grenades remaining: {grenadeCount}");


}

public void AddGrenades(int amount)


{
grenadeCount += amount;
}
}

Grenade Prefab Setup:

1. Create sphere GameObject


2. Add Rigidbody

3. Add Sphere Collider

4. Add Grenade.cs script


5. Assign explosion effect (particle system)
6. Save as prefab

3.7 VehicleController.cs

using UnityEngine;

public class VehicleController : MonoBehaviour


{
[Header("Wheel Colliders")]
public WheelCollider frontLeftWheel;
public WheelCollider frontRightWheel;
public WheelCollider rearLeftWheel;
public WheelCollider rearRightWheel;

[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;

private float currentMotorForce;


private float currentBrakeForce;
private float currentSteerAngle;

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");

currentMotorForce = verticalInput * motorForce;


currentSteerAngle = horizontalInput * maxSteerAngle;

currentBrakeForce = Input.GetKey(KeyCode.Space) ? brakeForce : 0f;


}
void HandleMotor()
{
frontLeftWheel.motorTorque = currentMotorForce;
frontRightWheel.motorTorque = currentMotorForce;

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);
}
}

public void AddFuel(float amount)


{
currentFuel += amount;
currentFuel = Mathf.Min(currentFuel, maxFuel);
Debug.Log($"Fuel added. Current fuel: {currentFuel}/{maxFuel}");
}
}

Vehicle Setup:

1. Import jeep/car model


2. Add Rigidbody (mass ~1500)
3. Add 4 WheelCollider components (position at wheel locations)

4. Add this script

5. Assign wheel colliders


6. Adjust suspension and friction curves

4. UI & Management Scripts


4.1 HealthUI.cs

using UnityEngine;
using UnityEngine.UI;
using TMPro;

public class HealthUI : MonoBehaviour


{
[Header("UI References")]
public Slider healthBar;
public TextMeshProUGUI healthText;

[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;

public class AmmoUI : MonoBehaviour


{
[Header("UI References")]
public TextMeshProUGUI ammoText;

[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;

public class GameManager : MonoBehaviour


{
public static GameManager instance;

[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();
}
}

public void TogglePause()


{
isPaused = !isPaused;

if (pauseMenu)
{
pauseMenu.SetActive(isPaused);
}

Time.timeScale = isPaused ? 0f : 1f;


Cursor.lockState = isPaused ? CursorLockMode.None : CursorLockMode.Locked;
Cursor.visible = isPaused;
}
public void GameOver()
{
if (gameOverScreen)
{
gameOverScreen.SetActive(true);
}

Time.timeScale = 0f;
Cursor.lockState = CursorLockMode.None;
Cursor.visible = true;
}

public void RestartLevel()


{
Time.timeScale = 1f;
SceneManager.LoadScene(SceneManager.GetActiveScene().name);
}

public void LoadChapter(int chapterNumber)


{
currentChapter = chapterNumber;
Time.timeScale = 1f;
SceneManager.LoadScene("Chapter" + chapterNumber);
}

public void QuitGame()


{
Application.Quit();
Debug.Log("Game Quit");
}
}

4.4 SceneTransition.cs

using UnityEngine;
using UnityEngine.SceneManagement;
using System.Collections;

public class SceneTransition : MonoBehaviour


{
[Header("Fade Settings")]
public CanvasGroup fadeCanvasGroup;
public float fadeDuration = 1f;

void Start()
{
if (fadeCanvasGroup)
{
StartCoroutine(FadeIn());
}
}

public void LoadScene(string sceneName)


{
StartCoroutine(TransitionToScene(sceneName));
}

public void LoadScene(int sceneIndex)


{
StartCoroutine(TransitionToScene(sceneIndex));
}

IEnumerator TransitionToScene(string sceneName)


{
yield return StartCoroutine(FadeOut());
SceneManager.LoadScene(sceneName);
}

IEnumerator TransitionToScene(int sceneIndex)


{
yield return StartCoroutine(FadeOut());
SceneManager.LoadScene(sceneIndex);
}

IEnumerator FadeIn()
{
float elapsedTime = 0f;

while (elapsedTime < fadeDuration)


{
elapsedTime += Time.deltaTime;
fadeCanvasGroup.alpha = Mathf.Lerp(1f, 0f, elapsedTime / fadeDuration);
yield return null;
}

fadeCanvasGroup.alpha = 0f;
}

IEnumerator FadeOut()
{
float elapsedTime = 0f;

while (elapsedTime < fadeDuration)


{
elapsedTime += Time.deltaTime;
fadeCanvasGroup.alpha = Mathf.Lerp(0f, 1f, elapsedTime / fadeDuration);
yield return null;
}

fadeCanvasGroup.alpha = 1f;
}
}
4.5 Collectible.cs

using UnityEngine;

public class Collectible : MonoBehaviour


{
[Header("Item Settings")]
public string itemName = "Item";
public int quantity = 1;
public CollectibleType type;

public enum CollectibleType


{
Ammo,
HealthPack,
Grenade,
Fuel,
Food
}

[Header("Rotation")]
public bool rotateItem = true;
public float rotationSpeed = 50f;

void Update()
{
if (rotateItem)
{
transform.Rotate(Vector3.up * rotationSpeed * Time.deltaTime);
}
}

void OnTriggerEnter(Collider other)


{
if (other.CompareTag("Player"))
{
CollectItem(other.gameObject);
}
}

void CollectItem(GameObject player)


{
switch (type)
{
case CollectibleType.Ammo:
WeaponSystem weapon = player.GetComponentInChildren<WeaponSystem>()
if (weapon)
{
weapon.reserveAmmo += quantity;
Debug.Log($"Collected {quantity} ammo");
}
break;

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;
}

// Add item to inventory


if (InventorySystem.instance)
{
InventorySystem.instance.AddItem(itemName, quantity);
}

Destroy(gameObject);
}
}

5. Setup Instructions

5.1 Unity Project Setup


Step 1: Create New Project

1. Open Unity Hub


2. Click "New Project"
3. Select "3D Core" template
4. Name: "ZombieSurvival"
5. Click "Create Project"

Step 2: Install Required Packages

1. Open Package Manager (Window > Package Manager)

2. Install TextMeshPro

3. Install AI Navigation (com.unity.ai.navigation)

Step 3: Create Folder Structure

Assets/
├── Scripts/
│ ├── Player/
│ ├── Enemy/
│ ├── Weapons/
│ ├── UI/
│ └── Managers/
├── Prefabs/
│ ├── Characters/
│ ├── Enemies/
│ ├── Weapons/
│ └── Items/
├── Scenes/
├── Materials/
├── Audio/
└── UI/

5.2 Player Setup

1. Create Player GameObject:

GameObject > Create Empty

Name: "Player"
Tag: "Player"
2. Add Components:

Character Controller
PlayerController script
GrenadeThrower script
3. Create Camera:

Create child object "Main Camera"


Position at (0, 1.6, 0)
Tag as "MainCamera"

4. Create Weapon Holder:


Create child object "WeaponHolder"
Position in front of camera

Add WeaponSystem script


5. Assign References:

PlayerController: Assign camera transform

WeaponSystem: Assign player camera, shoot point

5.3 Zombie Setup

1. Import Model:

Download from Mixamo.com or Unity Asset Store

Drag model into scene


2. Add Components:
NavMeshAgent

Capsule Collider
ZombieAI script
Tag as "Enemy"
3. Setup Animator:

Create Animator Controller

Add animations: Idle, Walk, Attack, Hit, Die


Create parameters: isWalking (Bool), Attack (Trigger), Hit (Trigger), Die (Trigger)

4. Save as Prefab:
Drag configured zombie to Prefabs folder

5.4 NavMesh Baking

1. Mark Walkable Surfaces:


Select all ground/floor objects
Window > AI > Navigation

Object tab > Mark as "Walkable"


2. Bake NavMesh:
Bake tab
Agent Radius: 0.5

Agent Height: 2
Click "Bake"

5.5 UI Setup
Health Bar:

1. Create Canvas (UI > Canvas)


2. Canvas Scaler > "Scale with Screen Size"

3. Add Slider (UI > Slider)


4. Remove handle, keep background and fill

5. Position top-left corner

6. Add HealthUI script to Canvas

Ammo Display:

1. Create TextMeshPro text


2. Position bottom-right corner
3. Add AmmoUI script to Canvas

Pause Menu:

1. Create Panel (child of Canvas)


2. Add "Resume" and "Quit" buttons

3. Set inactive by default

6. Implementation Tips

Getting Free Assets


Character Models:

Mixamo.com (free zombie animations)


Unity Asset Store ("Zombie", "Soldier")

Search: female character for Andria

Environments:

Unity Asset Store: school interior

Free 3D models: military base, city buildings

Sound Effects:

Freesound.org
Unity Asset Store (free audio packs)
Mixkit.co
Weapons & Effects:

Muzzle flash particles


Explosion VFX

Blood/hit particles

Chapter Implementation Order

1. Start with Chapter 3 (easiest to test)


Open environment

All core mechanics

Good for prototyping


2. Then Chapter 1 (tutorial level)

Linear gameplay
Introduces mechanics
Polish this last

3. Build remaining chapters progressively

Performance Optimization

Zombie AI:

Limit 10-15 active zombies max

Use object pooling


Disable distant zombie AI
Graphics:

Use LOD (Level of Detail)

Occlusion culling
Bake lighting
Code:

Update zombie AI every 0.1s instead of every frame


Use coroutines for delayed actions

Cache component references

Common Controls
WASD - Movement
Mouse - Look around

Left Click - Shoot


R - Reload
G - Throw grenade
Space - Jump / Brake (vehicle)

Shift - Sprint

ESC - Pause menu

7. Troubleshooting

Issue: Zombies not pathfinding

Solutions:

✓ Bake NavMesh (Window > AI > Navigation > Bake)

✓ Check "Walkable" on ground objects


✓ Verify NavMeshAgent component on zombie

✓ Check detection range in ZombieAI script

Issue: Player falling through floor

Solutions:

✓ Add Box Collider to ground

✓ Check Character Controller is enabled


✓ Verify collision layers

✓ Increase Character Controller radius

Issue: Shooting doesn't work


Solutions:

✓ Assign camera reference in WeaponSystem


✓ Check raycast range value
✓ Verify zombie has ZombieAI script

✓ Check weapon is active in hierarchy

Issue: Companion not following

Solutions:

✓ Assign player reference in CompanionAI


✓ Add NavMeshAgent component

✓ Bake NavMesh
✓ Check follow distance values

Issue: Vehicle won't move

Solutions:

✓ Assign all 4 WheelColliders

✓ Check motorForce value (1500+)

✓ Add Rigidbody to vehicle


✓ Verify ground has collider
Testing Checklist

□ Player movement (all directions)


□ Camera rotation (smooth)
□ Shooting (damages zombies)
□ Zombie AI (chase & attack)
□ Health system (take damage)
□ Ammo system (reload works)
□ Grenade throwing & explosion
□ Inventory (add/remove items)
□ Companion following
□ Vehicle driving
□ Fuel consumption
□ Scene transitions
□ UI displays correctly
□ Collectibles pickup
□ Game pause/resume

Next Steps
1. Create Chapter 1 scene (school classroom)

2. Test all core mechanics in one scene first


3. Build one chapter at a time
4. Playtest frequently (don't wait until complete)

5. Add polish (sounds, effects, animations)


6. Build and test on your target platform

Additional Resources

YouTube Tutorials:

Brackeys (Unity Basics)

CodeMonkey (Advanced Systems)

Blackthornprod (Game Design)

Unity Learn:

FPS Microgame Tutorial


Unity Beginner Tutorials

AI Navigation Documentation

Asset Sources:

Mixamo.com (characters & animations)


Unity Asset Store (free assets)
Freesound.org (sound effects)

Poly Pizza (3D models)

Pro Tips

✓ Start simple - Get basic mechanics working first


✓ Test frequently - Don't wait until everything is done
✓ Use prefabs - Make reusable zombies, items, etc.
✓ Comment code - Future you will thank present you
✓ Backup project - Save versions regularly
✓ Get feedback - Let others playtest
✓ Focus on gameplay before graphics
✓ One feature at a time - Don't try to do everything at once

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.

Good luck with your game development journey! 🎮

If you encounter issues not covered in this guide, check:

Unity's official documentation


Unity forums and communities
YouTube tutorial channels
Stack Overflow for specific coding questions

Created by: AI Assistant


Version: 1.0
Last Updated: October 2025

You might also like