Placing blocks only works on some sides

I’ve created a building system that places a 4x4x4 block on a 4x4 grid, while it works nicely, it doesn’t let me place blocks on certain sides of the blocks.

https://gyazo.com/bd99a1187ba638abebbb96e38ae513ff

I’ve tried rewriting the script multiple times to see if I could get a different outcome but I keep getting the same outcome.

This is my main building script.

local ServerStorage = game:GetService("ServerStorage")
local Players = game:GetService("Players")
local Workspace = game:GetService("Workspace")
local ReplicatedStorage = game:GetService("ReplicatedStorage")

local BlockFolder = ServerStorage:WaitForChild("Blocks")
local BlockTemplate = BlockFolder:WaitForChild("Block")
local SoundFolder = ServerStorage:WaitForChild("Sounds")
local PlaceSound = SoundFolder:WaitForChild("Placed")
local GridSize = 4

local playerBlocks = {}

local function hasBuildTool(player)
	local character = player.Character
	if character then
		local tool = character:FindFirstChild("Build")
		return tool and tool:IsA("Tool")
	end
	return false
end

local function hasDestroyTool(player)
	local character = player.Character
	if character then
		local tool = character:FindFirstChild("Delete")
		return tool and tool:IsA("Tool")
	end
	return false
end

local function getGridPosition(position)
	local x = math.floor(position.X / GridSize + 0.5) * GridSize
	local y = math.floor(position.Y / GridSize + 0.5) * GridSize
	local z = math.floor(position.Z / GridSize + 0.5) * GridSize
	return Vector3.new(x, y, z)
end

local function placeBlock(player, mousePosition, selectedColor, selectedMaterial)
	if not hasBuildTool(player) then return end

	local color = selectedColor or Color3.new(1, 1, 1)
	local material = selectedMaterial or "Plastic"

	local gridPosition = getGridPosition(mousePosition)

	local existingBlock = false
	for _, block in pairs(Workspace:WaitForChild("Blocks"):GetChildren()) do
		if (block.Position - gridPosition).magnitude < GridSize then
			existingBlock = true
			break
		end
	end

	if existingBlock then
		return
	end

	local newBlock = BlockTemplate:Clone()
	newBlock.Position = gridPosition
	newBlock.Parent = Workspace:WaitForChild("Blocks")

	newBlock.Color = color

	if Enum.Material[material] then
		newBlock.Material = Enum.Material[material]
	else
		newBlock.Material = Enum.Material.Plastic
	end

	newBlock:SetAttribute("Creator", player.UserId)

	if not playerBlocks[player] then
		playerBlocks[player] = {}
	end
	table.insert(playerBlocks[player], newBlock)

	local placeSound = PlaceSound:Clone()
	placeSound.Parent = newBlock
	placeSound:Play()

	placeSound.Ended:Connect(function()
		placeSound:Destroy()
	end)
end

local function deleteBlock(player, mousePosition)
	if not hasDestroyTool(player) then return end

	local gridPosition = getGridPosition(mousePosition)

	local ray = Ray.new(gridPosition + Vector3.new(0, 5, 0), Vector3.new(0, -10, 0))
	local hitPart = Workspace:FindPartOnRay(ray, player.Character)

	if hitPart and hitPart.Parent == Workspace:WaitForChild("Blocks") then
		local creatorId = hitPart:GetAttribute("Creator")
		if creatorId == player.UserId then
			hitPart:Destroy()
		end
	end
end

Players.PlayerRemoving:Connect(function(player)
	if playerBlocks[player] then
		for _, block in pairs(playerBlocks[player]) do
			block:Destroy()
		end
		playerBlocks[player] = nil
	end
end)

game.ReplicatedStorage.Events.PlaceBlock.OnServerEvent:Connect(function(player, mousePosition, selectedColor, selectedMaterial)
	placeBlock(player, mousePosition, selectedColor, selectedMaterial)
end)

game.ReplicatedStorage.Events.DeleteBlock.OnServerEvent:Connect(function(player, mousePosition)
	deleteBlock(player, mousePosition)
end)

ReplicatedStorage.Events.SetColor.OnServerEvent:Connect(function(player, newColor)
	local selectedColor = player:FindFirstChild("SelectedColor")
	if selectedColor then
		selectedColor.Value = newColor
	end
end)

ReplicatedStorage.Events.SetMaterial.OnServerEvent:Connect(function(player, newMaterial)
	local selectedMaterial = player:FindFirstChild("SelectedMaterial")
	if selectedMaterial then
		selectedMaterial.Value = newMaterial
	end
end)

Please let me know what I should change, I’ve been struggling at this and block placement has not been my number one thing.

Whats the reason for the sides you cannot place on being red?

I don’t know, thats the issue.

Oh I see what you mean, I labeled those red because those are the sides I cannot place on, so it’s really for debugging.

I would recommend pulling the mouse position a little bit closer to their camera, that way it won’t ever intersect. You would need to do it from the client side. I’m assuming you currently just use Mouse.Hit.Position, so add on the Camera.ZVector0.1 to the position. if you wanted to be more precise, you could create a new CFrame at the mouse position, looking at the camera position, and add on 0.1that look vector to the mouse position. Keep in mind the ZVector is like the back vector, look vector is the negated form.

1 Like

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