Weird offset with grid placement system

This is a support category for asking questions about how to get something done on the Roblox websites or how to do something on Roblox applications such as Roblox Studio.

You can write your topic however you want, but you need to answer these questions:

  1. What do you want to achieve? Keep it simple and clear!
    A grid placement system

  2. What is the issue? Include screenshots / videos if possible!
    Weird block offset when placing a part to the side of another part

  1. What solutions have you tried so far? Did you look for solutions on the Developer Hub?
    changing Y offset

After that, you should include more details if you have any. Try to make your topic as descriptive as possible, so that it’s easier for people to help you!

here is the script:

local ReplicatedStorage = game:GetService("ReplicatedStorage")
local PlaceRemote = ReplicatedStorage.Remotes.Place
local PartsFolder = ReplicatedStorage.Parts

local gridSize = 2

local function SnapToGrid(pos, hitPart, PartClone)
	return Vector3.new(
		math.floor(pos.X / gridSize + 0.5) * gridSize,
		hitPart.Position.Y + (PartClone.Size.Y / 2) + (hitPart.Size.Y / 2),
		math.floor(pos.Z / gridSize + 0.5) * gridSize
	)
end

PlaceRemote.OnServerEvent:Connect(function(player, partName, hitPos, normal, hitPart)
	local part = PartsFolder:FindFirstChild(partName)
	if not part or not hitPart then return end

	local PartClone = part:Clone()
	PartClone.Anchored = true

	local offset = normal * (PartClone.Size.Y / 2)
	local targetPos = hitPos + offset
	local snappedPos = SnapToGrid(targetPos, hitPart, PartClone)

	PartClone.Position = snappedPos
	PartClone.Parent = workspace
end)

and here is the client script if needed:

local ReplicatedStorage = game:GetService("ReplicatedStorage")
local PlaceRemote = ReplicatedStorage.Remotes.Place

local player = game.Players.LocalPlayer
local mouse = player:GetMouse()

mouse.Button1Down:Connect(function()
	if not player.Character then return end

	local unitRay = mouse.UnitRay
	local raycastParams = RaycastParams.new()
	raycastParams.FilterType = Enum.RaycastFilterType.Exclude
	raycastParams.FilterDescendantsInstances = {player.Character}

	local raycastResult = workspace:Raycast(unitRay.Origin, unitRay.Direction * 500, raycastParams)

	if raycastResult then
		local hit = raycastResult.Instance
		local pos = raycastResult.Position
		local normal = raycastResult.Normal
		PlaceRemote:FireServer("BasicBrick", pos, normal, hit)
	end
end)
hitPart.Position.Y + (PartClone.Size.Y / 2) + (hitPart.Size.Y / 2),

This snaps it to the part above.

this is it otherwise

math.floor(pos.Y / gridSize + 0.5) * gridSize,

Are you using hitPos or the position of the part that was hit?

the position of the part that was hit with an offset

This might work, I think you just need to add an additional offset.


In case that doesn’t work or you run into other issues, here’s mine:

local UserInputService = game:GetService("UserInputService")

local currentCamera = workspace.CurrentCamera

local PART = script.Parent
local GRIDSIZE = 2

UserInputService.InputChanged:Connect(function(input: InputObject, gameProcessedEvent: boolean)
	if gameProcessedEvent or input.UserInputType ~= Enum.UserInputType.MouseMovement then
		return
	end
	
	local inputPos: Vector3 = input.Position
	local ray = currentCamera:ScreenPointToRay(inputPos.X, inputPos.Y)
	
	local raycastResult = workspace:Raycast(ray.Origin, ray.Direction * 50)
	if not raycastResult or not raycastResult.Instance then
		return
	end
	
	local hitPart = raycastResult.Instance
	if not hitPart:IsA("BasePart") then
		return
	end
	
	local hitPos = raycastResult.Position
	local sizeOffset = PART.Size / 2 * raycastResult.Normal
	
	PART.Position = Vector3.new(
		math.round((hitPos.X + sizeOffset.X) / GRIDSIZE) * GRIDSIZE,
		math.round((hitPos.Y + sizeOffset.Y) / GRIDSIZE) * GRIDSIZE,
		math.round((hitPos.Z + sizeOffset.Z) / GRIDSIZE) * GRIDSIZE
	)
end)

I run into the same problem the first part placed is 1 stud above the ground while all the other parts i place ontop or to the side of it are perfect

Offset all parts 1 stud down then, or make the grid relative to the surface.

How would I make the grid relative to the surface? here is my current code:

local ReplicatedStorage = game:GetService("ReplicatedStorage")
local PlaceRemote = ReplicatedStorage.Remotes.Place
local PartsFolder = ReplicatedStorage.Parts

local GRIDSIZE = 2

PlaceRemote.OnServerEvent:Connect(function(player, partName, hitPos, normal, hitPart)
	local part = PartsFolder:FindFirstChild(partName)
	if not part or not hitPart then return end

	local PartClone = part:Clone()
	PartClone.Anchored = true
	PartClone.Parent = workspace

	local offset = normal * (PartClone.Size.Y / 2)
	local targetPos = hitPos + offset
	local sizeOffset = PartClone.Size / 2 * normal

	PartClone.Position = Vector3.new(
		math.round((hitPos.X + sizeOffset.X) / GRIDSIZE) * GRIDSIZE,
		math.round((hitPos.Y + sizeOffset.Y) / GRIDSIZE) * GRIDSIZE,
		math.round((hitPos.Z + sizeOffset.Z) / GRIDSIZE) * GRIDSIZE
	)
end)

here it does not change at all depending on the surface

Try hitPos.Y % GRIDSIZE perhaps?

I ended up using a different system for placing but thanks for the help!

This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.