Snapping a model/part to one of 6 faces of another model/part

Tried looking this up, found nothing that I’ve needed. Basically I’m trying to find a method of snapping a model/part to one of the 6 faces of the target part based on the position of the mouse?

Here’s what I have so far:

local Grid = 2

function snap(pos, modelSize)  -- Position and ModelSize
	local X = math.floor(pos.X/Grid+0.5)*Grid 
	local Y = math.floor(pos.Y/Grid+0.5) * Grid + modelSize.Y/2  -- Snaps properly on Y axis however, if I apply the same "modelSize.(X/Z)/2  then the placement system starts acting weird.
    local Z = math.floor(pos.Z/Grid+0.5)*Grid 
	return Vector3.new(X,Y,Z) 
end

1 Like

How exactly does the placement system act weird when you add ModelSize.{X, Z} to the other variables? We can’t really do much without knowing exactly what’s going wrong. Is modelSize the size of the model being moved or the target?

modelSize is the size of the model that’s being moved. I’m not sure how to describe the weird movement of it when applied to X, Z but it doesn’t snap where the mouse is pointing at, it acts more like an offset from the mouse.

So how exactly are you supposed to snap to the face of a target part without the script even referencing a target part?

The target part is detected by casting a ray from the mouse.

local Grid = 2

function snap(pos, modelSize)  -- Position and ModelSize
	local X = math.floor(pos.X/Grid+0.5)*Grid 
	local Y = math.floor(pos.Y/Grid+0.5) * Grid + modelSize.Y/2  -- Snaps properly on Y axis however, if I apply the same "modelSize.(X/Z)/2  then the placement system starts acting weird.
    local Z = math.floor(pos.Z/Grid+0.5)*Grid 
	return Vector3.new(X,Y,Z) 
end

RendersteppedFunction()
IgnoreTable = {}

		    local UnitRay = Mouse.UnitRay
			local ray = Ray.new(UnitRay.Origin,UnitRay.Direction*100)
			local modelSize = PlacementModule:CalculateModelSize(SampleBlock, rotationY) --shouldn't matter
			local target,pos,normal = workspace:FindPartOnRayWithIgnoreList(ray,IgnoreTable)
			ActualPosition = CFrame.new(snap(pos, modelSize))*CFrame.Angles(0,math.rad(rotationY),0)
end)

I’m not exactly sure what you’re trying to achieve? Do you just want the model to go in a grid? Or do you want rotate with the face of the part?
Anyways the first thing you’ll need to change is your snap functions. Altho it looks like it’s on a grid it actually isn’t. Try it with models which are bigger than others. They don’t align. To fix this you will need to ‘gridify’ the corner of the hitbox instaid of the center.

function snap(pos, modelSize)  -- Position and ModelSize
	local X = math.floor((pos.X+modelSize.X/2)/Grid+0.5)*Grid-modelSize.X/2
	local Y = math.floor(pos.Y/Grid+0.5) * Grid + modelSize.Y/2  -- Snaps properly on Y axis however, if I apply the same "modelSize.(X/Z)/2  then the placement system starts acting weird.
    local Z = math.floor((pos.Z+modelSize.Z/2)/Grid+0.5)*Grid-modelSize.Z/2
	return Vector3.new(X,Y,Z) 
end

This should now properly put the model in a grid. I still am not quite sure what you mean with snapping to one of the 6 faces but I believe this should fix it.

1 Like

Hey thank you for you reply.

https://gyazo.com/5f129d29e3b4711e5006c3336828c2e4

I’m trying to stop parts from intersecting each other by snapping it to one of the faces. At the moment as you can see in the video the model is going through the target model instead of going forward.

Also thank you a lot for the fix there!

Ah okay thank you for that video, that helps out ALOT!
You might need to add an offset to my previous piece of code (X+0.5 might do it)
Remember that rays return a normal value? Yeah we’re going to use that.
If you don’t know here’s a very short description of normal values.
Normal values are vectors which describe a rotation. How it all works doesn’t really matter for now but I would suggest searching it up. Normal values are always between -1 and 1. Which is extreemly usefull in our case. If we multiply the the normal with modelSize then devide it by 2 we already solved your problem!

ActualPosition = CFrame.new(snap(pos, modelSize))*CFrame.Angles(0,math.rad(rotationY),0) + normal*modelSize/2

This works because faces of a part are basicly normal vectors. Up for example is (0,1,0) if you multiply that by the modelsize you get only the Y size of the part! Devide that by 2 + the grid and you got a part placed ontop!

1 Like

Thank you! That really helped out and solved my problem! Although I implemented the same code for the Y snapping as you did for X, Z.

function snap(pos, modelSize)  -- Position and ModelSize
	local X = math.floor((pos.X+modelSize.X/2)/Grid+0.5)*Grid-modelSize.X/2
	local Y = math.floor((pos.Y+modelSize.Y/2)/Grid+0.5)*Grid-modelSize.Y/2 
    local Z = math.floor((pos.Z+modelSize.Z/2)/Grid+0.5)*Grid-modelSize.Z/2
	return Vector3.new(X,Y,Z) 
end
1 Like