For quite a few projects I have worked on, I've found that I always need a way to detect if a player is clicking on a button or part from behind another part (Usually transparent and uncollidable.) I've never found a way to do this and have had to use work arounds. So my question is, what is the best way to see when a player clicks on a part even when there is another part beetwen the player and the part? If you need me to explain more I'm more then happy too.
How to let a user click on a object through another object?
2 answers
You could achieve this by shooting a Ray from the camera to the mouse position. You would need to supply Ray.new() with a starting/origin position and direction.
We can get the direction by using a function called :ScreenPointToRay() from the Camera object along with the mouse using :GetMouse().
local Players = game:GetService("Players")
local player = Players.LocalPlayer
local mouse = player:GetMouse()
local pointRay = workspace.CurrentCamera:ScreenPointToRay(mouse.X, mouse.Y, 1)
pointRay will be a unit vector of length 1 that is positioned to the camera's location in the world and faces the mouse's own position.
We can then create a new Ray and provide the Origin and Direction properties of pointRay to this Ray.
local distance = 500 --How far we want to shoot the ray in studs
local ray = Ray.new(pointRay.Origin, pointRay.Direction * distance)
local hit, pos = workspace:FindPartOnRay(ray)
We now have a ray firing from the camera to the mouse with a magnitude of 500 studs. We could connect all this to create some kind of click detection for certain parts. I use UserInputService to do this.
local Players = game:GetService("Players")
local uis = game:GetService("UserInputService")
local player = Players.LocalPlayer
local mouse = player:GetMouse()
local partToIgnore = workspace:WaitForChild("IgnorePart")
local targetedPart = workspace:WaitForChild("TargetPart")
local distance = 500
local function onInput(inputObject, gameProccessed)
if inputObject.UserInputType == Enum.UserInputType.MouseButton1 then
local pointRay = workspace.CurrentCamera:ScreenPointToRay(mouse.X, mouse.Y, 1)
local ray = Ray.new(pointRay.Origin, pointRay.Direction * distance)
local hit, pos = workspace:FindPartOnRay(ray, partToIgnore)
if hit == targetedPart then
hit.BrickColor = BrickColor.Random()
end
end
end
uis.InputBegan:Connect(onInput)
Here's a example gif linked to imgur.
For testing, I included a part that :FindPartOnRay will ignore. I then compare what it returns through the hit variable to my target part and change it's BrickColor to something random. You can see more on UserInputService for InputBegan here.
Note that this is done in a local script so nothing is replicated to the server.
In this case, you would use Mouse.TargetFilter, which gets an instance to ignore (Only one, but it will ignore descendants).
Here’s how you would use it:
local player = game:GetService(“Players”).LocalPlayer
local mouse = player:GetMouse()
mouse.TargetFilter = workspace.PartInFront
game:GetService(“RunService”).RenderStepped:Connect(function()
print(mouse.Target) — PartBehind
end)
(I’M ACTUALLY NOT SURE IF THIS WOULD WORK WITH CLICKDETECTORS PLEASE TRY)
This discussion is preserved as it was. New answers, comments, and votes are closed.

1 comment
Thank you so much this is exactly what i was looking for