Why does NPC freeze after target dies?

Hello. Ive done some researching on this problem, but I have found nothing.

Basically, I have made an AI that finds and kills players and other npcs.

However, after a kill, the AI will stand still, and will keep standing still until the player or npc despawns.
After the player/npc despawns, the AI goes to killing people again.

Anyway to fix this?

My code: (While not recommended to look at it as it causes loss of braincells, you can tell I am in a struggle to try and make this work)

local replicatedStorage = game:GetService("ReplicatedStorage")
local pathModule = require(script.SimplePath)

local maxDistance = math.huge 
local players = game:GetService("Players")
local parent = script.Parent

parent.PrimaryPart:SetNetworkOwner(nil)

local aware = false
local human = script.Parent:WaitForChild("Humanoid")

local DAMAGE = 5

local AMMO = 20
local MAX_AMMO = 20

local moving_backwards = false
local cooldown = false
local is_reloading = false

local screenShakeEvent = replicatedStorage:WaitForChild("events"):WaitForChild("remotes"):WaitForChild("shake_remote") 

task.wait(1)

local ignore = {}

function findTarget()
	local closest_player, closest_distance = nil, maxDistance
	for i, player in pairs(workspace:GetDescendants()) do
		if player:IsA("Model") and player:FindFirstChildOfClass("Humanoid") and player ~= parent and not table.find(ignore, player) then
			local faction = player:FindFirstChild("faction")
			if faction.Value ~= parent.faction.Value then
				local char = player
				local distance = (parent.PrimaryPart.Position - char.HumanoidRootPart.Position).Magnitude
				local targethuman:Humanoid = char:FindFirstChildOfClass("Humanoid")

				if targethuman.Health <= 0 then
					closest_player = nil
					closest_distance = maxDistance
					return 
				end

				if targethuman.Health > 0 then
					if distance < closest_distance then
						closest_player = char
						closest_distance = distance
					end
				end
			end
		end
	end
	return closest_player 
end

function CREATE_TRAIL_(ORIGIN, POINT)
	local REPLICATED_STORAGE = game:GetService("ReplicatedStorage")
	local MISCS = REPLICATED_STORAGE.miscs
	local BULLET = MISCS.Bullet:Clone()
	local TRAIL = MISCS.Trail:Clone()

	TRAIL.Attachment0.WorldPosition = ORIGIN
	TRAIL.Attachment0.WorldCFrame = CFrame.lookAt(TRAIL.Attachment0.WorldPosition, POINT)

	TRAIL.Attachment1.WorldPosition = POINT
	TRAIL.Attachment1.WorldCFrame = CFrame.lookAt(TRAIL.Attachment1.WorldPosition, POINT)

	BULLET.Position = ORIGIN
	BULLET.CFrame = CFrame.lookAt(ORIGIN, POINT)

	TRAIL.Parent = workspace 
	BULLET.Parent = workspace

	coroutine.wrap(function()
		local LOOP
		local RUN_SERVICE = game:GetService("RunService")

		LOOP = RUN_SERVICE.Heartbeat:Connect(function(DT)
			BULLET.CFrame *= CFrame.new(0, 0, -10 * (DT * 60))
			if (BULLET.Position - POINT).Magnitude < 4 or (ORIGIN - BULLET.Position).Magnitude > 1000 then
				BULLET:Destroy()
				LOOP:Disconnect()
			end
		end)
	end)()

	local TWEEN_SERVICE = game:GetService("TweenService")
	local GOAL = {}
	GOAL = {Width0 = 0}

	local TWEEN = TWEEN_SERVICE:Create(TRAIL.Beam, TweenInfo.new(1), GOAL)
	TWEEN:Play()

	GOAL = {Width1 = 0}

	local TWEEN = TWEEN_SERVICE:Create(TRAIL.Beam, TweenInfo.new(1), GOAL)
	TWEEN:Play()

	game:GetService("Debris"):AddItem(TRAIL, 2)
	game:GetService("Debris"):AddItem(BULLET, 5)

	GOAL = nil
end 

local parry_cooldown = false
function parry_()
	coroutine.wrap(function()
		if parry_cooldown then return end
		parry_cooldown = true
		
		task.wait(0.1)

		local parry = parent.Humanoid.Animator:LoadAnimation(parent.Animations.Parry)
		parry:Play()
		
		parry:AdjustSpeed(0.65)

		parent.character_values.is_parrying.Value = true

		parry.Stopped:Wait()

		parent.character_values.is_parrying.Value = false
		
		task.wait(1.5)
		
		parry_cooldown = false
	end)()
end

function FIRE_(target)
	local can_see = false
	
	local enemy_hrp = target.Head 
	local origin = parent.HumanoidRootPart.Position
	local table_ = {parent} 

	for i, player in pairs(workspace:GetDescendants()) do
		if player:IsA("Model") and player:FindFirstChildOfClass("Humanoid") and player ~= parent then 
			local faction = player:FindFirstChild("faction")
			if faction.Value == parent.faction.Value then
				table.insert(table_, player)
			end
		end
	end
	
	local params = RaycastParams.new()
	params.FilterType = Enum.RaycastFilterType.Exclude
	params.FilterDescendantsInstances = table_

	local direction = (enemy_hrp.Position - Vector3.new(0, 0.5, 0) - origin).Unit 

	local raycast = workspace:Raycast(origin, direction * 3000, params)

	if raycast then
		local model = raycast.Instance:FindFirstAncestorOfClass("Model")
		if model then
			local target_human = model:FindFirstChildOfClass("Humanoid")
			if target_human then
				can_see = true
			end
		end
	end
	
	if not can_see then return end
	
	can_see = false
	
	coroutine.wrap(function()
		if cooldown then return end
		cooldown = true

		local number = math.random(5, 20)
		for i = 1, number do
			
			if AMMO <= 0 then
				cooldown = true
				is_reloading = true
				local anim = parent.Humanoid.Animator:LoadAnimation(parent.Animations.Reload)
				anim:Play()
				
				task.wait(3)
				
				AMMO = MAX_AMMO
				cooldown = false
				is_reloading = false
				return
			end
			if human.Health <= 0 then return end
			
			AMMO -= 1
			
			local can_see = false

			local enemy_hrp = target.Head 
			local origin = parent.HumanoidRootPart.Position

			local params = RaycastParams.new()
			params.FilterType = Enum.RaycastFilterType.Exclude
			params.FilterDescendantsInstances = {parent, parent["SCAR-H"]}

			local direction = (enemy_hrp.Position - Vector3.new(0, 0.5, 0) - origin).Unit 

			local raycast = workspace:Raycast(origin, direction * 3000, params)

			if raycast then
				local model = raycast.Instance:FindFirstAncestorOfClass("Model")
				if model then
					local target_human = model:FindFirstChildOfClass("Humanoid")
					if target_human then
						can_see = true
					end
				end
			end

			if not can_see then
				cooldown = false
				return 
			end
			
			parent.Humanoid.Animator:LoadAnimation(parent.Animations.Fire):Play()

			for i, particle in pairs(parent["SCAR-H"].Components.MuzzleFlash:GetChildren()) do
				if particle:IsA("ParticleEmitter") then
					particle:Emit(20)
				elseif particle:IsA("Sound") then
					particle:Play()
				end
			end
			
			local origin = parent.HumanoidRootPart.Position
			
			local params = RaycastParams.new()
			params.FilterType = Enum.RaycastFilterType.Exclude
			params.FilterDescendantsInstances = {parent, parent["SCAR-H"]}

			local direction = (enemy_hrp.Position - Vector3.new(0, 0.5, 0) - origin).Unit 
			
			local raycast = workspace:Raycast(origin, direction * 3000, params)
			
			if raycast then
				CREATE_TRAIL_(origin, raycast.Position)
				
				local model = raycast.Instance:FindFirstAncestorOfClass("Model")
				if model then
					local target_human = model:FindFirstChildOfClass("Humanoid")
					if target_human then
						target_human:TakeDamage(DAMAGE) 
						if players:GetPlayerFromCharacter(target_human.Parent) then 
							screenShakeEvent:FireClient(players:GetPlayerFromCharacter(target_human.Parent), 3, false) 
						end
					end
				end
			else
				CREATE_TRAIL_(origin, direction)
			end
			
			task.wait(0.1) 
		end

		task.wait(number/10)

		cooldown = false 
	end)()
end

local target_goal

function backwards_()
	target_goal = target_goal.HumanoidRootPart
	task.spawn(function()
		local number = math.random(1, 2)
		if number == 1 then
			moving_backwards = true
			local direction = (parent.HumanoidRootPart.Position - target_goal.Position).Unit

			parent.Humanoid.AutoRotate = false
			parent.Humanoid:MoveTo(parent.HumanoidRootPart.Position + direction * 10)

			task.wait(2)

			if not parent.Humanoid.MoveToFinished then
				parent.Humanoid.WalkSpeed = 0
				moving_backwards = false
				parent.Humanoid.AutoRotate = true
				return 
			end
			

			parent.Humanoid.MoveToFinished:Wait()
			moving_backwards = false
			parent.Humanoid.AutoRotate = true
		else
			moving_backwards = true
			parent.Humanoid.AutoRotate = false
			parent.Humanoid:MoveTo(parent.HumanoidRootPart.CFrame.RightVector * 5)

			task.wait(2)

			if not parent.Humanoid.MoveToFinished then
				parent.Humanoid.WalkSpeed = 0
				moving_backwards = false
				parent.Humanoid.AutoRotate = true
				return 
			end

			parent.Humanoid.MoveToFinished:Wait()
			moving_backwards = false
			parent.Humanoid.AutoRotate = true
		end
	end)
end

local HRP = parent.HumanoidRootPart

local bodyGyro = Instance.new("BodyGyro")
bodyGyro.Parent = HRP
bodyGyro.MaxTorque = Vector3.new(math.huge, math.huge, math.huge)

function loop_()
	if human. Health <= 0 then return end
	local target = findTarget()
	if target then
		if target.Humanoid.Health <= 0 then
			if not table.find(ignore, target) then
				table.insert(ignore, target)
			end
			return
		end
		
		aware = true
		if aware then
			aware = true
			local goal 
			
			goal = target:WaitForChild("HumanoidRootPart").Position 
			
			bodyGyro.CFrame = CFrame.new(HRP.Position, goal)

			local path = pathModule.new(parent)

			path.Visualize = false

			path.Blocked:Connect(function()
				if not moving_backwards then
					path:Run(goal)  
				end 
			end)

			path.WaypointReached:Connect(function()
				if not moving_backwards then
					path:Run(goal)  
				end
			end)

			path.Error:Connect(function(errorType)
				if not moving_backwards then
					path:Run(goal)  
				end
			end)

			if not moving_backwards then
				path:Run(goal)  
			end
			
			if (parent.HumanoidRootPart.Position - goal).Magnitude < 100 then
				FIRE_(target)
			end
			if (parent.HumanoidRootPart.Position - goal).Magnitude < 10 then
				target_goal = target
				parry_() 
				coroutine.resume(coroutine.create(backwards_))
			end
		end
	end
end

while task.wait() do
	loop_()
end

The problem is that the NPC keeps chasing the player even if he is dead. Try to change the script so that it doesn’t chase a player who has already died.

Make it so that if the target’s health is at or below 0 it will search another target. There must be some kind of loop in one of the modules you have or that is called by the loop_() function, so make the one that actually has the NPC walk also detect if the target is dead.

Already did this. ‎ ‎ ‎ ‎ ‎ ‎ ‎ ‎ ‎

Fixed it myself.

			target.Humanoid.HealthChanged:Connect(function()
				if target.Humanoid.Health <= 0 then
					if not table.find(ignore, target) then
						table.insert(ignore, target)
						target = nil
						return
					end
				end
			end)
2 Likes

This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.