Better AI script because I was bored

As a better version to my older script found here this one actually has object permanence, basically the AI is smarter, If you are behind a wall it wont magically know you’re there and it has to maintain line of sigh with you while It’s chasing you. If it looses this line of sight it will go to the last location and go from there, feel free to use it however you want credit my if you’d like

task.wait(1)

local PathfindingService = game:GetService("PathfindingService")

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

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()
	
	Hum:MoveTo(waypoints[2].Position)
			
		
	local humTarget = getTarget()
	local LineOfSight = lineOfSight(humTarget.Character.HumanoidRootPart)
	
	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
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()

It isn’t perfect, with more then one player in the game it can have some strange behavior, for example if it losses sight of player A and goes to their last location it will completely ignore player B if it sees them on route to PlayersA last location, however it doesn’t outright break and I posted this so people can adapt it into their own games and maybe learn something from it so yeah.

1 Like

umm, why doesn’t it break out of it going back to A, and go after B? Does it know B is there but does not break out ? or does it not know about B until it hits the last place of A it is on route to?

also do you have a test place that is editable, or a .rbxl to check out? with a NPC in it?

I would like to try it out in a place area with walls and such

Thanks

umm ya, try to get this to work, is like umm ya… you call other scripts or something animation wise in your NPC that we do not have… nor would we be able to run the animation ids unless you also provide the animation save frames in the npc…

Can you make an editable testing place, with the npc and animation we can load and save our own ids?

I like you idea of the AI needed to SEE you… and would like to check it out.

Thanks

Those are just animations. You can make your own the ones I used are for testing and are pretty bad in terms of how the look

It’s AI is locked to going to the last position A was seen and won’t call any functions that would cause it to break out. I made this for a strictly single player game so for my needs it wasn’t an issue but I reloaded after posting for multiplayer games it could do that so just left a warning. It’s an oversight as in my single player game it only ever has one target

When I’m home in a couple of hours I’ll give you a link to an uncopylocked place

Cool, I’Ll check out the link when u send it

Thanks

I forgot about this for 3 days but here is the place

1 Like

The AI, attacks once, then stops and does not move again… how can it be made to keep attacking?

Thanks

Strange, I tested it right after I saw your message and it works fine in my game. Did you modify the script at all?