I have a script that spawns a few “FakeZombies”, the FakeZombies break barriers and then spawn the actual “Zombie”
In the FakeZombie and Zombie model there is a script that changes a value in replicated storage called ZombiesCount by -1, the main script checks that value so it knows once the player has killed all the zombies.
I’ve tried making loops that check the number of Zombies and FakeZombies spawned at a time so it can add a limit to amount spawned. I want to make it so if about 25 Zombies/FakeZombies are spawned in then it will stop spawning more until one has been killed and there is room.
Here is my script, any help is appreciated!
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local ZombiesCount = ReplicatedStorage:WaitForChild("ZombiesCount")
local Folder = workspace.ZombiesFolder -- Folder
-- Configuration
local IntermissionDuration = 8 -- time until next round
local InitialZombiesCount = 5
local ZombiesCountIncrement = 2
local maxZombiesCount = 3
-- Variables
local zombieHealth = 80
local zombieSpeed = 8
local roundNumber = 0
local zombiesRemaining = 0
--When a round starts, teleport all players that are dead to the map spawn.
local DeadPart = workspace:FindFirstChild("Dead")
local AlivePart = workspace:FindFirstChild("Alive")
local function teleportPlayers()
for _, player in pairs(game.Players:GetPlayers()) do
local character = player.Character
if character then
local humanoid = character:FindFirstChildOfClass("Humanoid")
if humanoid then
local distance = (DeadPart.Position - humanoid.RootPart.Position).Magnitude
if distance <= 10 then
humanoid.RootPart.CFrame = AlivePart.CFrame
end
end
end
end
end
function startRound()
teleportPlayers()
roundNumber = roundNumber + 1
zombiesRemaining = InitialZombiesCount + ZombiesCountIncrement * (roundNumber - 1)
zombieHealth = zombieHealth * 1.25
ZombiesCount.Value = zombiesRemaining
ReplicatedStorage.RoundNumber.Value = roundNumber
-- Spawn zombies
for i = 1, zombiesRemaining do
local Folder_Children = Folder:GetChildren()
local ZombieClone = ReplicatedStorage.FakeZombie:Clone()
ZombieClone.Humanoid.MaxHealth = zombieHealth
ZombieClone.Humanoid.Health = zombieHealth
ZombieClone.Humanoid.WalkSpeed = zombieSpeed
ZombieClone.Parent = workspace.ZombiesFolder
task.wait(1)
end
-- Check if round is over
while zombiesRemaining > 0 do
task.wait(1)
zombiesRemaining = ZombiesCount.Value
end
-- If round is over then start next
if zombiesRemaining <= 0 then
task.wait(IntermissionDuration)
startRound()
end
-- Start next round
end
-- Start first round
task.wait(IntermissionDuration)
startRound()
teleportPlayers()
ZombiesCount is a NumberValue. The neat thing about those, is that they are objects that have events that you can wait for. But before I show you how to do that, I have an advice:
Your startRound() function is recursive. That means it executes itself at the end. Normally this would not be a problem, but this is generally discouraged for anything else than really simple functions. It can cause a lot of problems if you are not careful and will be slowly leaking memory.
Granted, probably not much, but there are better ways to solve this. Let me introduce to you coroutines. By splitting Your script into logical chunks, you can have them working along side each other. And you can replace recursive function with an infinite loop.
Here is the code:
-- add this to configuration
local maxZombiesOnMap = 25
function startRound()
teleportPlayers()
roundNumber = roundNumber + 1
zombiesRemaining = InitialZombiesCount + ZombiesCountIncrement * (roundNumber - 1)
zombieHealth = zombieHealth * 1.25
ZombiesCount.Value = zombiesRemaining
ReplicatedStorage.RoundNumber.Value = roundNumber
-- Spawn zombies
-- here is the first coroutine
-- this coroutine will handle the zombie spawning
task.spawn(function()
--create new variable, as zombiesRemaining will be overwritten by players killing zombies
local zombiesToSpawn = zombiesRemaining
local zombiesOnMap = 0
while zombiesToSpawn > 0 do
--this loop will pause the spawner, when there are too many zombies
zombiesOnMap = ZombiesCount.Value - zombiesToSpawn
while zombiesOnMap >= maxZombiesOnMap do
ZombiesCount.Changed:Wait()
-- double check, as changed event does not guarantee that the condition is met
zombiesOnMap = ZombiesCount.Value - zombiesToSpawn
end
local Folder_Children = Folder:GetChildren()
local ZombieClone = ReplicatedStorage.FakeZombie:Clone()
ZombieClone.Humanoid.MaxHealth = zombieHealth
ZombieClone.Humanoid.Health = zombieHealth
ZombieClone.Humanoid.WalkSpeed = zombieSpeed
ZombieClone.Parent = workspace.ZombiesFolder
-- update the counter
zombiesToSpawn -= 1
task.wait(1)
end
end)
-- Check if round is over
while zombiesRemaining > 0 do
--task.wait(1)
--this is better
ZombiesCount.Changed:Wait()
zombiesRemaining = ZombiesCount.Value
end
--[[
this is bad, as recursive function like this will cause a memory leak
if zombiesRemaining <= 0 then
task.wait(IntermissionDuration)
startRound()
end--]]
end
-- Start first round
-- loop the function here
-- you may use coroutine if you plan to add more statements later in the script
task.spawn(function() -- this is optional, if while true loop is the last thing in the script, this may be removed
while true do
task.wait(IntermissionDuration)
startRound()
--no need to teleport players, as you do it inside the startRound() function anyway
end
end)