Problems with furniture clipping through wall

Originally I had thought I fixed this problem, and although it is partially fixed (e.g, it works for the floor). There are still problems with the furniture clipping through the wall when selecting where to place them.
https://gyazo.com/a710722b1adf08b095ca704c3fee1726

The local script

mouse.Move:Connect(function()
	if CreatedFurnitureLocal ~= nil then
		if CreatedFurnitureLocal then
			local SizeY = FurnitureLocal.PrimaryPart.Size.Y
			local SizeX = FurnitureLocal.PrimaryPart.Size.X
			local SizeZ = FurnitureLocal.PrimaryPart.Size.Z
			for i, v in pairs(FurnitureLocal:GetChildren()) do
				if v.Name ~= "GridPart" then
					v.Transparency = 0
				end
			end
			SnapFurniture()	-- "Snaps" furniture to grid
			mouse.TargetFilter = FurnitureLocal

			FurnitureLocal:SetPrimaryPartCFrame(CFrame.new(Vector3.new(posX + SizeX/2, posY + SizeY/2, posZ + SizeZ/2)))	-- The important bit, pos values comes from a snap to grid function
		end
	end
end)

The important bit here is FurnitureLocal:SetPrimaryPartCFrame(CFrame.new(Vector3.new(posX + SizeX/2, posY + SizeY/2, posZ + SizeZ/2))) which is supposed to prevent furniture from going through parts.

You are directly adding the offset to the position, which means it will only work in certain directions, since axes are composed of both positive and negative increments. You should try getting the surface normal of the wall that your cursor is at, that way you know the correct direction to offset the CFrame.

There’s an older thread discussing about this problem with a proper fix: Block Placement System Help (Positioning the blocks relative to other parts?) - #8 by Intended_Pun

I see, but this would involve the use of raycasting to find the surface normal right?
Would there an alternative to using raycasting?

Yes, it does use raycasting, what’s the problem with using it? I don’t know any alternative to finding surface normals with rays.

There’s no problem apart from me being unfamiliar with raycasting.
How would I create multiple rays in all 6 directions of a furniture piece and wouldn’t this be pretty performant intensive?

You’re not creating rays from the furniture. You’re creating just one ray from your screen (workspace.CurrentCamera) and pointing it to Mouse.Hit, which is the location of your cursor. Because the furniture is right at cursor and right in front of a wall, the ray will hit that wall and you will be able to find the surface normal of that wall.
Pretty much everything you need to know is in the sample .rbxl file inside the thread I mentioned above.

Taking a look at the rbxl file, I wish to use raycast params to create a ray. However I had only gotten this far:

function doFakeMouseStuff()
	local rayOrigin = mouse.UnitRay.Origin
	local rayDirection = mouse.UnitRay.Direction.unit * 200
	
	local ignoreList = {item, player.Character}	--game.Workspace:WaitForChild("BaseStore"):GetChildren()
	local newRay = RaycastParams.new()

	newRay.FilterDescendantsInstances = {item, player.Character}
	newRay.FilterType = Enum.RaycastFilterType.Blacklist
	local raycastResult = workspace:Raycast(rayOrigin, rayDirection, newRay)
	target, pos, norm = raycastResult  
end

In this case, how would I assign the target, pos and norm variables to the raycastResult?

raycastResult is a table. It has the instance(what the ray hit), the position(where it hit), the material(the material/terrain of where it hit), and the normal(which is what you want). So to get the normal, you simply put its name.

local raycastResult = workspace:Raycast(rayOrigin, rayDirection, newRay)
local normal = raycastResult.Normal

The normal is a Vector3, ranging from -1 to 1 in values. You just need to multiply those axes with the original offsets in your script.

FurnitureLocal:SetPrimaryPartCFrame(CFrame.new(Vector3.new(
  posX + (SizeX/2) * normal.X, 
  posY + (SizeY/2) * normal.Y,
  posZ + (SizeZ/2) * normal.Z
)))

(I haven’t tested any of this, but in theory, it should work)

Or instead of breaking down the positions into pieces and putting it back together, here’s an easier way:

--Pos would be Mouse.Hit
FurnitureLocal:SetPrimaryPartCFrame(Pos + (FurnitureLocal.PrimaryPart.Size/2 * normal))

If you need any more assistance, these should help:

2 Likes