Efficient way of getting entities in the player's FOV?
9 replies, posted
I understand that you could loop through every entity using ents.GetAll and test it against ply:Visible(ent), but that doesn't sound like the most efficient way. Is there a function I can use that already does this, or is a loop the best way?
[editline]8th July 2014[/editline]
Hmm, seems that ply:Visible(ent) only checks if the entity has a direct line of sight to the player, and not if the player is looking at it.
You can play with Entity:GetPos():ToScreen() and see if the returned values are lower than 0 and higher than both ScrW() and ScrH().
Thanks! Looks like it's better to trust the X and Y values than the "visible" field returned by ToScreen, as it seems to be true when it shouldn't be;
[code] for _, v in pairs(player.GetAll()) do
if not (v == ply) then
local screen_pos = v:GetPos():ToScreen()
print(not (screen_pos.x > ScrW() or screen_pos.y > ScrH()), screen_pos.visible)
end
end[/code]
Keep in mind that #GetPos() will only check the entity's origin.
#Visible() checks if the entity is visible at all.
ToScreen isn't really efficient though
[QUOTE=vexx21322;45328165]Keep in mind that #GetPos() will only check the entity's origin.
#Visible() checks if the entity is visible at all.[/QUOTE]
Visible check if the entity it's on the PVS, not on the FOV
[LUA]
local ratio = 0.95
local Player = FindMetaTable( "Player" )
function Player:IsLookingAt( vec )
return self:GetAimVector():DotProduct( ( vec - self:EyePos() ):Normalize() ) < ratio
end
[/LUA]
you could play with the ratio variable until it seems to only work when the ent is on your screen.
In the past I've used ents.FindInSphere as it's much faster than going through ALL entities along with ToScreen.
[QUOTE=nazer1290;45329826]In the past I've used ents.FindInSphere as it's much faster than going through ALL entities along with ToScreen.[/QUOTE]
Not sure if you're only looking to find players in a sphere around a player, or all entites.
However, if you are only looking for players in a sphere, here's a function that I posted a while back that's much more efficient than ents.FindInSphere if you only want players
[LUA]
local Vect = FindMetaTable( "Vector" )
local Ent = FindMetaTable( "Entity" )
local GetAll = player.GetAll
function Vect:PlayersInSphere( radius )
local plys = {}
local radius = radius * radius
local idx = 1
local DistToSqr = Vect.DistToSqr
local GetPos = Ent.GetPos
for _, ply in ipairs( GetAll() ) do
if DistToSqr( self, GetPos( ply ) ) <= radius then
plys[idx] = ply
idx = idx + 1
end
end
return plys
end
[/LUA]
[QUOTE=CallMePyro;45329516][LUA]
local ratio = 0.95
local Player = FindMetaTable( "Player" )
function Player:IsLookingAt( vec )
return self:GetAimVector():DotProduct( ( vec - self:EyePos() ):Normalize() ) < ratio
end
[/LUA]
you could play with the ratio variable until it seems to only work when the ent is on your screen.[/QUOTE]
Just posting to make this more accurate.
[lua]local cos = math.cos
local Player = FindMetaTable("Player")
function Player:GetDefaultFOV()
if self:IsBot() then
return 90 -- Bots are bots, who cares
end
return tonumber( self:GetInfo( "fov_desired" ) )
end
function Player:IsInFOV( pos )
local fov = cos( self:GetFOV() / self:GetDefaultFOV() )
local dir = ( pos - self:EyePos() ):GetNormal()
return self:GetAimVector():Dot( dir ) < fov
end[/lua]
Sorry, you need to Log In to post a reply to this thread.