Finding enemies within a angle and distance

Hello! Currently I am working on an boss fight and im wondering how would you find enemies within a angle/triangle something like this
image
Ex: Orange is boss, Blue is angle, Pink is enemies, x’s are for not included in the count (not in angle)
I want it to find every enemy within the angle and distance but not the enemies not inside the angle, something like vision

1 Like

Could dot products be a possible solution here? You could incorporate a distance check as well to determine if players are close enough in some given angle.

local function isPlayerInLineOfSight(player)
local lookDirection = rootPart.CFrame.LookVector
local directionToPlayer = (player.PrimaryPart.Position - rootPart.Position).Unit

local angle = lookDirection:Dot(directionToPlayer)

if angle < 1 then
--//Player is in line of sight
end
end

Could also adjust the maximum angle it can be, I believe anything less than 1 is in front of the NPC, and anything negative is behind it. You should be able to tighten this, and also incorporate a distance check to see if players in line of sight are also close enough.

3 Likes

Another thing to consider is what you want the 3D shape of the “angle” to be. Do you want “full 3D” angle, i.e. a cone shape, or do you want more of a 2D, top-down type angle, i.e. ignoring the height component for a “two planes” type of shape?

For the cone-type shape, this should work:

function vectorAngle(v1: Vector3, v2: Vector3): number
    --Explanation here: https://devforum.roblox.com/t/b/208450/4
    return math.acos(v1.Unit:Dot(v2.Unit))
end

function isPointInCone(point: Vector3, coneBase: Vector3, coneDir: Vector3, coneAngle: number): boolean
    local baseToPoint = point - coneBase
    local angle = vectorAngle(baseToPoint, coneDir)
    return angle < coneAngle
end

function isPointInRange(point: Vector3, pointFrom: Vector3, maxRange: number, minRange: number?): boolean
    local d = (point - pointFrom).Magnitude
    return d  == math.clamp(d, minRange or 0, maxRange)
end

  function isPointInView(point: Vector3, view: Attachment, viewAngle: number, viewRange: number): boolean
      return isPointInCone(point, view.WorldPosition, view.WorldCFrame.LookVector, viewAngle) and
           isPointInRange(point, view.WorldPosition, viewRange) 
  end

For a two-planes-type shape you could just remove the Y component:

function isPointInBiPlaneFrustrum(
    point: Vector3, plane1Point: Vector3, plane1Normal: Vector3, 
    plane2Point: Vector3, plane2Normal: Vector3): boolean --I swear this function name makes sense SOMEHOW https://en.wikipedia.org/wiki/Frustum
    
    local pointToPlane1Point = plane1Point - point
    local pointToPlane2Point = plane2Point - point
    local rightSideOfPlane1 = pointToPlane1Point:Dot(plane1Normal) > 0
    local rightSideOfPlane2 = pointToPlane2Point:Dot(plane2Normal) > 0
    return rightSideOfPlane1 and rightSideOfPlane2
end

function isPointInView(point: Vector3, view: Attachment, viewAngle: number, viewRange: number)
	local planeNormal1 = (view.WorldCFrame * CFrame.Angles(0, -viewAngle/2, 0)).LookVector
	local planeNormal2 = (view.WorldCFrame * CFrame.Angles(0,  viewAngle/2, 0)).LookVector
	
	A.CFrame = CFrame.new(view.WorldPosition, view.WorldPosition + planeNormal1) * CFrame.new(5, 0, 0)
	B.CFrame = CFrame.new(view.WorldPosition, view.WorldPosition + planeNormal2) * CFrame.new(-5, 0, 0)
	
	return isPointInBiPlaneFrustrum(point, view.WorldPosition, planeNormal1, view.WorldPosition, planeNormal2) 
		and isPointInRange(point, view.WorldPosition, viewRange) 
end

Here’s an illustration of what the view shape looks like, defined by a “Boss” part:

6 Likes

Hey its been a while since you sent this, im a bit confused on what to insert into the functions, for the cone shape without the y component, these are functions so where would i get the a,b in isPointInView, and how would I really use these in a function to check?

Whoops, looks like those were just some debugging things I forgot to remove. You should be able to just remove those two lines beginning with A.CFrame and B.CFrame.

You can use the functions to check if a specific point is inside the shape that each function represents. So if you have a list of all enemies, you can get a list of all enemies in view by looping through all enemies, checking if each one is in view, and inserting them into another table if they are.

Could you show me a way I could maybe use this idk how to use the functions well