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

3 comments

0

Do they reappear when your mouse cursor goes off of it?

0

Yes, this is confusing me a little as 3 tiles all around my mouse disappear at once.

0

If I just use math.round(v) it works perfectly but when I do math.round(v / 4) * 4 it stops working.