Help with Placement on Surface

Coding a grid-based object placement system & having trouble getting objects to place on a part.
Issue: Object ends up partially or completely inside the part instead of on the part’s surface.

Can’t seem to find a solution anywhere.
Code below. Looking for any suggestions or fix.

Thank you.

local players = game:GetService("Players")
local runService = game:GetService("RunService")

local object = game:GetService("ReplicatedStorage").Items["Plank Tile"]:Clone() -- "Plank Tile" is a 3x3x1 part
object.Parent = game:GetService("Workspace").ItemHolder
local primary = object.PrimaryPart

local player = players.LocalPlayer
local mouse = player:GetMouse()
mouse.TargetFilter = object

-- Offsets equal to half of object's size
local offsetX = primary.Size.X*0.5
local offsetY = primary.Size.Y*0.5
local offsetZ = primary.Size.Z*0.5

-- Function that rounds the object's position to the nearest stud
local function snap(pos)
	local newX = math.round(pos.X)
	local newY = math.round(pos.Y)
	local newZ = math.round(pos.Z + 0.5) - 0.5
	return CFrame.new(newX,newY,newZ)
end

-- Function that handles where the object will be placed
function placement()
	
	local posX = mouse.Hit.X
	local posY = mouse.Hit.Y
	local posZ = mouse.Hit.Z

	local pos = CFrame.new(posX, posY, posZ)
	local snappedPos = snap(pos)
	local surface = mouse.TargetSurface
	
	-- Pivots object to the desired position and applies offset depending on the face of the target part
	if surface.Name == "Top" then
		local finalCFrame = object:PivotTo(CFrame.new(snappedPos.X, snappedPos.Y + offsetY, snappedPos.Z))
	elseif surface.Name == "Bottom" then
		local finalCFrame = object:PivotTo(CFrame.new(snappedPos.X, snappedPos.Y - offsetY, snappedPos.Z))
	elseif surface.Name == "Left" then
		local finalCFrame = object:PivotTo(CFrame.new(snappedPos.X - offsetX, snappedPos.Y, snappedPos.Z))
	elseif surface.Name == "Right" then
		local finalCFrame = object:PivotTo(CFrame.new(snappedPos.X + offsetX, snappedPos.Y, snappedPos.Z))
	elseif surface.Name == "Front" then
		local finalCFrame = object:PivotTo(CFrame.new(snappedPos.X, snappedPos.Y, snappedPos.Z - offsetZ))
	elseif surface.Name == "Back" then
		local finalCFrame = object:PivotTo(CFrame.new(snappedPos.X, snappedPos.Y, snappedPos.Z + offsetZ))
	end
end

runService:BindToRenderStep("PlacementLoop", 1, placement)
1 Like

Hey, I’ve had this problem in the past aswell.

What I did was add an invisible PrimaryPart to the model you’re trying to place. It should be about the same size as your entire model. Then, when you connect to RenderStep and move the CFrame of your model, add half of the PrimaryPart’s Y to the Y axis.

local ObjectCFrame = CFrame.new(Mouse.Hit.Position.X, Mouse.Hit.Position.Y + PreviewObject.PrimaryPart.Size.Y/2, Mouse.Hit.Position.Z)

Your kind of problem has been asked and answered NUMEROUS times before. Please look through the forum thoroughly before making a thread, it saves both your time and the people trying to help.

1 Like

Thanks! Sorry, I was apparently searching using wrong keywords. Looking at the previous posts now.

Thank you so much! These posts helped immensely!