Stop builds from clipping into parts with my building system

I’ve recently been making a building system and everything has been going smoothly except for this one bug that I have yet to find a fix on. The “GhostModel” clips inside of parts that the mouse is not looking at but the GhostModel is big enough to fit into. Here’s a video of what I mean:

I’ve tried a few solutions and I have yet to fix the bug. If anybody has any ideas on how I could fix this or put be in the right direction that would be great, thanks!

Try making it so that it moves out of the way if it’s touching anything other than the player and the baseplate.

I’ve already tried this. What I did is I got all touching parts of the GhostModel’s PrimaryPart and then removed the other parts that the PrimaryPart was touching from the model from the touchingParts table.

local connection = ghostBuild.PrimaryPart.Touched:Connect(function() end)
local touchingParts = ghostBuild.PrimaryPart:GetTouchingParts()
connection:Disconnect()
			
local canMovePart = false
for i,v in pairs(touchingParts) do
	if ghostBuild:FindFirstChild(v.Name) then
		local index = table.find(touchingParts, v)
		table.remove(touchingParts, index)
	end
end

If the table returned nil then that means that the GhostModel isn’t intersecting anything so it can move

if touchingParts[1] == nil then
	canMovePart = true
	print("Made true")
end

I then checked if “canMovePart” is either true or false and that determines if the GhostModel can move. If it is true then I set the PrimaryPart’s CFrame to a variable called “previousCFrame.” This is the CFrame I will set the GhostModel to if the table doesn’t return nil (it is intersecting with another part)

if canMovePart == true then
	ghostBuild:SetPrimaryPartCFrame(CFrame.new(Snap(mouseRay.Position + partOffset)) * CFrame.Angles(rot,0,0))
	previousCFrame = ghostBuild.PrimaryPart.CFrame
	print("Can move is true")
else
	ghostBuild:SetPrimaryPartCFrame(previousCFrame)
end

That produces this problem though:

It doesn’t seem like “previousCFrame” is working properly because the GhostModel stays at where it was when the part was intersecting it.

Hi,
I can see you’re placing stuff on a grid. Try shooting a ray down on all possible grid spaces the object could occupy. You may then compare to see which ray hits the highest part, and move the object up a few studs based on the position of the highest ray. This should also, in theory, fix the previous issue you were having in your original post (meaning you can delete the stuff you had previously done).

The “ground level” of your object would be the following:

local groundlevel = part.Position.Y - (part.Size.Y/2)

As for the ray:

local toplevel = part.Position.Y + (part.Size.Y/2)

local raylevel = toplevel - groundlevel--number of studs between the top and bottom of your object

local raylevelbase = raylevel--just to remind ourselves later what the distance between the top and bottom was

local centertotop = raylevel/2--just to avoid dividing by 2 over and over again in this loop

for x = part.Position.X - (part.Size.X/2), part.Position.X + (part.Size.X/2) do
	--change the for loop as you so wish, for snapping and whatnot
	for z = part.Position.Z - (part.Size.Z/2), part.Position.Z + (part.Size.Z/2) do
		local ray = game.Workspace:Raycast(Vector3.new(part.Position) + Vector3.new(x, centertotop, z), Vector3.new(0, raylevel, 0))
		--don't forget to add raycastparams so rays don't hit the ghost object itself and whatnot
		if ray then
			raylevel = ray.Position.Y
		end
	end
end

and finally the amount to move your object “up” by would be:

local height = groundlevel + (raylevelbase - raylevel)

I haven’t tested it myself so it might not work out of the box, but as long as you get the idea behind it you should be able to fix whatever problem it might have.

You can also use math.floor if you wish it to snap to a grid vertically as well, so objects cannot be stacked strangely.

Hi there, I realized you put a lot of work into your reply and thank you for that but I’m pretty confused. Does all of this run inside of a .Renderstepped function? And what exactly does this all of this do? Does it completely replace my grid system from before or is it just a detection system I can add on to it?

No, you just do it once whenever the object has been moved, at the end of the code you had already written. The for loops don’t contain waits, they are done all at once. It doesn’t replace your grid system, it’s simply an extra check you can add after your previous code that will look to see if your object is clipping into anything vertically and move the object to be on top of whatever it may be.