Untested, but I got bored so this should do it:
-- Given a part and a position, returns which faces the position lies on or is
-- within `epsilon` studs of.
-- @returns a Faces object: https://developer.roblox.com/en-us/api-reference/datatype/Faces
local function WhichFaces(part, position, epsilon)
epsilon = epsilon or 0.1
local pos = part.CFrame:ToObjectSpace(position)
local halfSize = part.Size / 2
-- first check that we're within the part's outside bounds
if math.abs(pos.Y) < halfSize.Y + epsilon
and math.abs(pos.Z) < halfSize.Z + epsilon
and math.abs(pos.X) < halfSize.X + epsilon
then
local faces = {}
-- check if we're close to an edge
if pos.Y > halfSize.Y - epsilon then table.insert(faces, Enum.NormalId.Top) end
if pos.Y < epsilon - halfSize.Y then table.insert(faces, Enum.NormalId.Bottom) end
if pos.Z > halfSize.Z - epsilon then table.insert(faces, Enum.NormalId.Back) end
if pos.Z < epsilon - halfSize.Z then table.insert(faces, Enum.NormalId.Front) end
if pos.X > halfSize.X - epsilon then table.insert(faces, Enum.NormalId.Right) end
if pos.X < epsilon - halfSize.X then table.insert(faces, Enum.NormalId.Left) end
return Faces.new(unpack(faces))
else
return Faces.new()
end
end
-- USAGE e.g.
local mousePosition = Vector3.new(1, 1, 0)
local myPart = workspace.Part
local faces = WhichFaces(myPart, mousePosition)
if faces.Top then
print("Top face!")
if faces.Front then
print("Top-front edge too!")
if faces.Right then
print("Top-front-right corner!")
end
elseif faces.Left then
print("Top-left edge!")
end
-- etc.
end