I have a list of Vector3 points.
How would I get the closest point that the player’s camera is looking at?
Kinda like what’s going on in this game:
Notice the nametags for the training dummys
This is a way I would try implementing it
Loop through every point once and make sure the point is visible on the camera using WorldToViewportPoint
Then draw a series of points right in front of the camera. For every new point, loop through every NPC position to find the closest.
this is a lot of looping tho, and it has to happen very often
Is there a more efficient/better way to do this?
2 Likes
You should have some way of getting every point that is in range without having to loop through every point in the game. Look into quadtrees for a really nice way of doing that.
You then filter out every point that is off-screen.
You then sort the remaining points based on a scoring function. The scoring function should take into account distance from the camera and the angle to the camera’s look direction. You can tweak how important each of these are to get the right feel.
function vectorAngle( v1, v2 )
return math.acos( v1.Unit:Dot(v2.Unit) )
end
function vectorDistance( v1, v2 )
return (v2 - v1).Magnitude
end
function targetScore( targetPoint, cameraPos, cameraLookVector )
local distance = vectorDistance(targetPoint, cameraPos)
local angle = vectorAngle(cameraLookVector, (cameraPos - targetPoint))
return distance * 10 + math.deg(angle) * 2
end
function sortTargets( targets, cameraPos, cameraLookVector )
table.sort(targets, function( a, b )
return
targetScore( a, cameraPos, cameraLookVector ) <
targetScore( b, cameraPos, cameraLookVector )
end)
end
function isOnScreen( worldPoint )
local _, onScreen = camera:WorldToScreenPoint(worldPoint)
return onScreen
end
function getPotentialTargets( camera )
-- you figure this one out. Or just return every target in the game to test it.
end
function getBestTarget( camera )
local ts = {}
for _, t in pairs(getPotentialTargets(camera)) do
if isOnScreen(t) and vectorDistance(camera.CFrame.p) <= MAX_TARGET_DISTANCE then
table.insert(r, ts)
end
end
sortTargets(ts)
return ts[1]
end
4 Likes
That’s smart!
Using angles instead of position is way more efficient.
Is it worth doing a quad tree if the points are dynamically moving around though?
Just using angles will significantly improve performance. I might skip on using quadtrees because I don’t completely see how that would work.
Thank you
Computing angles vs distances isn’t really that much faster. I just think it might make the system work more intuitively to have both distance and angle have an influence, so e.g. a really close enemy at the edge of the screen doesn’t get targeted if there’s a sorta close enemy in the center of the screen.
The issue is having to do it for every single thing that can be targeted, which might be in the 100s to 1000s.
Keeping the quadtree up-to-date is obviously more complex when enemies are moving around, but it can be done and it should still give some performance gain. Don’t optimize prematurely tho
1 Like