Block Placement Only Snapping On 2 Sides

I have been trying to get block placement to work, but it won’t snap on some sides. It only snaps on two sides of the block.

Video of the issue:

local Player = game:GetService("Players").LocalPlayer
local PlayerMouse = Player:GetMouse()

local Stud = 3
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local Block = ReplicatedStorage:WaitForChild("DefaultBlock")

local DisplayBlock = Block:Clone()
DisplayBlock.Parent = workspace
DisplayBlock.Transparency = 0.5
PlayerMouse.TargetFilter = DisplayBlock

local function ShowBlock()
	local MousePosition = PlayerMouse.Hit.Position
	local BlockPosition = Vector3.new(0, Block.Size.Y / 2, 0)

	BlockPosition += MousePosition

	local XPos = math.round(BlockPosition.X / Stud) * Stud
	local YPos = math.round(BlockPosition.Y / Stud) * Stud
	local ZPos = math.round(BlockPosition.Z / Stud) * Stud

	BlockPosition = Vector3.new(XPos, YPos, ZPos)
	DisplayBlock.Position = BlockPosition
end

local function PlaceBlock()
	local PlacingSound = script.Parent:WaitForChild("Placing")
	PlacingSound:Play()

	local NewBlock = Block:Clone()
	NewBlock.Position = DisplayBlock.Position
	NewBlock.Parent = workspace
end

PlayerMouse.Move:Connect(ShowBlock)
PlayerMouse.Button1Down:Connect(PlaceBlock)

Can anybody help me with this?

The problem is that your display block is inside the actual pre-existing block. You can see this if you add a highlight instance to the display block.

A way to fix this would be to move the hit vector closer to the camera.

local function ShowBlock()
	local MousePosition = PlayerMouse.Hit.Position
	local unitVector = (workspace.CurrentCamera.CFrame.Position - MousePosition).Unit
	MousePosition += unitVector * 0.1 -- I've used 0.1 but you can set it to any amount you see fit
	-- By adding this vector to the mouse position vector, you've moved the vector 0.1 stud closer to the camera

	local BlockPosition = Vector3.new(0, Block.Size.Y / 2, 0)

	BlockPosition += MousePosition

	local XPos = math.round(BlockPosition.X / Stud) * Stud
	local YPos = math.round(BlockPosition.Y / Stud) * Stud
	local ZPos = math.round(BlockPosition.Z / Stud) * Stud

	BlockPosition = Vector3.new(XPos, YPos, ZPos)
	DisplayBlock.Position = BlockPosition
end

Hope this helped.

local unitVector = (workspace.CurrentCamera.CFrame.Position - MousePosition).Unit

Could you explain this one line please? It fixed the block placement, but I don’t really understand it.

I’m not so sure about using math.round. It has consistency issues because it rounds towards 0, while math.floor and floor division always rounds towards one direction (negative infinity). You code can change behavior depending on which quadrant of the world it is working with.

This should be a better approach and I’ve condensed it all into a single line:

BlockPosition = (Block.Position/Stud + Vector3.one*.5)//1 * Stud
1 Like

Say you have Vector A (mouse hit vector) and Vector B (camera position). To move A to B you need the vector AB which is given by B - A. We can get the unit vector of AB by using .Unit which just makes the magnitude of AB one.

Then you can add the vector AB to the original vector A, which moves the vector towards B by one stud (since the magnitude is one). If you wanted to move more or less than a stud you can multiply the Unit vector by some value (in my example I just used 0.1).

And like @Prototrode said, you might want to consider flooring your snapping calculations to avoid unwanted behaviour.

Ah okay thanks, that makes sense