Help with placement system / raycasting

Hello there!
I got into raycasting a few days ago and decided to try out making a placement system.
My goal is to achieve a simple placement system which supports placing down models or parts, moving them and rotating them.

The issue is when you rotate a part, it starts to clip though the surface of other parts (The surface normal becomes weird and the part doesn’t stick to the surface the mouse is pointing at.)

Normal behavior without rotation:
Normal

The issue after I rotate:
Rotate

I’ve read many posts on the devforum and I’ve tried changing the values, but it just breaks the whole system.
(The models I use are just simple models with PrimaryParts.
Models

LocalScript inside StarterPlayerScripts.

 -- Services
local UIS = game:GetService("UserInputService")

-- Variables
local player = game:GetService("Players").LocalPlayer

local mouse = player:GetMouse()

local target

local position

local normal

local models = workspace.Models

local gridSize = 0.1

local rotation = 0

local item

wait(2)

-- Functions
for i, model in pairs(models:GetChildren()) do
	local button = Instance.new("TextButton", player.PlayerGui.PlacementGui.ScrollingFrame)
	button.Size = UDim2.new(1,-12,0,50)
	button.ZIndex = 2
	button.Text = model.Name
	button.Name = model.Name
end

for i, button in pairs(player.PlayerGui.PlacementGui.ScrollingFrame:GetChildren()) do
	if button and button:IsA("TextButton") then
		button.MouseButton1Click:Connect(function()
			print(button.Text)
			if item ~= nil then item:Destroy() end
			item = models[button.Text]:Clone()
			item.Parent = workspace
		end)
	end
end

local function RayCast()
	local ray = Ray.new(workspace.CurrentCamera.CFrame.p, (mouse.Hit.p - workspace.CurrentCamera.CFrame.p).unit * 64)
	target, position, normal = workspace:FindPartOnRayWithIgnoreList(ray, {player.Character, item})
	if position ~= nil and target ~= nil and normal ~= nil then
		--print(position)
		--print(target.Name)
		--print(normal)
	end
end

local function Position(part)
	local x = math.floor((position.X + (normal.X * (part.Size.X / 2))) / gridSize + 0.5) * gridSize
	local y = math.floor((position.Y + (normal.Y * (part.Size.Y / 2))) / gridSize + 0.5) * gridSize 
	local z = math.floor((position.Z + (normal.Z * (part.Size.Z / 2))) / gridSize + 0.5) * gridSize
	return x, y, z
end

local function Move()
	if item ~= nil and item.PrimaryPart then
		local x, y, z = Position(item.PrimaryPart)
		item:SetPrimaryPartCFrame(CFrame.new(x, y, z) * CFrame.Angles(0, math.rad(rotation), 0))
	end
end

mouse.Button1Down:Connect(function()
	if item ~= nil then
		item:Clone().Parent = workspace
	end
end)

UIS.InputBegan:Connect(function(inputObject, gPe)
	if gPe then return end
	if inputObject then
		if inputObject.KeyCode == Enum.KeyCode.X then
			print("X")
			if item ~= nil then item:Destroy() end
		elseif inputObject.KeyCode == Enum.KeyCode.R then
			rotation = rotation + 90
			if rotation == 360 then rotation = 0 end
			print(rotation)
		end
	end
end)


game:GetService("RunService").RenderStepped:Connect(function()
	RayCast()
	Move()
end)

Thanks in advance, any help would be great :slight_smile:

Oh, thanks so much for the help! :smiley: