Zombies freezing after spawning

Hello, I am having this issue with my zombies:

robloxapp-20230901-2044448.wmv (2.5 MB)

The zombies are standing still for a short time after spawning in, it is related to the HumanoidRootPart being anchored during the spawning anim, but I need it to be anchored for the cool spawning effect. Any ways to fix other than make it so the HumanoidRootPart stays anchored?

Code:

local pathfindingService = game:GetService("PathfindingService")
local RunService = game:GetService("RunService")
local TweenService = game:GetService("TweenService")
local DebrisService = game:GetService("Debris")

local entity = script.Parent
local humanoid = entity.Humanoid
local defaultWalkSpeed = humanoid.WalkSpeed
local sightDistance = 60
local attackRange = 5
local attackDelay = 1.5
local damage = 15
local attackAnim = humanoid:LoadAnimation(script.Attack)
local deathAnim = humanoid:LoadAnimation(script.Death)
local spawnAnim = humanoid:LoadAnimation(script.Spawn)
local canAttack = true
local canDie = true

entity.HumanoidRootPart:SetNetworkOwner(nil)

local function canSeeTarget(target)
	local origin = entity.HumanoidRootPart.Position
	local direction = (target.HumanoidRootPart.Position - entity.HumanoidRootPart.Position).unit * sightDistance
	local ray = Ray.new(origin, direction)
	
	
	local hit, pos = workspace:FindPartOnRay(ray, workspace.Zombies)
	
	if hit then
		if hit:IsDescendantOf(target) then
			return true
		else
			return false
		end
	end
end

local function findTarget()
	local players = game.Players:GetPlayers()
	local maxDistance = sightDistance
	local nearestTarget
	
	for index, player in pairs(players) do
		if player.Character then
			local target = player.Character
			local distance = (entity.HumanoidRootPart.Position - target.HumanoidRootPart.Position).Magnitude
			
			if distance <= maxDistance and canSeeTarget(target) and target.Humanoid.Health > 0 then
				nearestTarget = target
				maxDistance = distance
			end
		end
	end
	
	return nearestTarget
end

local function getPath(destination)
	local pathParams = {
		["AgentHeight"] = 5, 
		["AgentRadius"] = 2.6,
		["AgentCanJump"] = false
	}
	local path = pathfindingService:CreatePath(pathParams)

path:ComputeAsync(entity.HumanoidRootPart.Position, destination.Position)
	
	return path
end

local function generateSound(folder)
	local randomNumber = Random.new()
	local possibleSounds = folder:GetChildren()
	local randomSound = possibleSounds[randomNumber:NextInteger(1, #possibleSounds)]
	local selectedSound = randomSound:Clone()
	selectedSound.Parent = entity.HumanoidRootPart
	
	return selectedSound
end

local function attack(target)
	local distance = (entity.HumanoidRootPart.Position - target.HumanoidRootPart.Position).Magnitude
	
	if distance <= attackRange and canAttack then
		canAttack = false
		attackAnim:Play()	
		attackAnim:GetMarkerReachedSignal("Attack"):Wait()
		if (entity.HumanoidRootPart.Position - target.HumanoidRootPart.Position).Magnitude <= attackRange then
			target.Humanoid.Health -= damage
		end
		
		attackAnim.Ended:Wait()
		task.wait(attackDelay)
		canAttack = true
	end
end

local function patrol()
	local target = findTarget()
	local attackCo = coroutine.create(attack)
	if target and entity.HumanoidRootPart.Anchored == false then
		coroutine.resume(attackCo, target)
		humanoid:MoveTo(target.HumanoidRootPart.Position)
	end
end

local function death()
	canDie = false
	entity.HumanoidRootPart.Anchored = true
	entity.HumanoidRootPart.Death:Play()
	
	deathAnim:Play()
	deathAnim:GetMarkerReachedSignal("Death"):Wait()
	entity:Destroy()
end

humanoid.Died:Connect(death)

RunService.Heartbeat:Connect(function()
	if humanoid.Health <= 0 and canDie then
		
	elseif entity.HumanoidRootPart.Anchored == false then
		patrol()
		wait(0.01)
	end
end)

local function entitySpawned(property)
	if property == "Parent" then
		
		local forceField = Instance.new("ForceField")
		forceField.Visible = false
		forceField.Parent = entity

		entity.HumanoidRootPart.Anchored = true

		spawnAnim:Play()
		spawnAnim.Ended:Wait()

		entity.HumanoidRootPart.Anchored = false
		forceField:Destroy()
	end
end

entity.Changed:Connect(entitySpawned)
2 Likes

This is your issue;

		entity.HumanoidRootPart.Anchored = true

		spawnAnim:Play()
		spawnAnim.Ended:Wait()

		entity.HumanoidRootPart.Anchored = false

You are anchoring the HumanoidRootPart until the spawn animation ends, which is preventing the NPC from moving until it’s done. Change it to this instead:

entity.HumanoidRootPart.Anchored = false
spawnAnim:Play()
spawnAnim.Ended:Wait()
1 Like

If I do that, then the zombies move during the spawning animation.

1 Like

Can you check to see if you have a window of time at the end of your animation where the NPC stops moving? That may be the issue

1 Like

I know for a fact there is not. After they get un-anchored the zombies act like a static object for about 5 seconds, they can be pushed over and won’t move (but they will still attack.) It’s shown in the video.

1 Like

On the secondline within your entitySpawned function below the if statement, do me a favor and add a print(“test”) line to see if the function is fired as soon as the animation ends. Send me a video with the results

Do you want it here

local function entitySpawned(property)
	if property == "Parent" then
		print("test") --here it is
		local forceField = Instance.new("ForceField")
		forceField.Visible = false
		forceField.Parent = entity

		entity.HumanoidRootPart.Anchored = true

		spawnAnim:Play()
		spawnAnim.Ended:Wait()

		entity.HumanoidRootPart.Anchored = false
		forceField:Destroy()
	end
end

or here

local function entitySpawned(property)
	if property == "Parent" then
		
		local forceField = Instance.new("ForceField")
		forceField.Visible = false
		forceField.Parent = entity

		entity.HumanoidRootPart.Anchored = true

		spawnAnim:Play()
		spawnAnim.Ended:Wait()
        print("test") --here it is

		entity.HumanoidRootPart.Anchored = false
		forceField:Destroy()
	end
end

Cause I am confused on where exactly you want it.

may as well do both and name them differently

It printed both times, and the original video is at the top of my post.

i want to see a new video with the new results after printing, i already know they will both print but i dont know how soon they will. im just using this to narrow down the possible problem

How can I show you the output at the same time then?? I’m using studio’s built-in recording.

repeat what you did in the video you sent at the top of this thread and send me a new video with your output open again. use obs or something of that sort

Here they are


Try adding a IsSpawning variable instead of anchoring.

local IsSpawning = true

Then you can use it on patrol() and entitySpawned().

local function patrol()
	local target = findTarget()
	local attackCo = coroutine.create(attack)
	if target and not IsSpawning then
		coroutine.resume(attackCo, target)
		humanoid:MoveTo(target.HumanoidRootPart.Position)
	end
end
local function entitySpawned(property)
	if property == "Parent" then
		IsSpawning = true
		
		local forceField = Instance.new("ForceField")
		forceField.Visible = false
		forceField.Parent = entity

		spawnAnim:Play()
		spawnAnim.Ended:Wait()

		forceField:Destroy()
		IsSpawning = false
	end
end
1 Like

That’s sort of what I had wanted, but then this is the result (the pink block is the HumanoidRootPart):

1 Like

Try setting the Animation Priority of spawnAnim to Action4

spawnAnim.Priority = Enum.AnimationPriority.Action4
1 Like

No difference, the problems seems to be with the zombie colliding with the ground, but the only thing with CanCollide set to true is the HumanoidRootPart. I avoided this problem by anchoring the HumanoidRootPart, but it seems that makes them act like a static model and fall over for about 5 seconds. I am trying to achieve a spawning animation similar to the one in Guts and Blackpowder on Roblox.

1 Like