Scripting HelpersARCHIVE
A little piece of Roblox history. Preserved for everyone, one question at a time.Read about the archive →
COMMUNITY QUESTION

[SOLVED] Why does the Monster AI doesn't chase when a player is near?

I am making the AI for the monster in my horror maze game. It works fine, but it follows the waypoint instead of chasing me when I get close. And the AI keeps bumping into walls when they can choose a longer way to get to that waypoint without bumping in walls.

Here is the video recording, the photo of all waypoints in the maze, and the AI Script:

local PathfindingService = game:GetService("PathfindingService")
local Players = game:GetService("Players")
local ReplicatedStorage = game:GetService("ReplicatedStorage")

local monster = script.Parent
local monsterHumanoid = monster:WaitForChild("Humanoid")
local monsterWaypoints = workspace:WaitForChild("MonsterWaypoints")
local monsterRoot = monster:WaitForChild("HumanoidRootPart")

for index, bodyPart in pairs(monster:GetDescendants()) do
	if bodyPart:IsA("BasePart") then
		bodyPart:SetNetworkOwner(nil)
	end
end

local function CheckIfAlive(character)
	if ((character ~= nil) and (Players:GetPlayerFromCharacter(character) ~= nil) and (character:FindFirstChild("Head") ~= nil) and (character:FindFirstChild("HumanoidRootPart") ~= nil) and (character:FindFirstChildOfClass("Humanoid") ~= nil) and ((character:FindFirstChildOfClass("Humanoid")).Health > 0)) then
		return true
	end
end

local function CanSeeTarget(target)
	local origin = monsterRoot.Position
	local direction = (target:WaitForChild("HumanoidRootPart").Position - monsterRoot.Position).Unit * 40
	local ray = Ray.new(origin, direction)
	
	local hit, pos = workspace:FindPartOnRay(ray, monster)
	
	if (hit ~= nil) then
		if hit:IsDescendantOf(target) then
			return true
		end
	else
		return false
	end
end

local function FindTarget()
	local maxDistance = 40
	local nearestTarget
	
	for index, player in pairs(Players:GetPlayers()) do
		local character = player.Character or player.CharacterAdded:Wait()
		
		if (character ~= nil) then
			local target = character
			local distance = (monsterRoot.Position - character:WaitForChild("HumanoidRootPart").Position).Magnitude
			
			if (distance < maxDistance) and (CanSeeTarget(target) == true) then
				nearestTarget = target
				maxDistance = distance
			end
		end
	end
	
	return nearestTarget
end

local function GetPath(destination)
	local agentParameters = {
		["AgentHeight"] = 5,
		["AgentRadius"] = 4,
		["AgentCanJump"] = false,
		["Costs"] = {
			["SafeSpot"] = math.huge
		}
	}
	
	local path = PathfindingService:CreatePath(agentParameters) 
	path:ComputeAsync(monsterRoot.Position, destination.Position)
	
	return path
end

function Attack(target)
	local distance = (monsterRoot.Position - target:WaitForChild("HumanoidRootPart").Position).Magnitude
	
	if distance > 4 then
		monsterHumanoid:MoveTo(target:WaitForChild("HumanoidRootPart").Position)
	else
		target:FindFirstChildOfClass("Humanoid"):TakeDamage(target:FindFirstChildOfClass("Humanoid").MaxHealth)
	end
end

function WalkTo(destination)
	local path = GetPath(destination)
	
	if path.Status == Enum.PathStatus.Success then
		for index, waypoint in pairs(path:GetWaypoints()) do
			local target = FindTarget()
			
			if (target ~= nil) and (CheckIfAlive(target) == true) then
				Attack(target)
				break
			else
				monsterHumanoid:MoveTo(waypoint.Position)
				monsterHumanoid.MoveToFinished:Wait()
			end
		end
	else
		monsterHumanoid:MoveTo((destination.Position - (monsterRoot.CFrame.LookVector * 10)))
	end
end

function Patrol()
	local waypoints = monsterWaypoints:GetChildren()
	local randomWaypoint = waypoints[math.random(1, #waypoints)]
	WalkTo(randomWaypoint)
end

while true do
	task.wait()
	Patrol()
end

6 comments

0

Check in the script if you haven't set something that makes the AI moving to the waypoint.

0

I literally checked everything in the script and everything’s fine. That’s why I’m asking for help. If I had knew already I would’ve not created this question in the first place.

0

you might want to disable the function patrol when pathfinding to the player

0

the patrol function should be activated when Target == nil so it does not interfere with the pathfinding to the target

0

ok thx i’ll try that

0

puppynniko thx for the help, it worked :)

1 answer

I finally fixed it! @Puppynniko suggested detecting if the target is nill or not in the patrol function, and it worked! Thanks to @Puppynniko! This is my new AI script:

local PathfindingService = game:GetService("PathfindingService")
local Players = game:GetService("Players")
local ReplicatedStorage = game:GetService("ReplicatedStorage")

local monster = script.Parent
local monsterHumanoid = monster:WaitForChild("Humanoid")
local monsterWaypoints = workspace:WaitForChild("MonsterWaypoints")
local monsterRoot = monster:WaitForChild("HumanoidRootPart")

local chasing = false
local hipHeight = monsterHumanoid.HipHeight
local HitboxLength = 4

local agentParameters = {
	["AgentHeight"] = ((hipHeight > 0 and hipHeight) or 5),
	["AgentRadius"] = (monsterRoot.Size.X or 2),
	["AgentCanJump"] = false,
	["Costs"] = {
		["SafeSpot"] = math.huge
	}
}

for index, bodyPart in pairs(monster:GetDescendants()) do
	if bodyPart:IsA("BasePart") or bodyPart:IsA("MeshPart") or bodyPart:IsA("UnionOperation") then
		bodyPart:SetNetworkOwner(nil)
	end
end

local function CheckIfAlive(character)
	if ((character ~= nil) and (Players:GetPlayerFromCharacter(character) ~= nil) and (character:FindFirstChild("Head") ~= nil) and (character:FindFirstChild("HumanoidRootPart") ~= nil) and (character:FindFirstChildOfClass("Humanoid") ~= nil) and ((character:FindFirstChildOfClass("Humanoid")).Health > 0)) then
		return true
	else
		return false
	end
end

local function CheckIfTargetIsSafe(target)
	if (target ~= nil) and (Players:GetPlayerFromCharacter(target) ~= nil) and (target:FindFirstChild("Head") ~= nil) and (target:FindFirstChild("HumanoidRootPart") ~= nil) and (target:FindFirstChildOfClass("Humanoid") ~= nil) then
		if Players:GetPlayerFromCharacter(target):FindFirstChild("Safe") then
			if Players:GetPlayerFromCharacter(target):FindFirstChild("Safe").Value == true then
				return true
			else
				if target:FindFirstChildOfClass("ForceField") then
					return true
				else
					return false
				end
			end
		else
			if target:FindFirstChildOfClass("ForceField") then
				return true
			else
				return false
			end
		end
	else
		return false
	end
end

local function CanSeeTarget(target)
	local origin = monsterRoot.Position
	local direction = (target:WaitForChild("HumanoidRootPart").Position - monsterRoot.Position).Unit * 1000
	local ray = Ray.new(origin, direction)
	
	local hit, pos = workspace:FindPartOnRayWithIgnoreList(ray, {monster})
	
	if hit then
		if hit:IsDescendantOf(target) then
			if target:FindFirstChildOfClass("ForceField") then
				return true
			else
				local plr = Players:GetPlayerFromCharacter(target)
				
				if plr then
					local safeValue = plr:FindFirstChild("Safe")
					
					if safeValue then
						if safeValue.Value == false then
							return true
						else
							return false
						end
					else
						return false
					end
				else
					return false
				end
			end
		end
	else
		return false
	end
end

local function FindTarget()
	local maxDistance = 10000
	local nearestTarget
	
	for index, player in pairs(Players:GetPlayers()) do
		local character = player.Character or player.CharacterAdded:Wait()
		
		if character then
			local target = character
			local distance = (monsterRoot.Position - character:WaitForChild("HumanoidRootPart").Position).Magnitude
			
			if (distance < maxDistance) and (CanSeeTarget(target) == true) then
				nearestTarget = target
				maxDistance = distance
			end
		end
	end
	
	return nearestTarget
end

local function GetPath(destination)
	local path = PathfindingService:CreatePath(agentParameters) 
	path:ComputeAsync(monsterRoot.Position, destination.Position)
	
	return path
end

function Attack(target)
	local distance = (monsterRoot.Position - target:WaitForChild("HumanoidRootPart").Position).Magnitude
	
	if distance > (HitboxLength or 1) then
		monsterHumanoid:MoveTo(target:WaitForChild("HumanoidRootPart").Position)
	else
		target:FindFirstChildOfClass("Humanoid"):TakeDamage(target:FindFirstChildOfClass("Humanoid").MaxHealth)
	end
end

function WalkTo(destination)
	local path = GetPath(destination)
	
	if path.Status == Enum.PathStatus.Success then
		for index, waypoint in pairs(path:GetWaypoints()) do
			local target = FindTarget()
			
			if target and CanSeeTarget(target) and (CheckIfAlive(target) == true) and (CheckIfTargetIsSafe(target) == false) then
				break
			else
				monsterHumanoid:MoveTo(waypoint.Position)
				monsterHumanoid.MoveToFinished:Wait()
			end
		end
	else
		monsterHumanoid:MoveTo((destination.Position - (monsterRoot.CFrame.LookVector * 10)))
	end
end

function Patrol()
	local target = FindTarget()
	
	if target and CanSeeTarget(target) and (CheckIfAlive(target) == true) and (CheckIfTargetIsSafe(target) == false) then
		Attack(target)
	else
		local waypoints = monsterWaypoints:GetChildren()
		local randomWaypoint = waypoints[math.random(1, #waypoints)]
		WalkTo(randomWaypoint)
	end
end

while true do
	task.wait()
	Patrol()
end

Also, you can use this script too to make your own Monster AI! Don't exactly copy-paste mine because it could cause errors.

If you're wondering what game it is, here's the game!

This discussion is preserved as it was. New answers, comments, and votes are closed.