#Can someone explain this code to an idiot (me)

1 messages · Page 1 of 1 (latest)

devout harness
#

I am following this tutorial about NPC eyesight and the last part is about checking if the NPC has detected any players or other objects. The math parts of it are the most confusing and the main part I am struggling at grasping

https://devforum.roblox.com/t/how-to-create-a-realistic-npc-eyesight-system/2456522

So uhhhh if you wanna give this a shot here is the code:

local function checkSight(npc)
local detectable = {}

local characters = getCharacters()
local taggedObjects = CollectionService:GetTagged("Detectable")

for index, character in characters do
    table.insert(detectable, character)
end

for index, object in taggedObjects do
    table.insert(detectable, object)
end

for index, object in detectable do
    if object:IsA("Model") then
        object = object.PrimaryPart
    end
    
    local headPosition = npc.Head.Position
    
    local objectPosition = object.Position
    local headCFrame = npc.Head.CFrame
    
    local direction = (objectPosition - headPosition).Unit
    local lookVector = headCFrame.LookVector
    
    local dotProduct = direction:Dot(lookVector)
    local angle = math.deg(math.acos(dotProduct))
    
    local distance = (headPosition - objectPosition).Magnitude
    
    if angle > fieldOfView then
        continue
    end
    
    if distance > viewRange then
        continue
    end
    
    if raycast(npc, headPosition, objectPosition) then
        return
    end
    
    if object:IsA("Model") then
        objectLastDetected = object.Parent
    else
        objectLastDetected = object
    end
    
    return true
end

end

haughty quiver
#

It gathers characters + tagged objects, checks if they’re in front of the NPC, within range, and not blocked by a raycast. If so, they’re marked as seen.

My improved version fixes bad loops, avoids nil PrimaryPart, and returns all seen objects instead of just the first

#

local function checkSight(npc)
local head = npc:FindFirstChild("Head")
if not head then return nil end

local detectable = {}
for _, character in ipairs(getCharacters()) do
    table.insert(detectable, character)
end
for _, object in ipairs(CollectionService:GetTagged("Detectable")) do
    table.insert(detectable, object)
end

local detected = {}
local headPosition = head.Position
local headCFrame = head.CFrame
local lookVector = headCFrame.LookVector

for _, object in ipairs(detectable) do
    if object:IsA("Model") then
        object = object.PrimaryPart
        if not object then continue end
    end
    
    local objectPosition = object.Position
    local direction = (objectPosition - headPosition).Unit
    local dotProduct = direction:Dot(lookVector)
    local angle = math.deg(math.acos(dotProduct))
    local distance = (headPosition - objectPosition).Magnitude
    
    if angle <= fieldOfView and distance <= viewRange then
        if not raycast(npc, headPosition, objectPosition) then
            table.insert(detected, object)
        end
    end
end

return #detected > 0 and detected or nil

end

devout harness
#

just one more quick question

#

To make it detect NPCs I would change

for _, object in ipairs(detectable) do
if object:IsA("Model") then
object = object.PrimaryPart
if not object then continue end
end

#

to

#

for _, enemy in ipairs(detectable) do
if object:IsA("Humanoid") then
enemy = enemy.HumanoidRootPart
if not enemy then continue end
end

#

?