In my new project, which involves sneaking into other buildings and stealing items, we want to make a system where NPCs can spot the player. The question is how we go about doing this
It’s not as simple as using grid logic, since our game is a 2D game based around grids, we want it to be variable based on the height of objects and if the player is crouching or not
Raycasts might be a good idea. They’re easy and almost work in any solution. You send a raycast from enemy to the player and if the player can be seen then they will be “detectable” at a minimum.
Like what @EpicMetatableMoment said, use Raycasting. I made a quick script to help you get the idea.
--// CONSTANTS \\--
local DISTANCE = 20 -- How far the NPC can see.
--// SERVICES \\--
local Players = game:GetService("Players")
--// VARIABLES \\--
local origin = script.Parent.Head -- Origin of where the raycast is.
--// MAIN CODE \\--
while wait() do
local ray = Ray.new(origin.Position, origin.CFrame.lookVector * DISTANCE) -- Calculating the raycast.
local hit = workspace:FindPartOnRay(ray, origin.Parent) -- Creating a ray to see what the npc sees.
if hit then
for _, player in pairs(Players:GetPlayers()) do -- We're going to loop through all players to see if the npc sees any of them.
if player.Character and player.Character:IsAncestorOf(hit) then
-- Handle what happens here.
print("I see " .. player.Name)
break
end
end
end
end
Of course, you’re going to want to change the script to have it suit your needs, but this will give you an idea of how they work.
local viewP = viewDirection:dot(directionToPlayer)
viewDirection would be the direction their eyes face and directionToPlayer is (playerPositon - eyePosition).Unit
This returns a number between -1 and 1. -1 means theyre behind them, 0 means theyre perpendicular to them, and 1 means theyre right in front of them. You can use this to detect if the NPC can see them within a cone of vision. This is very useful if it is like old Metal Gear where you can sneak around and behind people.
This is useful but how can you make it see wider? Like bigger angle on the vision, cuz rn it can only see something exactly in front of the head. I guess it can be maybe fixed if u make the “origin” part some other part that is bigger.
You could probably cast a ray to all nearby players up to 90° and check if theres anything in the way.
Use the information from this comment to check the angle.
try dot producting the NPCs head and the target,
and raycasting from NPC’s head to the target to check if anything non see through is blocking it.
local function DP(TargetPos, CF)
--Target is what youre trying to check whether if its in the field of view
--CF is the CF of the NPCs head
local LV = CF.LookVector
local DIR_TO_POS = (TargetPos - CF.Position).Unit
return LV:Dot(DIR_TO_POS)
end
returns a value between -1 and 1, depending on how you set it up, it will return something between 0 and 1 for everything in the front, and something between 0 and -1 for everything in the back where I believe 1 to be the 90* front angle and -1 the 90* behind angle and 0 being the sides…
Play around with the return values to understand them, enjoy!
Im personally using it to help Vehicular NPCs steer towards nodes where im using the RightVector instead of the Lookvector so that -1 is left and 1 is right and the front is 0… Good Luck!!
EDIT:
I had no idea this was a 3 year old post thats already been covered, sorry everyone!