How can I take any given position, and snap it onto a grid of stud increment?

I want to try creating a placement system from scratch. Although the mouse position and hit is easily accessible, how can I snap it onto a grid based on an editable stud increment, on all 3 axis? If you give formulas or sample code, please explain so I can understand it.

You can do this through a simple function.

function Round(x: number, y: number, z: number, grid: number)
	return Vector3.new(
		math.floor(x / (grid) + 0.5) * grid,
		math.floor(y / (grid) + 0.5) * grid,
		math.floor(z / (grid) + 0.5) * grid
	)
end

The expression math.floor(x / grid + 0.5) is used to round x to the nearest multiple of grid.
x / grid: Divides the x coordinate by grid to normalize it to the grid system.
math.floor(), it just rounds the number.
Multiplying by grid: After rounding, we multiply the result by grid to bring it back into the original scale, effectively snapping the coordinate to the nearest grid multiple.

Edit: @EtNowis 's explanation is a lot better! :sweat_smile:

2 Likes

suppose our grid is 1 stud in size,
we can use newX = math.floor(pos.X) to snap its center to a grid intersection. (do the same for all axis)

notice our block sizeX = 1, so its center is at 0.5, if we want to keep the block at the space rather than at the grid intersection, we need to offset by 0.5
newX = math.floor(pos.X) + 0.5
the same is actually true for all odd sizeX

if however our sizeX is even, then we don’t have to offset it because its center should sit right at the grid line.
newX = math.floor(pos.X)

combine both cases, we can do
newX = math.floor(pos.X) + ( math.floor(size.X) % 2 == 0 ? 0 : 0.5 )
or use if for easier understanding.

What if the grid is not 1 stud in size? Suppose the grid is 2 stud, now a 2x2x2 block equals 1 grid in length, and a 4x4x4 block is 2 grid in length. so we see that we can simply divide by gridSize to get the grid coordinate
newX_in_grid = math.floor(pos.X / gridSize) + ( math.floor(size.X / gridSize) % 2 == 0 ? 0 : 0.5 )
then we multiply by gridSize again to convert into world coordinate
newX = newX_in_grid * gridSize

You both explained it very well! Thank you for your responses!