In short
A zombie survival game is a wave spawner that sends more and tougher zombies each round, zombie AI cheap enough to run dozens at once, weapons with limited ammo, barricades to defend and repair, and cash per kill to spend between waves. Build one small map with one weapon, barricades and ten waves first, test it with three friends, then add a weapon shop, perks, revives and more maps.
- Escalate on several numbers at once (count, health, speed, new zombie types) so later waves feel different, not just longer.
- Keep the server cost of each zombie low: one simple chase loop, server-owned, and a cap on how many are alive.
- Scarcity is the fun. If ammo and cash are plentiful, the game is a shooting gallery.
On this page
What makes a zombie survival game work
The loop in one line: survive the wave, earn cash, spend it on guns, doors and repairs, survive a bigger wave. Roblox's Survival genre covers games where the objective is to survive, escape or defeat something threatening the players, and a zombie game with lots of shooting may also fit Shooter with the PvE Shooter subgenre. Pick by your core gameplay.
- Every 10 seconds: triage. Shoot the zombie closest to the window, reload now or after this one, run to the teammate who is down.
- Every wave: a breather, then a squeeze. The short break between waves is when players shop, repair and plan. The wave is when the plan is tested.
- Every 5 waves: something new. A fast zombie, a tank, an exploder, a boss wave. New threats force new tactics where bigger numbers alone do not.
- Every session: a record. The highest wave reached is the score. "We got to wave 23" is the story players tell.
- Teamwork. Revives, shared doors that one player pays to open, and holding different windows make co-op the natural way to play.
Zombie games that get abandoned usually escalate only health (so late waves are long and boring), let players camp one corner forever, or hand out so much ammo that there is no decision. Good ones make the map itself part of the challenge: you start in a small room and pay to open doors into more space, more weapons and more danger.
Two shapes of the genre exist. Wave survival (this guide's first playable) is round based: defend a place, survive waves. Open-world survival adds scavenging, crafting, hunger and a base that saves; Roblox lists it as the Open World & Survival RPG subgenre. Start with waves: every system it needs, you will need in the open-world version too.
The systems a zombie survival game needs
| System | What it does | Roblox pieces | Guide |
|---|---|---|---|
| Wave spawner | Sends bigger, tougher waves with a break between them | Server loop, ServerStorage template, PivotTo | This page |
| Zombie AI | Walks at the nearest player and hits in range | Humanoid:MoveTo, SetNetworkOwner | This page and NPC pathfinding |
| Guns and ammo | Server-checked shots, limited magazines, reloads | Tool, RemoteEvent, workspace:Raycast | Gun script |
| Melee | A last resort when ammo runs out | Tool, GetPartBoundsInBox | Sword script |
| Barricades and doors | Boarded windows to repair, doors players pay to open | ProximityPrompt, attributes | Door script |
| Cash and shop | Cash per kill, weapons and perks to buy | leaderstats, server-checked purchases | Shop GUI |
| Revives | A downed teammate can be helped up | ProximityPrompt with HoldDuration | This page |
| Rounds and game over | Start, wave counter, everyone down, back to lobby | Server state | Round system |
| Day and night (open world) | Safer days, dangerous nights | Lighting.ClockTime | Day and night cycle |
| Inventory (open world) | Scavenged items and crafting materials | Saved slots, GUI | Inventory |
The hard part: running a horde on the server
A horror game has one monster; a zombie game may have 25 at once, each a character model with a Humanoid. The decisions that keep that affordable:
- Cap the number alive. The wave can be 60 zombies long, but only 25 are on the map at once. The rest spawn as others die. Players feel the size of the wave without the server paying for all of it.
- Chase in a straight line. Each zombie calls
Humanoid:MoveTotoward the nearest player a few times a second. No path computing. In a zombie game, a zombie stuck on a barricade is not a bug, it is the barricade working. Use pathfinding only for special zombies that must find a way round. - Let the server own them.
SetNetworkOwner(nil)on each zombie's root part stops ownership switching to nearby players, which causes stutter and lets a player's device decide where zombies are. - Clean up. Destroy dead zombies a few seconds after they fall. Dozens of bodies a wave add up.
- Spawn out of sight. Spawn points behind the map's windows and doors, not in the open, so zombies arrive instead of appearing.
Build plan: from a baseplate to launch
- A starting room. A small building with three or four windows, each with a boarded barricade, and an outside area where zombies spawn. Add a
ZombieSpawnsfolder of invisible parts outside the windows. - A zombie. Make a rig, rename it
Zombie, give it a green look and put it in ServerStorage. Check its root part is not anchored. - Waves. Add the ZombieWaves script. Stand in the room with no weapon and watch the waves arrive and grow.
- One weapon. A pistol from the gun guide with limited ammo. Pay cash for kills (the gun script deals the damage; give cash when a zombie's Humanoid dies to the player who hit it last).
- Barricades. Boards that zombies break by standing at them, and a hold prompt that lets players rebuild them for a little cash.
- First playable and test. Ten waves, four players. Watch whether the team spreads out to cover windows or bunches in a corner, and when they first run low on ammo.
- Doors and a wall shop. Paid doors into new rooms with better weapons on the walls. This turns the map into a progression.
- Launch features. Revives, a game over screen with the wave reached, a highest-wave leaderboard, a lobby, two zombie types beyond the basic one, and the maturity questionnaire.
Escalating waves and the zombie chase
One server script runs the whole horde. Each wave has more zombies (6 plus 4 per wave), more health (60 plus 15 per wave) and a little more speed, capped at 16 so a zombie never outruns a walking player. Each zombie walks at the nearest living player and hits when close.
-- Script in ServerScriptService named ZombieWaves.
-- Spawns bigger, tougher waves of ServerStorage.Zombie at the parts in
-- Workspace.ZombieSpawns. Each zombie walks at the nearest living player.
local Players = game:GetService("Players")
local ServerStorage = game:GetService("ServerStorage")
local template = ServerStorage:WaitForChild("Zombie") :: Model -- a rig with a Humanoid
local spawns = workspace:WaitForChild("ZombieSpawns") :: Folder
local MAX_ALIVE = 25 -- zombies on the map at once; the rest wait their turn
local HIT_DAMAGE, HIT_RANGE, HIT_COOLDOWN = 10, 4, 1
local alive = 0
local function nearestPlayer(from: Vector3): (BasePart?, Humanoid?)
local best, bestHumanoid, bestDistance = nil, nil, math.huge
for _, player in Players:GetPlayers() do
local character = player.Character
local root = character and character:FindFirstChild("HumanoidRootPart")
local humanoid = character and character:FindFirstChildOfClass("Humanoid")
if root and root:IsA("BasePart") and humanoid and humanoid.Health > 0 and (root.Position - from).Magnitude < bestDistance then
best, bestHumanoid, bestDistance = root, humanoid, (root.Position - from).Magnitude
end
end
return best, bestHumanoid
end
local function spawnZombie(health: number, speed: number)
local points = spawns:GetChildren()
local zombie = template:Clone()
local humanoid = zombie:FindFirstChildOfClass("Humanoid") :: Humanoid
local root = zombie:FindFirstChild("HumanoidRootPart") :: BasePart
humanoid.MaxHealth, humanoid.Health, humanoid.WalkSpeed = health, health, speed
zombie:PivotTo((points[math.random(#points)] :: BasePart).CFrame + Vector3.new(0, 3, 0))
zombie.Parent = workspace
root:SetNetworkOwner(nil) -- the server moves zombies, so no player can drag them
alive += 1
humanoid.Died:Once(function()
alive -= 1
task.delay(3, zombie.Destroy, zombie)
end)
local nextHit = 0
while humanoid.Health > 0 and zombie.Parent do
local target, victim = nearestPlayer(root.Position)
if target and victim then
humanoid:MoveTo(target.Position) -- straight line: walls and barricades stop it
if (target.Position - root.Position).Magnitude < HIT_RANGE and os.clock() > nextHit then
victim:TakeDamage(HIT_DAMAGE)
nextHit = os.clock() + HIT_COOLDOWN
end
end
task.wait(0.25)
end
end
local wave = 0
while true do
task.wait(15) -- break between waves: repair, buy, regroup
wave += 1
workspace:SetAttribute("Wave", wave)
for _ = 1, 6 + wave * 4 do -- more zombies each wave, each a little tougher and faster
while alive >= MAX_ALIVE do
task.wait(1)
end
task.spawn(spawnZombie, 60 + wave * 15, math.min(10 + wave * 0.5, 16))
task.wait(0.5)
end
repeat
task.wait(1)
until alive == 0
end
MAX_ALIVEis the cap from the section above. Raise it only after testing your biggest wave on a real server with a full team.- Each zombie runs its own small loop four times a second.
MoveTostops on its own after 8 seconds without reaching the goal, so the loop calls it again well before that. TakeDamagedoes nothing while the player has a ForceField, so players who just respawned are briefly safe.- The script never ends a run: dead players respawn and keep fighting. For a real game over, stop respawns during a wave (or use downed players, below), and when no player is left alive, destroy the zombies, show the wave reached and reset.
- For new zombie types, read a type from a list per wave: a runner with high speed and low health, a tank with lots of health and a slow walk, both from different templates in ServerStorage.
Revives: the system that makes it co-op
Without revives, a player who dies early watches the rest of the round. With them, a downed player is a problem the team has to solve under pressure, and those are some of the tensest moments a round can have. A simple version: when a player's health would hit zero, the server sets a Downed attribute instead, slows them to a crawl, and puts a ProximityPrompt with a HoldDuration of a few seconds on them. A teammate who holds it to the end brings them back with some health. If nobody comes in time, they die and respawn next wave.
Do the downed check on the server: keep the Humanoid's health above zero by handling damage yourself (for example in the same place your zombies and weapons call TakeDamage), rather than trying to undo a death after it happens.
Monetization that fits zombie survival
In a co-op PvE game, nobody loses a fight to another player's purchase, so power is easier to sell than in a shooter or a fighting game. The risk moves elsewhere: if a purchase makes the game trivial, the buyer gets bored, and if the team expects one person to carry, everyone else feels useless.
| Item | Roblox feature | Accepted? | Watch out for |
|---|---|---|---|
| Starting weapon | Pass | Yes | A strong gun at wave 1 skips the early game. Make it better than the free pistol, not better than the wall guns. |
| Self-revive | Developer product | Yes | Limit it per match, or the team stops reviving each other. |
| Cosmetics (skins, outfits, kill effects) | Pass or developer product | Yes | None. |
| More ammo or inventory slots | Pass | Mixed | Ammo scarcity is a main source of tension. A little extra is fine; unlimited removes the game. |
| Private server | Private servers | Yes | Squads want to play with people they trust. |
| Watch an ad for a bonus | Rewarded video ads | Only if eligible | Rewards must be developer products. Roblox says ads should not harm the character during play, so offer them in the lobby or between waves, never mid-wave. |
Passes are one-time purchases; developer products can be bought again, so self-revives and ammo refills are developer products. See the game pass guide for checking ownership on the server.
What brings zombie survival players back
- Highest wave. A leaderboard of the best wave per team or per player is the genre's main goal. Show the record on the game over screen.
- New maps. Each map is a new puzzle of windows, doors and choke points. A map with a secret (a hidden weapon, a way to end the waves) gives players something to discover.
- Progression between matches. Levels that unlock new starting loadouts or cosmetics give a reason to play even a run that ends at wave 8.
- Zombie variety. Each update adds a zombie that breaks an old strategy.
- Open world later. Scavenging, crafting and a saved base turn a round-based game into one players live in. It is a big step; ship waves first.
For a single, smarter enemy instead of a horde, see the horror game guide; for defending a path with placed units instead of guns, see the tower defense guide.
Build it with RoCode
RoCode is an independent AI agent for Roblox Studio, not made by Roblox. You describe the game in a web chat and its Studio plugin writes the Luau and builds parts, scripts and UI in the place you have open. For a zombie game it can build the starting room and spawns, the wave and zombie scripts, weapons with server checks, barricades and doors, and add a HUD, a round timer and a shop from its UI kits. It can also build a themed world island, such as a snow or desert canyon area, in one call. It cannot make zombie meshes or animations.
Make the first playable version of a zombie survival game in my place: a small building with 4 boarded windows, zombie spawn points outside, a Zombie rig in ServerStorage, waves that grow in count, health and speed with a 15 second break, at most 25 zombies alive, a pistol with limited ammo, cash per kill in leaderstats and a wave counter on screen.
- Writes the wave, zombie, weapon and barricade scripts with damage and cash decided on the server
- Builds the starting room and spawn points, then adds doors, a shop and revives in rounds
- Can add UI kit screens such as a shooter HUD, a round timer, a shop and notifications
- Can run a test robot that walks, equips a tool and reports PASS or FAIL on what it checked
RoCode does not publish the game or spend Robux, and it cannot say whether wave 20 is fun. The free plan gives free credits every day, no card needed. How RoCode builds a game.
Questions
How do I make zombies chase players in Roblox?
Give each zombie a Humanoid, make the server its network owner, and a few times a second call Humanoid:MoveTo toward the nearest living player. The wave script does this. Use pathfinding only for zombies that must find their way around walls.
How many zombies can a Roblox server handle?
It depends on your zombie models, scripts and map, so measure rather than guess. Start with a cap of around 25 alive at once, test your largest wave on a real server with a full team, and raise it only if the game stays smooth.
How do I make zombie waves harder?
Raise several things together: zombie count, health and speed, and add new zombie types every few waves. Raising only health makes waves longer, not harder.
Can I make a zombie game without scripting?
The map and barricades can be built with parts, but waves, zombie AI, guns and cash need scripts. You can paste the scripts from this page and the gun guide, or describe the game to RoCode and let it write them.
Is selling a strong gun pay to win in a zombie game?
Less so than in PvP, because no other player loses to it. It can still hurt the game by making early waves trivial for the buyer, so make paid weapons a head start rather than the best weapon in the game.
Sources and further reading
- Roblox Creator Docs: Genres. Survival, PvE Shooter, Open World & Survival RPG
- Roblox Engine API: Humanoid. MoveTo timeout and TakeDamage
- Roblox Engine API: BasePart. SetNetworkOwner
- Roblox Engine API: ProximityPrompt. HoldDuration for revives and repairs
- Roblox Creator Docs: Rewarded video ads. developer product rewards, no harm during ads
- Roblox Creator Docs: Content maturity and compliance. violence frequency and fear content
- RoCode guide: Gun script. server-checked shots and ammo
How the code was checked: every script on this page passes Luau's strict type checker against Roblox's API definitions (luau-lsp, 26 October 2026). A type check catches misspelt APIs and wrong types, not game logic, so playtest in Studio before you publish.