Grid Building System Problem

Trying to fix a rounding issue with my grid placement system

Grid Rounding System isn’t rounding correctly

there is many grid placement system tutorials (all using the same principle)

but it isn’t being reliable, it works properly on some sides but does not work correctly on others, thus only working half the time

looking for some help on a fix, or another way to round

Code:
Full

local Player = game.Players.LocalPlayer

local Build_Storage = game:GetService("ReplicatedStorage"):WaitForChild("Buildables")
local Concrete_Block = Build_Storage:WaitForChild("Concrete")

local Placed_Blocks = game.Workspace:WaitForChild("Placed_Blocks")
local Ignore_Blocks = game.Workspace:WaitForChild("Ignore_Blocks")
local Base = game.Workspace:WaitForChild("Base")

local Mouse = Player:GetMouse()
Mouse.TargetFilter = Ignore_Blocks


function Snap(block)
	
	local posx = math.floor((Mouse.Hit.p.X / block.Size.X) + 0.5) * block.Size.X 
	local posy = math.floor((Mouse.Hit.p.Y / block.Size.Y) + 0.5) * block.Size.Y
	local posz = math.floor((Mouse.Hit.p.Z / block.Size.Z) + 0.5) * block.Size.Z
	

	return Vector3.new(posx, posy, posz)
	
end


function build()
	local conclone = Concrete_Block:Clone()
	conclone.CanCollide = false
	conclone.Transparency = .3
	conclone.Parent = Ignore_Blocks
	
	Mouse.Move:connect(function()
	wait(.02)
	conclone.Position = Snap(conclone)

	end)
	
	Mouse.Button1Down:connect(function()
	
	local conclonebuild = Concrete_Block:Clone()
	conclonebuild.Position = conclone.Position
	conclonebuild.Parent = Placed_Blocks

	end)
end

wait(5)

build()

Problem Code

function Snap(block)
	
	local posx = math.floor((Mouse.Hit.p.X / block.Size.X) + 0.5) * block.Size.X 
	local posy = math.floor((Mouse.Hit.p.Y / block.Size.Y) + 0.5) * block.Size.Y
	local posz = math.floor((Mouse.Hit.p.Z / block.Size.Z) + 0.5) * block.Size.Z
	

	return Vector3.new(posx, posy, posz)
	
end

keep in mind this is just prototype code until I get the rounding correct then I’m going to make it more functional

Thanks

3 Likes

Here is my hacky solution to fixing this.

Put an invisible, CanCollide false, Size = .1,.1,.1 brick where the mouse is every time you move it. The little extra offset usually lets the rounding functions work out right.

Edit: The same brick of-course not a new one.

1 Like

Don’t know if that would work as I am rounding with the parts size

unless im not understanding what you said properly?

I have to round by the parts size as im going to add more objects that are bigger than 5x5x5 eg 5x10x5 etc

1 Like

The problem is that when your mouse hits the face coming from a negative direction the code it will be rounded into the next “Section” of the grid. There is no easy way math wise to determine what direction the player is “meaning” so my hack little fix is literally to force in a little offset.

local Part = Instance.new("Part",game.Workspace);
Part.Size = Vector3.new(.1.1.1);
Part.Transpareny = 1;
Part.CanCollide = false;

while wait() do
    Part.CFrame = Mouse.Hit;
end

it didn’t work (I upped the size a bit it didnt work at .1 either)

Took a bit but I finally found a solution

I combined what I had with the solution of this post Block Placement System Help (Positioning the blocks relative to other parts?)

and it works perfectly

Code, It’s not the neatest so sorry about that

local Player = game.Players.LocalPlayer

local Build_Storage = game:GetService("ReplicatedStorage"):WaitForChild("Buildables")
local Concrete_Block = Build_Storage:WaitForChild("Concrete")

local Placed_Blocks = game.Workspace:WaitForChild("Placed_Blocks")
local Ignore_Blocks = game.Workspace:WaitForChild("Ignore_Blocks")
local Base = game.Workspace:WaitForChild("Base")

local Mouse = Player:GetMouse()
Mouse.TargetFilter = Ignore_Blocks

local target = nil
local pos = nil
local norm = nil

local MAX_PLACEMENT_DISTANCE = 2000

function doFakeMouseStuff()
	local ignoreList = {Ignore_Blocks}	--game.Workspace:WaitForChild("BaseStore"):GetChildren()
	local mouseRay = Mouse.UnitRay
	local newRay = Ray.new(mouseRay.Origin, mouseRay.Direction.unit * MAX_PLACEMENT_DISTANCE)
	target, pos, norm = workspace:FindPartOnRayWithIgnoreList(newRay, ignoreList)
end

game:GetService("RunService").RenderStepped:connect(function()
	doFakeMouseStuff()
end)

function round(vec, block)
	local posx = math.floor(vec.X / block.PrimaryPart.Size.X + 0.5) * block.PrimaryPart.Size.X 
	local posy = math.floor(vec.Y / block.PrimaryPart.Size.Y + 0.5) * block.PrimaryPart.Size.Y
	local posz = math.floor(vec.Z / block.PrimaryPart.Size.Z + 0.5) * block.PrimaryPart.Size.Z
	
	return Vector3.new(posx, posy, posz)
end
local item = Concrete_Block:Clone()
item.Parent = Ignore_Blocks
Mouse.Move:connect(function()
	if item and pos and norm then
		doFakeMouseStuff()	-- Just to be cetain that the data is up to date.
		local endPos = round(pos + (norm * (item.PrimaryPart.Size*.5)), item)
		item:SetPrimaryPartCFrame(CFrame.new(endPos))
	end
end)

Mouse.Button1Down:connect(function()
	local part = item:Clone()
	part:SetPrimaryPartCFrame(CFrame.new(item.PrimaryPart.Position))
	part.Name = 'block'
	part.Parent = workspace
	
end)

14 Likes

I don’t know much about these grid systems, but could you not just see which face your mouse is looking at, then position by Vector3.FromNormalId?

mouse.TargetFilter = newPart
local target = mouse.Target
local face = mouse.TargetSurface

newPart.Position = target.Position + (Vector3.FromNormalId(face) * newPart.Size) 

Or am I over-simplifying this?

I know this is from 2019 but thank you so much. I’ve been searching for a similar fix to my system which had trouble rounding up for hours.

1 Like