Hi, I am trying to create a script that checks if a player is looking at a part. How would I go about doing this? The camera is always in 1st person if that information matters.
cast a ray from the cameras CFrame and see if it returns any parts
Okay I will do that, thank you
How would I implement this? I tried doing this but it just doesn’t work
Do you want to know if a player is directly looking at a part or if it is simply on the screen? If you want the former, raycasting is probably your best bet. You can roughly implement it like this:
local part = workspace:WaitForChild'a part'; --a part to determine whether the player is looking at
local cam = workspace.CurrentCamera;
local length = 100; --a max distance in which the ray can detect objects. we multiply the camera's look vector by this number
local cfg = RaycastParams.new();
cfg.FilterDescendantsInstances = {game.Players.LocalPlayer.Character}; --specify a table of anything that the raycast should ignore (you always stare at your character, so i highly recommend you keep the player's character in here)
local cast = workspace:Raycast(cam.CFrame.Position, cam.CFrame.LookVector * length, cfg); --start a ray at the camera's position and extrude it in its look direction (cframe allows you to determine both position and orientation of the camera) with our specified ray parameters
if cast and cast.Instance == part then --make sure the ray actually hit something and make sure its the part we want to know about
--do stuff
end
Otherwise, detecting whether an object is on the screen is even simpler:
local part = workspace:WaitForChild'whatever';
local cam = workspace.CurrentCamera;
local isOnScreen = select(2, cam:WorldToViewportPoint(part.Position)); --get the position of the object in question on the player's screen. this also tells you whether the passed in vector is actually on the player's visible viewport or not, which is the only thing we need (hence select)
local plr = game.Players.LocalPlayer
local char = plr.Character or plr.CharacterAdded:Wait()
local primary = char.PrimaryPart or char:WaitForChild("HumanoidRootPart")
local cam = workspace.CurrentCamera
local function OnScreen(object)
local IsObsufcated = #cam:GetPartsObscuringTarget({object.Position},{object,char}) == 0
local _, OnScreen = cam:WorldToScreenPoint(object.Position)
return OnScreen and IsObsufcated
end
OnScreen(primary) -- should print true
made a more accurate version
local function OnScreen(object : Part)
local Positions = {
(object.CFrame * CFrame.new(object.Size.X/2,object.Size.Y/2,object.Size.Z/2)).Position,
(object.CFrame * CFrame.new(-object.Size.X/2,object.Size.Y/2,object.Size.Z/2)).Position,
(object.CFrame * CFrame.new(object.Size.X/2,-object.Size.Y/2,object.Size.Z/2)).Position,
(object.CFrame * CFrame.new(object.Size.X/2,object.Size.Y/2,-object.Size.Z/2)).Position,
(object.CFrame * CFrame.new(-object.Size.X/2,-object.Size.Y/2,-object.Size.Z/2)).Position,
(object.CFrame * CFrame.new(-object.Size.X/2,-object.Size.Y/2,object.Size.Z/2)).Position,
(object.CFrame * CFrame.new(object.Size.X/2,-object.Size.Y/2,-object.Size.Z/2)).Position,
(object.CFrame * CFrame.new(-object.Size.X/2,object.Size.Y/2,-object.Size.Z/2)).Position,
}
local IsObsufcated = #cam:GetPartsObscuringTarget(Positions,{object,char}) == 0
local _,OnScreen = cam:WorldToScreenPoint(object.Position)
for _,pos in Positions do
if #cam:GetPartsObscuringTarget({pos},{object,char}) == 0 then
IsObsufcated = true
break
end
end
return OnScreen and IsObsufcated
end
Thank you! I will try this since I haven’t come to an answer yet
Thank you so much, I will try this
hi where can i put this script?
Code that accesses CurrentCamera
and LocalPlayer
only works in the client. I recommend using StarterCharacter
so that the ray configuration updates with a new character reference per death/reset.
Also check out the post from @kalabgs since it’s way more reliable and intricate despite its complexity.
How would i check if it’s on the screen???
And how fire a function then?
isOnScreen
on the second code snippet is a boolean that denotes whether part
is on the local player’s screen. I retrieved that by selecting the second value of the tuple that WorldToViewportPoint returns.
You can execute code based on isOnScreen
’s value. If it’s true, then run your function:
local function myCode()
--my code
end
if isOnScreen then
myCode();
end
so how is the isonscreen detected?
aka where?
could you make a script that is pasted into a part and if its visible it gets invisible?
it would be really helpful to learn
Hello so what I did is I made a part in the workspace which is anchored and invisible I made a local script in the startercharacterscripts made the isonscreen code in check if is on screen then print(“Is on screen”) as you can see in the following code:
local part = workspace:WaitForChild("Behind");
local cam = workspace.CurrentCamera;
local isOnScreen = select(2, cam:WorldToViewportPoint(part.Position));
if isOnScreen then
print("isonscreen")
end
Why doesn’t it work?
Are you aware that your provided code snippet will only perform a single check? The script will only determine whether the part is on the screen once per character load. If you want this behavior to be recursive, you can repeatedly call it with traditional loops or RunService update events.
local part: BasePart;
local cam = workspace.CurrentCamera;
game:GetService'RunService':BindToRenderStep('check_visibility', Enum.RenderPriority.Camera.Value + 1, function()
if select(2, cam:WorldToViewportPoint(part.Position)) then
print'on screen';
end
end)