Zombie flops around after being killed

So, after i kill the Zombie the death animation runs but after a few seconds it flops around, anyway of fixing this?

Zombie Script:

local plr = game:GetService("Players")
local myHuman = script.Parent:WaitForChild("Humanoid")
local myRoot = script.Parent:WaitForChild("HumanoidRootPart")
local head = script.Parent:WaitForChild("Head")
local lowerTorso = script.Parent:WaitForChild("LowerTorso")

local grab = script.Parent:WaitForChild("Grab")
local grabAnim = myHuman:LoadAnimation(grab)
grabAnim.Priority = Enum.AnimationPriority.Action

local die = script.Parent:WaitForChild("Death_1")
local dieAnim = myHuman:LoadAnimation(die)
dieAnim.Priority = Enum.AnimationPriority.Action

local grabSound = head:WaitForChild("Attack")
local screamSound = head:WaitForChild("Scream")

local clone = script.Parent:Clone()

function walkRandomly()
	local xRand = math.random(-50,50)
	local zRand = math.random(-50,50)
	local goal = myRoot.Position + Vector3.new(xRand,0,zRand)
	
	local path = game:GetService("PathfindingService"):CreatePath()
	path:ComputeAsync(myRoot.Position, goal)
	local waypoints = path:GetWaypoints()
	
	if path.Status == Enum.PathStatus.Success then
		for _, waypoint in ipairs(waypoints) do
			if waypoint.Action == Enum.PathWaypointAction.Jump then
				myHuman.Jump = true
			end
			myHuman:MoveTo(waypoint.Position)
			local timeOut = myHuman.MoveToFinished:Wait(1)
			if not timeOut and myHuman.Health ~= 0 then
				print("Got stuck")
				myHuman.Jump = true
				walkRandomly()
			end
		end
	else
		print("Path failed")
		wait(1)
		walkRandomly()
	end
end

function findPath(target)
	local path = game:GetService("PathfindingService"):CreatePath()
	path:ComputeAsync(myRoot.Position,target.Position)
	local waypoints = path:GetWaypoints()
	
	if path.Status == Enum.PathStatus.Success then
		for _, waypoint in ipairs(waypoints) do
			if waypoint.Action == Enum.PathWaypointAction.Jump then
				myHuman.Jump = true
			end
			myHuman:MoveTo(waypoint.Position)
			local timeOut = myHuman.MoveToFinished:Wait(1)
			if not timeOut then
				myHuman.Jump = true
				print("Path too long!")
				findPath(target)
				break
			end
			if checkSight(target) then
				repeat
					print("Moving directly to the target")
					myHuman:MoveTo(target.Position)
					attack(target)
					wait(0.1)
					if target == nil then
						break
					elseif target.Parent == nil then
						break
					end
				until checkSight(target) == false or myHuman.Health < 1 or target.Parent.Humanoid.Health < 1
				break
			end
			if (myRoot.Position - waypoints[1].Position).magnitude > 20 then
				print("Target has moved, generating new path")
				findPath(target)
				break
			end
		end
	end
end

function checkSight(target)
	local ray = Ray.new(myRoot.Position, (target.Position - myRoot.Position).Unit * 40)
	local hit,position = workspace:FindPartOnRayWithIgnoreList(ray, {script.Parent})
	if hit then
		if hit:IsDescendantOf(target.Parent) and math.abs(hit.Position.Y - myRoot.Position.Y) < 3 then
			print("I can see the target")
			return true
		end
	end
	return false
end

function findTarget()
	local dist = 50
	local target = nil
	local potentialTargets = {}
	local seeTargets = {}
	for i,v in ipairs(workspace:GetChildren()) do
		local human = v:FindFirstChild("Humanoid")
		local torso = v:FindFirstChild("Torso") or v:FindFirstChild("HumanoidRootPart")
		if human and torso and v.Name ~= script.Parent.Name then
			if (myRoot.Position - torso.Position).magnitude < dist and human.Health > 0 then
				table.insert(potentialTargets,torso)
			end
		end
	end
	if #potentialTargets > 0 then
		for i,v in ipairs(potentialTargets) do
			if checkSight(v) then
				table.insert(seeTargets, v)
			elseif #seeTargets == 0 and (myRoot.Position - v.Position).magnitude < dist then
				target = v
				dist = (myRoot.Position - v.Position).magnitude
			end
		end
	end
	if #seeTargets > 0 then
		dist = 100
		for i,v in ipairs(seeTargets) do
			if (myRoot.Position - v.Position).magnitude < dist then
				target = v
				dist = (myRoot.Position - v.Position).magnitude
			end
		end
	end
	if target then
		if math.random(20) == 1 then
			screamSound:Play()
		end
	end
	return target
end


function attack(target)
	if (myRoot.Position - target.Position).magnitude < 5 then
		grabAnim:Play()
		grabSound:Play()
		if target.Parent ~= nil then
			target.Parent.Humanoid:TakeDamage(2)
		end
		wait(0.4)
	end
end

function died()
	if myHuman.Health <= 0 then
		myHuman.Parent.HumanoidRootPart.Anchored = true
		dieAnim:Play()
		task.wait(1)
		myHuman.Parent.HumanoidRootPart.Anchored = false
	end
	--clone.Parent = workspace.Zombies
	--game:GetService("Debris"):AddItem(script.Parent,0.1)
end

myHuman.Died:Connect(died)

lowerTorso.Touched:Connect(function(obj)
	if not obj.Parent:FindFirstChild("Humanoid") then
		myHuman.Jump = true
	end
end)

function main()
	local target = findTarget()
	if target then
		myHuman.WalkSpeed = 16
		findPath(target)
	else
		myHuman.WalkSpeed = 8
		walkRandomly()
	end
end

while wait(0.1) do
	if myHuman.Health < 1 then
		break
	end
	main()
end

3 Likes

I’d expect this to be happening because you are unanchoring the humanoidrootpart after the animation. To fix this I would lengthen the animation slightly then remove the zombie before the animation finishes.

1 Like

Ok I see your point but I would like the zombie to stay in the position he’s in when killed and stay on map because eventually I will be adding a gui inventory to them, that allows the player to see if there any items that the zombie may have

Ok, could you potentially keep the zombie anchored and update its CFrame after the animation has finished?

1 Like

I’ll try that, that might work

ok so unanchored after the animation and this what happens

you will need to get the CFrame of the torso before it pops back up, then move the humanoidRootPart to that CFrame.

1 Like

ok how do I get its current position every time, because if copy his position and then I kill him somewhere else the next time, his body moves to the last position I kill him?

function died()
	if myHuman.Health <= 0 then
		myHuman.Parent.HumanoidRootPart.Anchored = true
		dieAnim:Play()
		
		task.wait(1)
		--myHuman.Parent.HumanoidRootPart.Anchored = false
		myHuman.Parent.HumanoidRootPart.CFrame = CFrame.new() 
	end
end

myHuman.Died:Connect(died)
1 Like

I would achieve something like this:

function died()
    if myHuman.Health <= 0 then
		myHuman.Parent.HumanoidRootPart.Anchored = true
		dieAnim:Play()
		
		task.wait(0.5) --This is however long it is until the zombie falls to the floor
        local updateCF = myHuman.Parent.Torso.CFrame
        task.wait(0.5)
		myHuman.Parent.HumanoidRootPart.CFrame = updateCF
	end
1 Like

id of thought itd be an issue with humanoid states/the zombie not actually entering a dead state and/or being allowed to leave a dead state

.Died in humanoids is also incredibly weird, thank roblox for that one

1 Like

I’ve tried using myHuman:GetStateEnabled(Enum.HumanoidStateType.Dead, true) but he stands back up.

1 Like

He still stands back up after being killed smh this is so weird, not sure I’ve tried rag dolling him, anchoring him, changing his state to died, changing his Orientation, nothing seems to work and keep him on the ground.

1 Like

I have had this type of problem before, when I used pathfinding for an npc, I think it is due to the NetworkOwner, something that I solve for this type of problem is to use the function “:SetNetworkOwner()” what I would do is the following ,at the beginning of the main script put workspace.“ZombieName”.HumanoidRootPart:SetNetworkOwner(nil)

1 Like

Changing the NetworkOwner also helps to avoid bugs when changing the state of an npc with ChangeState(), sometimes the function did not change the state of my npc, but when using :SetNetworkOwner(nil) the error disappeared

1 Like

Something that I must clarify for you is that it is not necessary to apply this to the player characters, since their NetworkOwner is not the server but rather their Device itself, on the other hand, the npcs, since they are not players, their NetworkOwner is the server, and that is sometimes causes problems

1 Like

sill not changing him from standing back up after dying, I’m so confused

1 Like

Send me the model of your zombie so I can do some tests and find the error

2 Likes

Test Zombie.rbxm (41.4 KB)

1 Like

Looks like there’s a few issues going on.

Firstly, you are trying to set the humanoid state to dead by using “GetStateEnabled()” You need to use “SetStateEnabled()”

myHuman:SetStateEnabled(Enum.HumanoidStateType.Dead,true)

When you anchor a part, the NetworkOwnership is automatically set to the server. So no need to anchor the HumanoidRootPart then set the NetworkOwnership to nil after the zombie dies

Another thing is when a humanoid is fallen over, it will get up, which looks like what your zombie is doing, so you should disable the GettingUp state on the humanoid when they die.

function died()
	if myHuman.Health <= 0 then
		myHuman:SetStateEnabled(Enum.HumanoidStateType.Getting, false)
		myHuman:SetStateEnabled(Enum.HumanoidStateType.Dead, true)
		myHuman.Parent.HumanoidRootPart.Anchored = true
		dieAnim:Play()
		
		task.wait(0.5) --This is however long it is until the zombie falls to the floor
		local updateCF = myHuman.Parent.Torso.CFrame
		task.wait(0.5)
		myHuman.Parent.HumanoidRootPart.CFrame = updateCF
	end
end

Also with animating, the animated limbs will go back to their original cframe after the animation is done playing. So you could anchor all the limbs once they are in the lying down position. But you’ll run into an issue where the limbs could hang over an edge without falling over since they are anchored.

So a hacky solution off the top of my head (Untested) would be to anchor all the limbs once they are in the lying down/dead position and set them to CanCollide true. Then destroy any welds connected to the HumanoidRootPart. Then you could replace the limb welds with Ball Constraints or something that would make them dangle around. Then unanchor all the limbs.

1 Like

nope still gets up, it’s unreal how hard it is to just make a dead NPC stay down smh

1 Like