Scripting Helpers is winding down operations and is now read-only. More info→
Ad
Log in to vote
0

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

Asked by 5 years ago

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

Log in to vote
1
Answered by
xPolarium 1388 Moderation Voter
5 years ago
Edited 5 years ago

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

0
Thank you so much this is exactly what i was looking for TheMysticLynxx 89 — 5y
Ad
Log in to vote
1
Answered by 5 years ago

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)

Answer this question