Snapping object to grid relative to an angled part

Hello!

Currently working on a placement system as a means to practice my scripting skills, however I have run into a problem. When putting my mouse over a wall, the object should snap to the wall’s rotation and move along the wall depending on the mouse position. The problem is that I am not sure how I would go about doing this because I don’t know how to assign the part’s position relative to the centre of the wall if that makes sense.

I have looked up things like Object and World space, however I can’t really seem to understand how it works and how I would go about solving this issue.

Object placement script, it snaps it to the wall but I’m not able to move the part along the wall if that makes sense:

local item
local snappedToWall = false
	currentConnections[#currentConnections + 1] = runService.RenderStepped:Connect(function()
		item = item or Instance.new('Part')
		item.Anchored = true
		local target = mouse.Target
		item.Parent = ignoreParts
		item.Position = snap(mouse.Hit.p) -- snaps the object to the grid, not the issue but I can post it should it be needed.
		if string.find(string.lower(target.Name), 'wall') then
			print('wall')
			item.CFrame = target.CFrame * CFrame.new(item.Size.X / 2, 0, 0) -- offsets the part from the wall's CFrame
		end
	end)

Video of the problem and how far I’ve gotten:

EDIT:

I have come up with somewhat of a solution, but I still need help if anyone can help with that.

2 Likes

Hey, what’s in that snap() function…?

2 Likes

Just snaps it to the closest increment.

local gridSnap = 5

local function snap(vector)
	local newVector = Vector3.new(
		math.floor((vector.X / gridSnap)) * gridSnap,
		vector.Y,
		math.floor((vector.Z / gridSnap)) * gridSnap
	)

	return newVector
end
1 Like

Have you tried doing the snap function but do the same thing for Y as you do X and Z? (So like make a separate snapWall() function.

1 Like

The Y axis isn’t the problem. The Y axis being ignored just makes the object freely moveable along the Y axis.

1 Like

Yes, but you didn’t use the snap() function for walls…

1 Like

Right, it should snap along the width of the wall which is what I don’t know how to do.

1 Like

You have to somehow combine target.CFrame * CFrame.new(item.Size.X / 2, 0, 0) with math.floor((vector.X / gridSnap)) * gridSnap somehow…

Yeah, I’m stumped too. I’ll take another look at this tmr and try to figure it out.

Let me know if/when you do!

2 Likes

I did come up with somewhat of a solution but it comes back to snapping it to a grid which I still am having problems with.

What I have so far:

item.Position = mouse.Hit.p -- Snap it to the hit position
item.Orientation = target.Orientation -- Same orientation as the wall
item.CFrame *= CFrame.new((item.Size.X) / 2, 0, 0) -- offset it by half of the item's size

I also tried using modulus to achieve the grid snapping effect but it ended up being buggy and not really what I was looking for.

local function snapAxis(number)
    return math.floor((number / gridSnap) + 0.5) * gridSnap
end
			local yAxis = snapAxis(item.Position.Y)
			item.Position = Vector3.new(item.Position.X, yAxis, item.Position.Z)
			local posX, posZ
			if item.Position.X < 0 then
				posX = -item.Position.X
			else
				posX = item.Position.X
			end
			if item.Position.Z < 0 then
				posZ = -item.Position.Z
			else
				posZ = item.Position.Z
			end
			local diffX = posX % gridSnap
			local diffZ = posZ % gridSnap
			item.CFrame -= Vector3.new(-diffX, 0, -diffZ) -- also tried multiplication

FINALLY got it!!! I was overcomplicating things way more than I had to.

local offsetCFrame = CFrame.new(snap(item.CFrame:ToObjectSpace(target.CFrame).Position)) -- find the difference between the hit position and the grid snap position relative to the mouse target
item.CFrame = target.CFrame:ToWorldSpace(CFrame.new(-offsetCFrame.Position.X, 0, -offsetCFrame.Position.Z)) -- set the new snapped position (ignore Y for now)
item.CFrame *= CFrame.new(item.Size.X / 2, 0, 0) -- offset for half of the item's size
item.Position = Vector3.new(item.Position.X, snapAxis(mouse.Hit.p.Y), item.Position.Z)  -- set the final position, snap to the Y axis
4 Likes

I’m just curious, what does the snap function?

It basically just rounds a number up or down.

1 Like