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 [Link]
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
[Link] = [Link];
[Link] = false;
}
void Update()
{
HandleMovement();
HandleCamera();
HandleJump();
}
void HandleMovement()
{
isGrounded = [Link];
if (isGrounded && velocity.y < 0)
{
velocity.y = -2f;
}
// Get input
float horizontal = [Link]("Horizontal");
float vertical = [Link]("Vertical");
// Calculate movement direction
Vector3 move = [Link] * horizontal + [Link] * vertical;
// Sprint
float currentSpeed = [Link]([Link]) ? sprintSpeed : moveSpeed;
[Link](move * currentSpeed * [Link]);
// Apply gravity
velocity.y += [Link].y * [Link];
[Link](velocity * [Link]);
}
void HandleCamera()
{
// Mouse input
float mouseX = [Link]("Mouse X") * mouseSensitivity;
float mouseY = [Link]("Mouse Y") * mouseSensitivity;
// Rotate player horizontally
[Link]([Link] * mouseX);
// Rotate camera vertically
verticalRotation -= mouseY;
verticalRotation = [Link](verticalRotation, -verticalLookLimit, verticalLook
[Link] = [Link](verticalRotation, 0f, 0f);
}
void HandleJump()
{
if ([Link]("Jump") && isGrounded)
{
velocity.y = [Link](jumpForce * -2f * [Link].y);
}
}
public void TakeDamage(int damage)
{
currentHealth -= damage;
[Link]("Player Health: " + currentHealth);
if (currentHealth <= 0)
{
Die();
}
}
void Die()
{
[Link]("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 [Link]
using UnityEngine;
using [Link];
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 = [Link];
void Start()
{
agent = GetComponent<NavMeshAgent>();
animator = GetComponent<Animator>();
player = [Link]("Player")?.transform;
currentHealth = maxHealth;
timer = wanderTimer;
}
void Update()
{
if (currentState == [Link]) return;
float distanceToPlayer = player ? [Link]([Link], [Link]
switch (currentState)
{
case [Link]:
HandleIdle();
break;
case [Link]:
HandlePatrol();
break;
case [Link]:
HandleChase();
break;
case [Link]:
HandleAttack();
break;
}
// Check if player is in range
if (player && distanceToPlayer <= detectionRange)
{
if (distanceToPlayer <= attackRange)
{
currentState = [Link];
}
else
{
currentState = [Link];
}
}
else if (currentState == [Link] || currentState == [Link])
{
currentState = [Link];
}
}
void HandleIdle()
{
animator?.SetBool("isWalking", false);
timer += [Link];
if (timer >= wanderTimer)
{
currentState = [Link];
timer = 0;
}
}
void HandlePatrol()
{
animator?.SetBool("isWalking", true);
if (![Link] || [Link] < 0.5f)
{
Vector3 randomDirection = [Link] * wanderRadius;
randomDirection += [Link];
NavMeshHit hit;
if ([Link](randomDirection, out hit, wanderRadius, 1))
{
[Link]([Link]);
}
}
}
void HandleChase()
{
animator?.SetBool("isWalking", true);
if (player)
{
[Link]([Link]);
}
}
void HandleAttack()
{
animator?.SetBool("isWalking", false);
animator?.SetTrigger("Attack");
[Link]([Link]);
if (player)
{
Vector3 direction = ([Link] - [Link]).normalized;
Quaternion lookRotation = [Link](new Vector3(direction.x, 0,
[Link] = [Link]([Link], lookRotation, Time.
if ([Link] >= nextAttackTime)
{
AttackPlayer();
nextAttackTime = [Link] + attackCooldown;
}
}
}
void AttackPlayer()
{
if (player)
{
PlayerController playerController = [Link]<PlayerController&g
if (playerController)
{
[Link](damage);
}
}
}
public void TakeDamage(int damageAmount)
{
currentHealth -= damageAmount;
animator?.SetTrigger("Hit");
if (currentHealth <= 0)
{
Die();
}
}
void Die()
{
currentState = [Link];
animator?.SetTrigger("Die");
[Link] = 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 [Link]
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 ([Link]("Fire1"))
{
Shoot();
}
}
else
{
if ([Link]("Fire1"))
{
Shoot();
}
}
// Reload
if ([Link](KeyCode.R) && currentAmmo < maxAmmo)
{
Reload();
}
}
void Shoot()
{
if ([Link] < nextFireTime) return;
if (currentAmmo <= 0)
{
[Link]("Out of ammo!");
return;
}
nextFireTime = [Link] + fireRate;
currentAmmo--;
// Visual effects
if (muzzleFlash) [Link]();
// Raycast
RaycastHit hit;
if ([Link]([Link], [Link]
{
[Link]("Hit: " + [Link]);
// Check if hit zombie
ZombieAI zombie = [Link]<ZombieAI>();
if (zombie)
{
[Link]((int)damage);
}
// Impact effect
if (impactEffect)
{
GameObject impact = Instantiate(impactEffect, [Link], [Link]
Destroy(impact, 2f);
}
}
}
void Reload()
{
if (reserveAmmo <= 0) return;
isReloading = true;
[Link]("Reloading...");
Invoke("CompleteReload", 2f);
}
void CompleteReload()
{
int ammoNeeded = maxAmmo - currentAmmo;
int ammoToReload = [Link](ammoNeeded, reserveAmmo);
currentAmmo += ammoToReload;
reserveAmmo -= ammoToReload;
isReloading = false;
[Link]("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 [Link] (Andria)
using UnityEngine;
using [Link];
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 = [Link]("Player")?.transform;
}
}
void Update()
{
if (!player) return;
float distanceToPlayer = [Link]([Link], [Link]);
if (distanceToPlayer > followDistance)
{
// Follow player
[Link]([Link]);
animator?.SetBool("isWalking", true);
}
else if (distanceToPlayer < rotateAroundDistance)
{
// Rotate around player when close
[Link]([Link]);
Vector3 directionToPlayer = ([Link] - [Link]).normalized
Quaternion lookRotation = [Link](directionToPlayer);
[Link] = [Link]([Link], lookRotation, Time.
animator?.SetBool("isWalking", false);
}
else
{
// Stay in place
[Link]([Link]);
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 [Link]
using UnityEngine;
using [Link];
[[Link]]
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 = [Link](x => [Link] == itemName);
if (existingItem != null)
{
[Link] += quantity;
[Link]($"Added {quantity} {itemName}(s). Total: {[Link]}");
return true;
}
// Add new item if space available
if ([Link] < maxSlots)
{
[Link](new InventoryItem(itemName, quantity));
[Link]($"Added new item: {itemName} x{quantity}");
return true;
}
[Link]("Inventory full!");
return false;
}
public bool RemoveItem(string itemName, int quantity = 1)
{
InventoryItem item = [Link](x => [Link] == itemName);
if (item != null && [Link] >= quantity)
{
[Link] -= quantity;
if ([Link] <= 0)
{
[Link](item);
}
[Link]($"Removed {quantity} {itemName}(s)");
return true;
}
[Link]($"Not enough {itemName} in inventory");
return false;
}
public bool HasItem(string itemName, int quantity = 1)
{
InventoryItem item = [Link](x => [Link] == itemName);
return item != null && [Link] >= quantity;
}
public int GetItemCount(string itemName)
{
InventoryItem item = [Link](x => [Link] == itemName);
return item?.quantity ?? 0;
}
}
How to Use:
// Add items
[Link]("Food", 5);
[Link]("Ammo", 30);
// Remove items
[Link]("Food", 1);
// Check if has item
if ([Link]("Grenade", 1))
{
// Player has at least 1 grenade
}
3.6 [Link] & [Link]
[Link]:
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, [Link], [Link]);
}
// Play sound
if (explosionSound)
{
[Link](explosionSound, [Link]);
}
// Damage nearby objects
Collider[] colliders = [Link]([Link], explosionRadius)
foreach (Collider nearbyObject in colliders)
{
// Damage zombies
ZombieAI zombie = [Link]<ZombieAI>();
if (zombie)
{
[Link](damage);
}
// Apply physics force
Rigidbody nearbyRb = [Link]<Rigidbody>();
if (nearbyRb)
{
[Link](explosionForce, [Link], explosionR
}
}
Destroy(gameObject);
}
void OnDrawGizmosSelected()
{
[Link] = [Link];
[Link]([Link], explosionRadius);
}
}
[Link]:
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 ([Link](KeyCode.G))
{
ThrowGrenade();
}
}
void ThrowGrenade()
{
if (grenadeCount <= 0)
{
[Link]("No grenades left!");
return;
}
grenadeCount--;
GameObject grenade = Instantiate(grenadePrefab, [Link], throwPoint.r
Rigidbody rb = [Link]<Rigidbody>();
if (rb)
{
Vector3 throwDirection = [Link] + [Link] * throwUpwardForce;
[Link]([Link] * throwForce, [Link])
}
[Link]($"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 [Link] script
5. Assign explosion effect (particle system)
6. Save as prefab
3.7 [Link]
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)
{
[Link]("Out of fuel!");
return;
}
GetInput();
HandleMotor();
HandleSteering();
ConsumeFuel();
}
void GetInput()
{
float verticalInput = [Link]("Vertical");
float horizontalInput = [Link]("Horizontal");
currentMotorForce = verticalInput * motorForce;
currentSteerAngle = horizontalInput * maxSteerAngle;
currentBrakeForce = [Link]([Link]) ? brakeForce : 0f;
}
void HandleMotor()
{
[Link] = currentMotorForce;
[Link] = currentMotorForce;
[Link] = currentBrakeForce;
[Link] = currentBrakeForce;
[Link] = currentBrakeForce;
[Link] = currentBrakeForce;
}
void HandleSteering()
{
[Link] = currentSteerAngle;
[Link] = currentSteerAngle;
}
void ConsumeFuel()
{
if ([Link](currentMotorForce) > 0)
{
currentFuel -= fuelConsumption * [Link];
currentFuel = [Link](0, currentFuel);
}
}
public void AddFuel(float amount)
{
currentFuel += amount;
currentFuel = [Link](currentFuel, maxFuel);
[Link]($"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 [Link]
using UnityEngine;
using [Link];
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 = [Link]();
if (healthBar)
{
[Link] = (float)currentHealth / [Link];
}
if (healthText)
{
[Link] = $"Health: {currentHealth}/{[Link]}";
}
}
}
}
4.2 [Link]
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)
{
[Link] = $"{[Link]} / {[Link]}";
}
}
}
4.3 [Link]
using UnityEngine;
using [Link];
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 ([Link]([Link]))
{
TogglePause();
}
}
public void TogglePause()
{
isPaused = !isPaused;
if (pauseMenu)
{
[Link](isPaused);
}
[Link] = isPaused ? 0f : 1f;
[Link] = isPaused ? [Link] : [Link];
[Link] = isPaused;
}
public void GameOver()
{
if (gameOverScreen)
{
[Link](true);
}
[Link] = 0f;
[Link] = [Link];
[Link] = true;
}
public void RestartLevel()
{
[Link] = 1f;
[Link]([Link]().name);
}
public void LoadChapter(int chapterNumber)
{
currentChapter = chapterNumber;
[Link] = 1f;
[Link]("Chapter" + chapterNumber);
}
public void QuitGame()
{
[Link]();
[Link]("Game Quit");
}
}
4.4 [Link]
using UnityEngine;
using [Link];
using [Link];
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());
[Link](sceneName);
}
IEnumerator TransitionToScene(int sceneIndex)
{
yield return StartCoroutine(FadeOut());
[Link](sceneIndex);
}
IEnumerator FadeIn()
{
float elapsedTime = 0f;
while (elapsedTime < fadeDuration)
{
elapsedTime += [Link];
[Link] = [Link](1f, 0f, elapsedTime / fadeDuration);
yield return null;
}
[Link] = 0f;
}
IEnumerator FadeOut()
{
float elapsedTime = 0f;
while (elapsedTime < fadeDuration)
{
elapsedTime += [Link];
[Link] = [Link](0f, 1f, elapsedTime / fadeDuration);
yield return null;
}
[Link] = 1f;
}
}
4.5 [Link]
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)
{
[Link]([Link] * rotationSpeed * [Link]);
}
}
void OnTriggerEnter(Collider other)
{
if ([Link]("Player"))
{
CollectItem([Link]);
}
}
void CollectItem(GameObject player)
{
switch (type)
{
case [Link]:
WeaponSystem weapon = [Link]<WeaponSystem>()
if (weapon)
{
[Link] += quantity;
[Link]($"Collected {quantity} ammo");
}
break;
case [Link]:
GrenadeThrower grenadeThrower = [Link]<GrenadeThrower>
if (grenadeThrower)
{
[Link](quantity);
[Link]($"Collected {quantity} grenade(s)");
}
break;
case [Link]:
if ([Link])
{
[Link]("Food", quantity);
}
break;
}
// Add item to inventory
if ([Link])
{
[Link](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 ([Link])
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 [Link] 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:
[Link] (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:
[Link]
Unity Asset Store (free audio packs)
[Link]
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:
[Link] (characters & animations)
Unity Asset Store (free assets)
[Link] (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