How do I detect what face/side of a part a player clicks on using UserInputService?

I want players to be able to place blocks when they click, kind of like in minecraft. However, I can’t figure out how to detect what face of a part a player clicks on without using something like surface guis or multiple parts.

I’ve thought about comparing the position a player clicks on to the position of the block they clicked but I can’t figure out how that would work with blocks that are other shapes than cubes.

Could this maybe help you?

https://developer.roblox.com/en-us/api-reference/property/Mouse/TargetSurface

I need something like that but with UserInputService or ideally with raycasts

I looked through a few posts and found this, is this what you are looking for?

1 Like

That gets the enum material of the part I click on. What does select() do?

select() i believe is a built in LUA function I can try and find what i does it may take a few minute.

select (index, ···)

If index is a number, returns all arguments after argument number index . Otherwise, index must be the string "#" , and select returns the total number of extra arguments it received.

https://www.lua.org/manual/5.1/manual.html#5

I see. Seems like its not the problem

If you want to be able to place blocks on the side you click, then you can use raycasting and use the normal after clicking the mouse button. The normal is a vector that is perpendicular to a surface

local Mouse = Player:GetMouse()
local Camera = workspace.CurrentCamera
local ray = Camera:ViewportToRay(Mouse.X, Mouse.Y, 1)

-- this is where you customise your raycast params to your liking
local params = RaycastParams.new()

local result = workspace:Raycast(ray.Origin, ray.Direction * 300, params)
if result then
    local part = result.Instance
    local block = -- the block you want to position
    -- "block_pos" is the position where you want the block to be placed after clicking
    local block_pos = part.Position + result.Normal * ((part.Size + block.Size) * 0.5)
end

But more generally, if you do want the side the player clicks on, then you can use the dot product to compare each and every directional vector of the part touched with the surface normal, since if the raycast hits a face, the normal of the raycast and the normal of that face will be in the same direction. We use the Right/Up/Look vectors because they are vectors perpendicular to the surfaces of the parts, hence why we used them as normals:

local CF = part.CFrame

local normals = {
    Left = -CF.RightVector;
    Right = CF.RightVector;
    Bottom = -CF.UpVector;
    Top = CF.UpVector;
    Back = -CF.LookVector;
    Front = CF.LookVector;
}

for face, surface_normal in pairs(normals) do
    if surface_normal:Dot(result.Normal) >= 0.999 then
        print("The " .. dir .. " face was hit")
        break
    end
end
4 Likes