Scripting HelpersARCHIVE
A little piece of Roblox history. Preserved for everyone, one question at a time.Read about the archive →
✓ ANSWER ACCEPTED

How to let a user click on a object through another object?

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.

2 answers

✓ Accepted answer

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.


##ScreenPointToRay

1 comment

0

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

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.