I need help with making an NPC

Hey again. I have an NPC which uses raycasting to check if a player is behind a wall or not, but the problem is for some odd reason it only detects the left/right arms. I provided the scripts below, and help would be appreciated!

AIController:

local ThinkingEnabled = true
local Rate = 0.1
local MaxDistance = 500

local Players = game:GetService("Players")
local Scanner = require(script:FindFirstChild("Scanner"))

local hitbox = script.Parent:FindFirstChild("HumanoidRootPart")
local params = RaycastParams.new()
params.FilterType = Enum.RaycastFilterType.Blacklist
local blacklist = { script.Parent }

local aiScanner = Scanner.create(function(plr: Player)
	local char = plr.Character
	return char ~= nil 
		and char:FindFirstChild("Humanoid")
		and char:FindFirstChild("Humanoid").Health > 0
		and plr:DistanceFromCharacter(hitbox.Position) < MaxDistance
end)

task.spawn(function()
	while ThinkingEnabled do
		task.wait(Rate)
		
		if #Players:GetChildren() > 0 then
			aiScanner:Scan()
			
			if aiScanner.ScanTable ~= nil and table.getn(aiScanner.ScanTable) > 0 then
				for _, p: Player in ipairs(aiScanner.ScanTable) do
					blacklist = { script.Parent }
					local root = p.Character:FindFirstChild("HumanoidRootPart")
					local dir = (hitbox.Position - root.CFrame.LookVector).Unit
					
					for _, a in pairs(p.Character:GetDescendants()) do
						if a:IsA("BasePart") and (a.Parent:IsA("Accessory") or a.Parent:IsA("Hat")) then
							table.insert(blacklist, a)
						end
					end
					
					params.FilterDescendantsInstances = blacklist
					local ray = workspace:Raycast(root.Position, dir * 500, params)
					
					if ray and ray.Instance then
						print(ray.Instance.Name)
					end
				end
			end
		end
	end
end)

Scanner:

--!strict
local Players = game:GetService("Players")

local Scanner = {}
Scanner.__index = Scanner

export type Conditional = (Player) -> boolean

function Scanner.create(conditional: Conditional)
	return setmetatable({
		Condition = conditional,
		ScanTable = {}
	}, Scanner)
end

function Scanner:Scan()
	self.ScanTable = {}
	for _, p: Player in ipairs(Players:GetChildren()) do
		if self.Condition(p) then
			table.insert(self.ScanTable, p)
		end
	end
end

return Scanner
2 Likes

I don’t follow your problem, if it’s getting the character regardless then its doing its job. It shouldnt be possible for it to just ignore your character through the HRP when the direction is your hrp cframe. Is your problem that? Or is it working 24/7 and you’re curious to why the result instance isnt the root? I looked at your code and nothing is wrong, without more information I can’t really give any help; for example is your character a custom rig? Or is there animations where the arms block the core position of hrp. Try blacklisting your L/R arms and see what happens

2 Likes

I think whats going on is that the raycast is detecting the players arms, not the npc’s arms.
So in your if statement, try doing this:

if aiScanner.ScanTable ~= nil and table.getn(aiScanner.ScanTable) > 0 then
		for _, p: Player in ipairs(aiScanner.ScanTable) do
			-- Blacklist the npc AND the player from the raycast.
			-- Anything in the blacklist will be ignored, including its descendants.
			blacklist = { script.Parent, p }
			local root = p.Character:FindFirstChild("HumanoidRootPart")
			local dir = (hitbox.Position - root.CFrame.LookVector).Unit
					
			params.FilterDescendantsInstances = blacklist
			local ray = workspace:Raycast(root.Position, dir * 500, params)
					
			if ray and ray.Instance then
				print(ray.Instance.Name)
			end
		end
	end
1 Like

The problem is that if I face forward or backward, the NPC wont recognize players, which is bad because I plan to have the AI be pretty fast with its decisions, and if you were being chased you could just face the NPC and it would suddenly think your not there.
I’m also going to provide a couple videos so I can showcase the problem better.

In the video below, the NPC only recognizes me if my arms are in a certain angle to the NPC, which doesn’t make sense because I’m raycasting to the HumanoidRootPart, not the arm parts:


You can also see when I face forward the NPC just thinks I’m not there, and stops printing the debug message in the console.

Now here is a video with a beam, used for debugging. This beam hits the exact point where the raycast stops at.


As you can see, even though I’m literally raycasting to the players HumanoidRootPart, my NPC heavily insists on only raycasting to the Players arms.

I haven’t dealt much with raycasts, but I really have no idea why this happens, it doesn’t make much sense that I am raycasting to the direction of the Players HumanoidRootPart, but somehow it ends up only hitting the players arms.
My guess is that I got the direction variable wrong, but I don’t know what is wrong about it.
Help would be much appreciated from anyone!

A blacklist prevents the raycast from detecting descendant parts of an instance. If I use this, the NPC doesn’t detect the player at all, which is of course because if I blacklist the player, the NPC doesn’t see the player.

My goal isn’t for the NPC to detect the arms of itself or any other player, I want to detect the HumanoidRootPart of the selected player and that alone.

Ah, finally figured it out. I had to switch some of the directions around, but I figured out I was raycasting from the players HumanoidRootPart, but I switched the origin to be the NPCs root part. Thanks for the help.