For the last while now, I have been working on a building system for my game. I used a tutorial to make the basis for it. As the blocks I am placing with are 4x4, I want to snap the placing position of the block to 4 studs. I have tried to do this but every time it has glitched strangely. The map you place on is randomly generated.
What is happening is that tiles that have been generated randomly disappear where my mouse cursor is.
How can I fix this?
Here is my generation code in a server script:
local partspawn = 1950 local partcount = math.round((partspawn / 10) * 12) local mapgenerateplace = Vector3.new((partspawn / 2) - partspawn, 0, (partspawn / 2) - partspawn) local wk,pl = game:GetService("Workspace"),game:GetService("Players") function spawnmap() local db = false local folder = Instance.new("Folder") folder.Name = "Map" folder.Parent = wk for i = 1,partcount,1 do local newpart = Instance.new("Part",folder) local height = math.round((math.random(10, 40) / 8)) * 8 local rad = math.round(math.random(1, 8)) if rad == 1 then newpart.Color = Color3.fromRGB(100, 100, 106) newpart.Material = Enum.Material.Slate newpart.Name = "Stone" newpart.Size = Vector3.new(40, height, 40) else newpart.Color = Color3.fromRGB(40, 127, math.round(math.random(70, 110))) newpart.Material = Enum.Material.Grass newpart.Name = "Grass" newpart.Size = Vector3.new(40, height, 40) end newpart.Position,newpart.Anchored = Vector3.new(mapgenerateplace.X + math.round(math.random(1, partspawn) / 40) * 40, math.round(mapgenerateplace.Y), mapgenerateplace.Z + math.round(math.random(1, partspawn) / 40) * 40),true if newpart then local clone = game.ReplicatedStorage.MapObjects.Tree:Clone() clone.Parent = workspace if newpart.Touched then if db == false then local parts = newpart:GetTouchingParts() for i, v in pairs(parts) do if v.Position == newpart.Position then newpart:Destroy() clone:Destroy() end end end end if math.random(0, 4) == 1 then if clone:FindFirstChild("Trunk") then clone.Trunk.Position = Vector3.new(newpart.Position.X, newpart.Position.Y + height / 2, newpart.Position.Z) clone.Leaves.Position = Vector3.new(clone.Trunk.Position.X, clone.Trunk.Position.Y + 10.5, clone.Trunk.Position.Z) else clone:Destroy() end else clone:Destroy() end end end db = false end spawnmap()
Here is my placement code in a local script:
local replicatedStorage = game:GetService("ReplicatedStorage") local UIS = game:GetService("UserInputService") local runService = game:GetService("RunService") local placeStructure = replicatedStorage:WaitForChild("PlaceStructure") local structureFrame = script.Parent.BuildFrame local structures = replicatedStorage:WaitForChild("Structures") local player = game.Players.LocalPlayer local char = player.Character or player.Character:Wait() local humanoidRootPart = char:WaitForChild("HumanoidRootPart") local mouse = player:GetMouse() local yBuildingOffset = 0 local maxPlacingDistance = 50 local rKeyIsPressed = false local placingStructure = false for _, structureButton in pairs(structureFrame:GetChildren()) do if structureButton:IsA("TextButton") then structureButton.MouseButton1Up:Connect(function() structureFrame.Visible = false structureFrame.Parent.Delete.Visible = false script.Parent.Instructions1.Visible = true script.Parent.Instructions2.Visible = true local yOrientation = 0 local goodToPlace = false local placedStructure if placingStructure == false then placingStructure = true local clientStructure = structures:FindFirstChild(structureButton.Name):Clone() clientStructure.BrickColor = BrickColor.new("Forest green") clientStructure.Material = "Neon" clientStructure.CanCollide = false clientStructure.Parent = workspace yBuildingOffset = clientStructure.Size.Y / 2 local startingCFrame = CFrame.new(0, 0, 0) clientStructure.CFrame = humanoidRootPart.CFrame:ToWorldSpace(startingCFrame) runService.RenderStepped:Connect(function() local mouseRay = mouse.UnitRay local castRay = Ray.new(mouseRay.Origin, mouseRay.Direction * 1000) local ignoreList = {clientStructure, char} local hit, position = workspace:FindPartOnRayWithIgnoreList(castRay, ignoreList) if hit and (not hit:IsA("Terrain") or not hit.Name:lower() == "terrain") and (humanoidRootPart.Position - clientStructure.Position).Magnitude < maxPlacingDistance then goodToPlace = true clientStructure.BrickColor = BrickColor.new("Forest green") else goodToPlace = false clientStructure.BrickColor = BrickColor.new("Crimson") end local newAnglesCFrame = CFrame.Angles(0, math.rad(yOrientation), 0) local newCFrame = CFrame.new(position.X, position.Y + yBuildingOffset, position.Z) local cframeTable = table.pack(newCFrame:GetComponents()) --Set the Position for i, v in pairs(cframeTable) do --Edit: cframeTable[i] = math.round(v / 4) * 4 end local roundedCFrame = CFrame.new(table.unpack(cframeTable)) clientStructure.CFrame = roundedCFrame * newAnglesCFrame --Positon Set end) UIS.InputBegan:Connect(function(input) if input.KeyCode == Enum.KeyCode.R then rKeyIsPressed = true local rotationSpeed = 5 while rKeyIsPressed do wait() if placingStructure == true then yOrientation = yOrientation + math.deg(0.785398) wait(0.25) end end end end) UIS.InputEnded:Connect(function(input) if input.KeyCode == Enum.KeyCode.R then rKeyIsPressed = false end end) local inputConnection inputConnection = UIS.InputBegan:Connect(function(input) if input.UserInputType == Enum.UserInputType.MouseButton1 and placingStructure == true then if goodToPlace then local structureCFrame = clientStructure.CFrame placedStructure = placeStructure:InvokeServer(clientStructure.Name, structureCFrame) if placedStructure then placingStructure = false clientStructure:Destroy() structureFrame.Visible = true script.Parent.Instructions1.Visible = false script.Parent.Instructions2.Visible = false inputConnection:Disconnect() end end end end) UIS.InputBegan:Connect(function(input) if input.KeyCode == Enum.KeyCode.X then placingStructure = false clientStructure:Destroy() structureFrame.Visible = true script.Parent.Instructions1.Visible = false script.Parent.Instructions2.Visible = false inputConnection:Disconnect() end end) end end) end end