I’m making a zombie game, but the AI sometimes doesn’t work, like it actually chases the player, but sometimes, when a zombie spawns for the first time, it like… bugs out and just stays still, he doesn’t do anything, i need help on this, here is both the scripts
oh and before i show it, some people may be saying: “Why don’t you use a loop, bro, that’s the most easy thing ever, just use a loop” EVERY TIME I use a loop, it lags out when there is a bit many zombies, like 7 zombies like what??? Ok now here is the script: (the ai and the spawner)
Spawner:
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local ZombiesFolder = ReplicatedStorage.Zombies
local ZombiesLimit = 7
while task.wait(10) do
if #workspace.Zombies:GetChildren() >= ZombiesLimit then
continue
end
local Zombies = ZombiesFolder:GetChildren()
local RandomZombie = Zombies[math.random(1, #Zombies)]
local NewZombie = RandomZombie:Clone()
NewZombie.Parent = workspace.Zombies
NewZombie:FindFirstChild(NewZombie.Name.."AI").Enabled = true
NewZombie:MoveTo(Vector3.new(math.random(-100, 100), 35, math.random(-100, 100)))
end
AI:
-- Import the module so you can start using it
local ServerStorage = game:GetService("ServerStorage")
local SimplePath = require(ServerStorage.SimplePath)
local RaycastHitbox = require(game.ReplicatedStorage.Modules.RaycastHitboxV4)
local NPC = script.Parent -- Ensure NPC is defined
local AttackSounds = NPC.Attacks
local AttackAnim = NPC.Humanoid:LoadAnimation(NPC.Animations.Attack)
local DamageEvent = game.ReplicatedStorage.Events.DamageEvent
local StunnedAnim = NPC.Humanoid:LoadAnimation(NPC.Animations.Stunned)
local StunnedIdleAnim = NPC.Humanoid:LoadAnimation(NPC.Animations.StunnedIdle)
StunnedAnim.Priority = Enum.AnimationPriority.Action4
StunnedIdleAnim.Priority = Enum.AnimationPriority.Action2
local AttackDB = false
local Players = game:GetService("Players")
local function findClosestPlayer(NPC)
local closestPlayer = nil
local closestDistance = math.huge
for _, player in Players:GetPlayers() do
local character = player.Character
if character and character:FindFirstChild("HumanoidRootPart") then
local distance = (character.HumanoidRootPart.Position - NPC.HumanoidRootPart.Position).Magnitude
if distance < closestDistance then
closestDistance = distance
closestPlayer = player
end
end
end
return closestPlayer
end
function AttackCheck(closestPlayer, path)
local distance = (closestPlayer.Character.HumanoidRootPart.Position - NPC.HumanoidRootPart.Position).Magnitude
if distance < 5 and AttackDB == false then -- Assuming 5 is the attack range
local NewHitbox = RaycastHitbox.new(NPC)
local Params = RaycastParams.new()
Params.FilterType = Enum.RaycastFilterType.Exclude
Params.FilterDescendantsInstances = {NPC}
NewHitbox.OnHit:Connect(function(hit, hum)
local Player = game.Players:GetPlayerFromCharacter(hum.Parent)
if Player and Player:FindFirstChild("Invincible").Value == false then
if Player:FindFirstChild("Parrying").Value == true then
script.Parent.HumanoidRootPart.Anchored = true
StunnedAnim:Play()
AttackAnim:Stop()
StunnedIdleAnim:Play()
task.wait(5)
StunnedAnim:Stop()
StunnedIdleAnim:Stop()
script.Parent.HumanoidRootPart.Anchored = false
--path:Run(closestPlayer.Character.HumanoidRootPart)
else
if Player:FindFirstChild("Invincible").Value == false then
DamageEvent:FireClient(Player)
hum:TakeDamage(5)
Player:FindFirstChild("Invincible").Value = true
--path:Run(closestPlayer.Character.HumanoidRootPart)
end
end
end
end)
local RandomAttackSound = AttackSounds:GetChildren()[math.random(1, #AttackSounds:GetChildren())]
AttackDB = true
NewHitbox:HitStart(1)
RandomAttackSound:Play()
AttackAnim:Play()
task.wait(2)
AttackDB = false
--task.wait(2)
path:Run(closestPlayer.Character.HumanoidRootPart)
else
path:Run(closestPlayer.Character.HumanoidRootPart)
end
end
--if NPC and NPC:WaitForChild("HumanoidRootPart") then
local success, errormessage = pcall(function()
local closestPlayer = findClosestPlayer(NPC)
if closestPlayer then
local path = SimplePath.new(NPC)
path:Run(closestPlayer.Character.HumanoidRootPart)
path.Blocked:Connect(function()
AttackCheck(closestPlayer, path)
closestPlayer = findClosestPlayer(NPC)
end)
path.WaypointReached:Connect(function()
AttackCheck(closestPlayer, path)
closestPlayer = findClosestPlayer(NPC)
end)
path.Error:Connect(function(errorType)
AttackCheck(closestPlayer, path)
closestPlayer = findClosestPlayer(NPC)
end)
path.Reached:Connect(function()
AttackCheck(closestPlayer, path)
closestPlayer = findClosestPlayer(NPC)
end)
end
end)
--end
DamageEvent.OnServerEvent:Connect(function(Player)
Player:FindFirstChild("Invincible").Value = false
end)
Can someone help? I’m having this problem even in the start of development, also the AI breaks only when it spawns for the first time (and sometimes it breaks naturally).
Please be patient, we all just volunteer here, and not everyone knows the answer to your particular issue.
I’m not sure of why, but a good troubleshooting tool is to print variables before they are checked with an if. It tells you what the variable is so you can see any unexpected behavior and trace back to where the variable is set.
Let’s say in this example the output gives you a name you don’t expect. You trace back where the variable is set and look for why it’s different:
print("closestPlayer = ", closestPlayer.Name)
if closestPlayer then
local path = SimplePath.new(NPC)
path:Run(closestPlayer.Character.HumanoidRootPart)
Sorry i was sleeping by the time you responded. hehe, anyways i get what you’re saying. I’m gonna try, i’ll get back to you if something happens with it
So that means the findClosestPlayer function isn’t even firing. This is why we troubleshoot the way I suggested.
Go to the if checks before you call the findClosestPlayer function to troubleshoot why it isn’t happening.
To be honest, i actually changed the whole thing, here is the new zombiespawner (i actually don’t know if this will lag or not, and also i’ll make the damage system later):
local Players = game:GetService("Players")
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local ZombiesFolder = ReplicatedStorage:WaitForChild("Zombies")
local Workspace = game:GetService("Workspace")
local WorkspaceZombiesFolder = Workspace:WaitForChild("Zombies")
local SpawnZombieEvent = ReplicatedStorage:WaitForChild("SpawnZombie")
local ZombiesLimit = 7
local SpawnArea = {minX = -100, maxX = 100, minY = 35, maxY = 35, minZ = -100, maxZ = 100}
local ZombieRarity = {
NormalZombie = 70, -- 70% chance
FastZombie = 20, -- 20% chance
StrongZombie = 10 -- 10% chance
}
local function getRandomPosition()
return Vector3.new(
math.random(SpawnArea.minX, SpawnArea.maxX),
math.random(SpawnArea.minY, SpawnArea.maxY),
math.random(SpawnArea.minZ, SpawnArea.maxZ)
)
end
local function getRandomZombieType()
local totalWeight = 0
for _, weight in ZombieRarity do
totalWeight = totalWeight + weight
end
local randomWeight = math.random(1, totalWeight)
local cumulativeWeight = 0
for zombieType, weight in ZombieRarity do
cumulativeWeight = cumulativeWeight + weight
if randomWeight <= cumulativeWeight then
return zombieType
end
end
end
local function spawnZombie()
local success, errorMessage = pcall(function()
if #WorkspaceZombiesFolder:GetChildren() >= ZombiesLimit then
return
end
local Zombies = ZombiesFolder:GetChildren()
if #Zombies == 0 then
warn("No zombies found in ReplicatedStorage.Zombies")
return
end
local selectedZombieType = getRandomZombieType()
local RandomZombie
for _, zombie in Zombies do
if zombie.Name == selectedZombieType then
RandomZombie = zombie
break
end
end
if not RandomZombie then
warn("Selected zombie type not found: " .. selectedZombieType)
return
end
local NewZombie = RandomZombie:Clone()
NewZombie.Parent = WorkspaceZombiesFolder
NewZombie.HumanoidRootPart:SetNetworkOwner(nil)
local AIScript = NewZombie:FindFirstChild(NewZombie.Name.."AI")
if AIScript then
AIScript.Enabled = true
else
warn("AI script not found for zombie: " .. NewZombie.Name)
end
NewZombie:MoveTo(getRandomPosition())
end)
if not success then
warn("Error in ZombieSpawner: " .. errorMessage)
end
end
local function adjustZombieLimit(newLimit)
ZombiesLimit = newLimit
print("ZombiesLimit adjusted to: " .. ZombiesLimit)
end
SpawnZombieEvent.OnServerEvent:Connect(function(player, action, newLimit)
if action == "spawn" then
spawnZombie()
elseif action == "adjustLimit" and newLimit then
adjustZombieLimit(newLimit)
end
end)
-- Initial spawn loop
game.Players.PlayerAdded:Connect(function(Player)
Player.CharacterAdded:Connect(function(Character)
task.wait(1)
for i = 1, 2 do
spawnZombie()
task.wait(0.3)
end
end)
end)
I keep telling you an easy way to troubleshoot your scripts. You just have to do a tiny of work to identify the area of code that isn’t working and track backwards through it to find out where the issue is.
It’s way easier to find the specific section of code (or even just a single line) that’s giving you trouble and ask forum members for help with that, rather than handing them the entire script and saying ‘it doesn’t work’.
I’m not a great scripter, but if I have a problem I just use this method. Trust me, it helps you out a lot.
Bro, i can’t fix it, what is happening with that AI?! For some reason, i tried troubleshooting the way you suggested, but it looks like the closest player function fires, but it for some reason just don’t run to the player, and for some reason, it like, do you know a loop? Exactly, it has a break function, it is like you’re calling the break function to stop the loop, which is not what i’m doing! What should I do? Wrap the function into a pcall?!