An update lol, managed to do what I was trying to, basically
I connect an event to the Cameras cframe changing, which then gets runs a function to additionally check for interactables.
If it’s within reach and on the screen, I get the magnitude between middle of the screen and the :WorldToViewportPoint() position of the object.
Do some comparing and find out which one is the closest if there are multiple
What I’m thinking is i have different proximityPrompts inside of this script, that get cloned to the highlighted object based on which tag it has (for example, doors/collectibles/buttons will have different tags), and inside of it theres a script that does what its supposed to do, and get deleted when it gets dehighlighted.
Thanks again for helping me out lol
And if anyone is opening this topic for a solution, you can get the ALL objects within your camera viewport, every frame, by doing:
local RunService = game:GetService("RunService")
local cam = workspace.CurrentCamera
-- you could use RenderStepped/Stepped/Heartbeat
RunService.RenderStepped:Connect(function()
for _, object in workspace:GetDescendants() do -- to get all descendants of the workspace
if object.ClassName ~= "Part" then -- to check if the object is a part,
continue --otherwise it might not have a position property
end
local vector, OnScreen = cam:WorldToViewportPoint(object.Position)
-- vector returns a Vector3 value vector.X is X position on screen, vector.Y is Y position on screen,
-- vector.Z is how far away from the screen it is
-- OnScreen is a bool value that returns true if the object is on screen and false if it is off screen
if OnScreen then
print(object, " is on the screen!")
end
end
end)
Does not work on models btw, you can create a dedicated function to get the position of the thing you supply it with, although if you supply it something wrong it will result in an error (for example, an empty folder)
heres the function:
local function getPosition(thing)
if not thing then
print("didn't get thing position")
return
end
if thing:IsA("Model") then
local pivot = thing:GetPivot()
return Vector3.new(pivot.X, pivot.Y, pivot.Z)
else
return thing.CFrame.Position
end
end
and you would replace :WorldToViewportPoint(obj) with :WorldToViewportPoint(getPosition(object))
Please note that I did not use this, as it is pretty hard on performance and my use case was different.
You’re better off using a while true do loop instead of runservice, and pausing like 0.1 seconds, but if you want it for every frame this script works.
Doesn’t work with unions apparently, and invisible parts will still get counted aslong as theyre within the bounds of the screen
Read more about RunService here
Read more about the :WorldToViewportPoint() here and to find out the difference between it and :WorldToScreenpoint()