AI Vision Issue

Hello scripters, I have a pretty big ask of you guys so any help is appreciated. I am trying to make an AI. I wont go into what features and everything that it does but feel free to look through the code to find out yourself. Basically, I am trying to use ray casting to find a player and attack them My issue is is that the attack is very inconsistent. what i mean by this is that the ai has a hard time seeing the player (see the video to fully understand what i mean). I have tried to new shape casting feature to expand the ray cast from a tiny line to a big area in order to “increase the ai’s vision” if you know what i mean. however, this did not work. it did the same exact thing. I would like to make it towards that the AI only checks if it can see the player (when attacking off corset) every 10-15 seconds. I unfortunately dont know how to do this unfortunately and am coming to you guys for help. Please help me out. ANY and i mean ANYTHING helps. Thank you for your time, have a blessed day.,

GUIDE: (find target function : line218. walkto function: line 263. attack function: line 596. where the attack function is called: line 666.)

VIDEO:

CODE:

local runservice = game:GetService(“RunService”)
local soundservice = game:GetService(“SoundService”)
local pathfindingservice = game:GetService(“PathfindingService”)

local idletasks = require(script.IdleTasks)

local neighbor = script.Parent
local humanoid = neighbor:WaitForChild(“Humanoid”)
local hrp = neighbor:WaitForChild(“HumanoidRootPart”)

local trapsfolder = game.ServerStorage.Traps
local distractions = workspace.Distractions

local rooms = workspace.Rooms:GetChildren()
local attackpaths = workspace:WaitForChild(“AttackPaths”)

local idlespeed = 12
local huntspeed = 16
local attackspeed = 18

local mode = neighbor.Mode
mode.Value = “Idle”

local bindables = game:GetService(“ReplicatedStorage”).Bindables
local remotes = game:GetService(“ReplicatedStorage”).RemoteEvents

local playerCaught = bindables:WaitForChild(“playerCaught”)

neighbor.HumanoidRootPart:SetNetworkOwner(nil)

local ogpositions = {}
local prevRooms = {}

for i, room in pairs (rooms) do

for i, instance in pairs (room:GetChildren()) do

	if instance.Name == "KeyItems" and instance:IsA("Folder") then

		for i, item in pairs (instance:GetChildren()) do
			
			table.insert(ogpositions, item.Position)
			
		end

	end
	
end

end

local function getChase()

local sounds = soundservice.Ambiences.ChaseMusics:GetChildren()
local soundchosen = sounds[math.random(1, #sounds)]

soundchosen.TimePosition = 0

return soundchosen

end

–THIS FUNCTION IS TO FIX A GLITCH. DO NOT USE (unless u have to)

local function findnearestPlayer()

local players = game.Players:GetPlayers()
local maxDistance = 100
local nearestTarget

for i, player in pairs(players) do

	local char = player.Character or player.CharacterAdded:Wait()

	if char then

		local target  = char
		local distance = (neighbor.HumanoidRootPart.Position - target.HumanoidRootPart.Position).Magnitude

		if distance < maxDistance then
			nearestTarget = target
			maxDistance = distance
		end
	end
end

return nearestTarget

end

local function getDistance(pos1, pos2)

local distance = (pos1 - pos2).Magnitude
return distance

end

local function getRandomRoom()

for i = 1, #rooms do
	local randomRoom = rooms[math.random(1, #rooms)]

	if table.find(prevRooms,randomRoom) ~= nil then
		repeat
			randomRoom = rooms[math.random(1, #rooms)]
			task.wait()
		until table.find(prevRooms,randomRoom) == nil
	end

	table.insert(prevRooms,randomRoom) 
	task.wait()
	return randomRoom
end

end

local function playAnim(animation, sound)

if mode.Value ~= "Attack" then
	
	local anim = humanoid:LoadAnimation(animation)
	anim:Play()
	if sound then
		sound:Play()
	end
	anim.Stopped:Wait()
	
end

end

local function findNearestRoom(plyr)

local target = plyr
local hrp = target:WaitForChild("HumanoidRootPart")
local rooms = workspace.Rooms
local distances = {}

for i, room in pairs(rooms:GetChildren()) do

	local label = room:FindFirstChild("Label")

	local distance = (hrp.Position - label.Position).Magnitude
	table.insert(distances, distance)

end

local nearest = math.min(table.unpack(distances))

for i, room in pairs (rooms:GetChildren()) do

	local label = room:FindFirstChild("Label")

	if (hrp.Position - label.Position).Magnitude == nearest then

		return room

	end

end

end

local function addFavLoc(room)

if not room:FindFirstChild("Favorite") then
	
	local fav = {}

	for i, rooom in pairs (rooms) do

		local isFav = room:FindFirstChild("Favorite")
		table.insert(fav, rooom)

	end

	if #fav >= #fav/2 then

		local tag = Instance.new("BoolValue")
		tag.Name = "Favorite"
		tag.Parent = room

	end
	
end

end
local function catch(target)

local nearest = findNearestRoom(target)

addFavLoc(nearest)
neighbor.Head.Sounds.Angry:Play()
wait(.8)
target.HumanoidRootPart:PivotTo(workspace.Spawn.CFrame)
playerCaught:Fire()
target.Humanoid.WalkSpeed = 16
target.Humanoid.JumpPower = 50

end

local function placeTrap(trap, position)

if trap == "BearTrap" then
	
	playAnim(script.Animations.PlaceBearTrap)
	local trap = trapsfolder.BearTrap:Clone()
	trap.Parent = distractions
	
	trap.Union.Position = position + Vector3.new(0,-.14,0)
	
	
end

end

local function findIntruder()

local players = game.Players:GetPlayers()
local intruder

for i, plyr in pairs (players) do

	local char = plyr.Character or plyr.CharacterAdded:Wait()

	if char then

		local direction = (char.PrimaryPart.Position - hrp.Position).Unit
		local raycastResult = workspace:Raycast(hrp.Position, direction * 50)
		
		if raycastResult then
			
			if raycastResult.Instance:IsDescendantOf(char) then

				intruder = char
				break

			end

		end

	end

end

return intruder

end

local function getPath(destination)

local path = pathfindingservice:CreatePath()
path:ComputeAsync(hrp.Position, destination)

return path

end

local function walkTo(destination)

local path = getPath(destination)

if path.Status == Enum.PathStatus.Success then
	for index, waypoint in pairs(path:GetWaypoints()) do
				
		local target = findIntruder()
		
		if target and target.Humanoid.Health > 0 then
			
			local chase = getChase()
			local counter = 0
			
			for i, sound in pairs (soundservice.Ambiences.ChaseMusics:GetChildren()) do

				if sound.Playing == false then

					counter += 1

				end

			end

			if counter == #soundservice.Ambiences.ChaseMusics:GetChildren() then

				chase.Playing = true

			end
			
			mode.Value = "Attack"
			
			local nearestroom = findNearestRoom(target)
			local tag = nearestroom:FindFirstChild("Favorite")
			
			if not tag then
				addFavLoc(nearestroom)
			end
			
		elseif not target then
			
			for i, sound in pairs (soundservice.Ambiences.ChaseMusics:GetChildren()) do

				sound.Playing = false

			end
			
			humanoid:MoveTo(waypoint.Position)
			humanoid.MoveToFinished:Wait()
			
		end
		
	end
else
	humanoid:MoveTo(destination - (hrp.CFrame.LookVector * 10)

	)
end

end

local function changeMode()

for i, instance in pairs (distractions:GetDescendants()) do

	if instance:IsA("BoolValue") and instance.Name == "Status" then

		if instance.Value == true and mode.Value ~= "Attack" then

			for i, instance in pairs (distractions:GetDescendants()) do

				if instance:IsA("BoolValue") and instance.Name == "Status" then

					if instance.Value == true and mode.Value ~= "Attack" then

						local lookAnim = script:WaitForChild("Animations"):WaitForChild("Look")
						
						if instance.Parent.Name == "Camera" then
							
							walkTo(instance.Parent.End.Position)
							
						elseif instance.Parent.Name == "BearTrap" then
							
							walkTo(instance.Parent.HitBox.Position)
							
						elseif instance.Parent.Name == "TV" then
							
							walkTo(instance.Parent.Position)
							
						end
						
						local lookAnim = script.Animations.Look
						
						playAnim(lookAnim, neighbor.Head.Sounds.Yell2)
						instance.Value = false

					end

				end

			end
			

			mode.Value = "Hunt"

		elseif instance.Value == false and mode.Value ~= "Attack" and mode.Value ~= "Hunt" then

			mode.Value = "Idle"

		end

	end

end

end

local function detectMovedObject(room)

for i, rooom in pairs (rooms) do

	if rooom.Name == room.Name then

		for i, instance in pairs (room:GetChildren()) do
			if instance.Name == "KeyItems" and instance:IsA("Folder") then

				local item = instance.Item

				for i, position in pairs (ogpositions) do

					local pos = table.find(ogpositions, item.Position)

					if not pos then

						return true

					elseif pos then

						return false

					end

				end

			end
		end

	end

end

end

local function idle()

humanoid.WalkSpeed = idlespeed
local randomroom = rooms[math.random(1, #rooms)]

local moved = detectMovedObject(randomroom)

if moved and randomroom.hasTrap.Value == false then
	
	local lookAnim = script.Animations.Look
	local tag = randomroom:FindFirstChild("Favorite")

	if not tag then
		addFavLoc(randomroom)
	end
	
	walkTo(randomroom.KeyItems.Item.Position)
	playAnim(lookAnim, neighbor.Head.Sounds.Yell)
	
	for i, item in pairs (randomroom:GetDescendants()) do

		if item.Name == "BeartrapPosition" then

			for i, position in pairs (item:GetChildren()) do

				walkTo(position.Position)
				placeTrap("BearTrap", position.Position)
				randomroom.hasTrap.Value = true

			end

		end

	end

	mode.Value = "Hunt"
	
else
	
print(randomroom.Name)
		
	walkTo(randomroom.Label.Position)

	if randomroom.Name == "Kitchen" and not findIntruder() then

		walkTo(randomroom.AnimationPart.Position)
		idletasks.WashDishes()

	end

end

end

local function hunt()

humanoid.WalkSpeed = huntspeed

local lookAnim = humanoid:LoadAnimation(script.Animations.Look)

local randomroom = getRandomRoom()
local label = randomroom.Label

local moved = detectMovedObject(randomroom)

local target = findIntruder()

if not label then
	error("No Label Found")
end

if moved then
	
	local lookAnim = script.Animations.Look
	local tag = randomroom:FindFirstChild("Favorite")
	
	if not tag then
		addFavLoc(randomroom)
	end
	
	walkTo(randomroom.KeyItems.Item.Position)
	playAnim(lookAnim, neighbor.Head.Sounds.Yell)
	
	if randomroom.hasTrap.Value == false then
		
		for i, item in pairs (randomroom:GetDescendants()) do

			if item.Name == "BeartrapPosition" then

				for i, position in pairs (item:GetChildren()) do

					walkTo(position.Position)
					placeTrap("BearTrap", position.Position)
					randomroom.hasTrap.Value = true

				end

			end

		end
		
	end
	
else
	
	local lookAnim = script.Animations.Look

	walkTo(label.Position)
	playAnim(lookAnim, neighbor.Head.Sounds.Grunt)
	
	local tag = randomroom:FindFirstChild("Favorite")
	local hideing = randomroom:FindFirstChild("Hideing")
	
	if tag and hideing and mode.Value ~= "Attack" then
		
		for i, spot in pairs (hideing:GetChildren()) do
			
			local point = spot.Point
			local anim = humanoid:LoadAnimation(script.Animations.OpenCloset)
			
			walkTo(point.Position)
			spot.Status.Value = true
			humanoid.WalkSpeed = 0
			anim:Play()
			anim:GetMarkerReachedSignal("Stop"):Wait()
			anim:AdjustSpeed(0)
			if spot.Player.Value == true then
				
				local target = findnearestPlayer()
				
				if target then
					catch(target)
				end

			end
			wait(.5)
			anim:AdjustSpeed(1)
			spot.Status.Value = false
			anim.Stopped:Wait()
			humanoid.WalkSpeed = huntspeed
			
		end
		
	end
	

end

end

local function newPath(name)

local path = Instance.new("Folder")
path.Parent = attackpaths
path.Name = name

return path

end

local function logPath(target, path, previous)

local intruder = findIntruder()

if intruder then
	
	local hrpart = target.HumanoidRootPart

	local marker = Instance.new("Part")
	marker.CFrame = hrpart.CFrame
	marker.Size = Vector3.new(.5,.5,.5)
	marker.Parent = path
	marker.Anchored = true
	marker.CanCollide = false
	marker.CanTouch = false
	marker.Transparency = .5
	
end

end

local function attack(target)

if target then

	humanoid.WalkSpeed = attackspeed

	local distance = (neighbor.HumanoidRootPart.Position - target.HumanoidRootPart.Position).Magnitude

	if distance > 2 then

		humanoid:MoveTo(target.HumanoidRootPart.Position)

	else

		catch(target)
		mode.Value = ""

	end

else
		
	mode.Value = "Idle"

end

end

–[[
task.spawn(function()

	while task.wait() do
		
		changeMode()
		
	end
	
end)
	]]--

while wait(.1) do

changeMode()

if mode.Value == "Idle" then

	humanoid.WalkSpeed = idlespeed
	idle()

elseif mode.Value == "Hunt" then
	
	humanoid.WalkSpeed = huntspeed
	for i, sound in pairs (soundservice.Ambiences.ChaseMusics:GetChildren()) do

		sound.Playing = false

	end
	
	if #prevRooms == #rooms then
		
		table.clear(prevRooms)
		mode.Value = "Idle"
		
	else
		
		hunt()
		
	end

	

elseif mode.Value == "Attack" then
	
	local intruder = findIntruder()
	
	humanoid.WalkSpeed = attackspeed
	attack(intruder)
	logPath(intruder,attackpaths)
	
	

end

end

i just realized maybe my code was too big for the dev forum lol

If this doesn’t format I’m sorry, I’m on mobile but here’s some code I did a while ago to do exactly what you want in your game

‘’’

task.wait(5)

local PathfindingService = game:GetService(“PathfindingService”)

local AI = script.Parent
local RP = script.Parent.HumanoidRootPart
local Hum = script.Parent.Humanoid

Hum.DisplayDistanceType = Enum.HumanoidDisplayDistanceType.None

local Waypoints = game.Workspace:WaitForChild(“Waypoints”):GetChildren()

RP:SetNetworkOwner(nil)

local attackAnim = Hum.Animator:LoadAnimation(script.Attack)
local walkAnim = Hum.Animator:LoadAnimation(script.Walk)
local runAnim = Hum.Animator:LoadAnimation(script.Run)

local rayParams = RaycastParams.new()
rayParams.FilterType = Enum.RaycastFilterType.Exclude
rayParams.FilterDescendantsInstances = {Hum}

local Damage = 25
local AttackRange = 5

walkAnim.Looped = true
runAnim.Looped = true
walkAnim:Play()

local LastSeenPos

local RayParams = RaycastParams.new()
RayParams.FilterType = Enum.RaycastFilterType.Exclude

local pathParams = {
AgentHeight = 5,
AgentRadius = 3,
AgentCanJump = true,
}

local function getPath(destination)
local path = PathfindingService:CreatePath(pathParams)

path:ComputeAsync(RP.Position, destination)

return path	

end

function lineOfSight(target)
local rayDirection = target.Position - RP.Position
local rayParams = RaycastParams.new()
rayParams.FilterDescendantsInstances = {RP.Parent}

local RayResult = workspace:Raycast(RP.Position, rayDirection, rayParams)


if RayResult and RayResult.Instance then
	if RayResult.Instance:IsDescendantOf(target.Parent) then
		return true
	else
		return false
	end
end

end

function getTarget()

local closestTarget
local distanceFromClosestTarget = 1000000000

for i, player in pairs(game.Players:GetChildren()) do
	local distance = (player.Character.HumanoidRootPart.Position - RP.Position).Magnitude

	if distance < distanceFromClosestTarget then
		distanceFromClosestTarget = distance
		closestTarget = player
	end
end


return(closestTarget)

end

local db = false

local runAnimPlayingStatus = false
local walkAnimPlayingStatus = false

function chaseTarget(target)
print(‘chasing’)
if runAnimPlayingStatus == false then
walkAnim:Stop()
runAnim:Play()
runAnimPlayingStatus = true
walkAnimPlayingStatus = false
end

local path

path = getPath(target.Character.HumanoidRootPart.Position)

local waypoints = path:GetWaypoints()

local humTarget = getTarget()
local LineOfSight = lineOfSight(humTarget.Character.HumanoidRootPart)

if waypoints[2] then
	Hum:MoveTo(waypoints[2].Position)

	LastSeenPos = humTarget.Character.HumanoidRootPart.Position

	if (humTarget.Character.HumanoidRootPart.Position - RP.Position).Magnitude <= 5 and db == false then
		db = true
		attackAnim:Play()
		humTarget.Character.Humanoid:TakeDamage(Damage)
		attackAnim.Ended:Wait()
		db = false
	end

	if humTarget and LineOfSight then
		chaseTarget(humTarget)
	else
		moveToLastSeen(LastSeenPos)
	end
else
	warn("checkpoint 2 does not exist, falling back to patrol")
	patrol()
end

end

function moveToLastSeen(location)
print(‘fired’)

local path = getPath(location)
for i, waypoint in pairs(path:GetWaypoints()) do

	local humTarget = getTarget()
	local LineOfSight = lineOfSight(humTarget.Character.HumanoidRootPart)

	if humTarget and LineOfSight then
		path:Destroy()
		chaseTarget(humTarget)
		break
	else
		if walkAnimPlayingStatus == false then
			walkAnim:Play()
			walkAnimPlayingStatus = true
		end
		runAnimPlayingStatus = false
		runAnim:Stop()

		Hum:MoveTo(waypoint.Position)
		Hum.MoveToFinished:Wait()


		if i == #path:GetWaypoints() then
			patrol()
		end
	end
end

end

function moveTo(target)
local humTarget = getTarget()
local LineOfSight = lineOfSight(humTarget.Character.HumanoidRootPart)

if humTarget and LineOfSight then
	chaseTarget(humTarget)
else
	
	local path = getPath(target)
	
	if path.Status == Enum.PathStatus.Success then

		
		for i, waypoint in pairs(path:GetWaypoints()) do
			
			local humTarget = getTarget()
			local LineOfSight = lineOfSight(humTarget.Character.HumanoidRootPart)

			if humTarget and LineOfSight then
				path:Destroy()
				chaseTarget(humTarget)
				break
			else
				if walkAnimPlayingStatus == false then
					walkAnim:Play()
					walkAnimPlayingStatus = true
				end
				runAnimPlayingStatus = false
				runAnim:Stop()

				Hum:MoveTo(waypoint.Position)
				Hum.MoveToFinished:Wait()

				
				if i == #path:GetWaypoints() then
					patrol()
				end
			end
		end
	end	
end

end

function patrol()
local ChosenWapoint = math.random(1, #Waypoints)
moveTo(game.Workspace.Waypoints:FindFirstChild(ChosenWapoint).Position)
end

patrol()

‘’’

Yup it did not format, oh well

its ok bro i can still read it thank you so much

Glad it helped, it has a feature that if it losses sight of you when it’s chasing you it will return to your last known location, if you don’t want that you need to remove it. Otherwise it should work. It needs a folder with some checkpoints in workspace and some animations, just run it and it will be obvious judging by the errors what it needs