Block building system problem

I made a script to build blocks, but I only did the preview, but it doesn’t stick to the wall, for example:
CAN SOMEONE HELP ME

Code:

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

local player = Players.LocalPlayer
local mouse = player:GetMouse()

local GRID_SIZE = 2

local previewBlock = Instance.new("Part")
previewBlock.Name = "PreviewBlock"
previewBlock.TopSurface = Enum.SurfaceType.Smooth
previewBlock.BottomSurface = Enum.SurfaceType.Smooth
previewBlock.Transparency = 0.5
previewBlock.CanCollide = false
previewBlock.CanTouch = false
previewBlock.CanQuery = false
previewBlock.AudioCanCollide = false
previewBlock.CastShadow = false
previewBlock.Size = Vector3.new(GRID_SIZE, GRID_SIZE, GRID_SIZE)
previewBlock.Anchored = true
previewBlock.Parent = Workspace

local vector3 = Vector3.new
local floor = math.floor

local function snapToGrid(position: Vector3)
	return vector3(
		floor(position.X / GRID_SIZE + 0.5) * GRID_SIZE,
		floor(position.Y / GRID_SIZE + 0.5) * GRID_SIZE,
		floor(position.Z / GRID_SIZE + 0.5) * GRID_SIZE
	)
end

mouse.Move:Connect(function()
	if not mouse.Hit then return end
	local snappedPosition = snapToGrid(mouse.Hit.Position)
	previewBlock.Position = snappedPosition
end)

(Sorry for my rusty English, I’m using Google Translate)
Thankss!

1 Like

Desktop 2025.10.16 - 06.33.12.04
serverscriptservice:

local repl = game:GetService('ReplicatedStorage')

local event_comm = Instance.new('RemoteEvent')
event_comm.Name = 'event_comm'
event_comm.Parent = repl

local CHEX = 255
local GRID_SIZE = 2
local bblock = nil
local bblock_reg = {}
local BLOCK_COLOR = Color3.fromRGB(1*CHEX, 0*CHEX, 0*CHEX)
local SIDE_C, SIDE_L, SIDE_R, SIDE_F, SIDE_B, SIDE_TOP, SIDE_BTM = 'center', 'left', 'right', 'front', 'back', 'top', 'btm'
function listen()
	event_comm.OnServerEvent:Connect(function(from, props)
		if (props['etype'] == 'place') then
			if (bblock == nil) then
				bblock = create_dummy(Vector3.new(GRID_SIZE, GRID_SIZE, GRID_SIZE), BLOCK_COLOR)
				reposition_pivot(bblock, SIDE_B)
			end
			bblock:PivotTo(CFrame.new(props['pos'], props['pos'] + props['nrm'] * -1))
		elseif (props['etype'] == 'mount') then
			local bblock_inst = bblock:Clone()
			bblock_inst:PivotTo(CFrame.new(props['pos'], props['pos'] + props['nrm'] * -1))
			bblock_inst.Parent = bblock.Parent
			table.insert(bblock_reg, bblock_inst)
		elseif (props['etype'] == 'remove') then
			if (bblock ~= nil) then
				bblock:Destroy()
				bblock = nil
			end
		end
	end)
end

function create_wall()
	local w = create_dummy(Vector3.new(8,8,4), Color3.fromRGB(1*CHEX, 1*CHEX, 1*CHEX))
	local ext_cf, ext_sz = w:GetBoundingBox()
	w:PivotTo(CFrame.new(0,ext_sz.Y/2,-5))
	w.Name = 'wall'
	w.Part.Shape = Enum.PartType.Cylinder
	w.Part.Transparency = 0
	w.Parent = workspace
end

function create_dummy(size_v, color)
	local m = Instance.new('Model')
	m.Parent = workspace
	local previewBlock = Instance.new('Part')
	previewBlock.Shape = Enum.PartType.Block
	previewBlock.CanCollide = false
	previewBlock.CanTouch = true
	previewBlock.CanQuery = true
	previewBlock.Material = Enum.Material.SmoothPlastic
	previewBlock.Transparency = 0.5
	previewBlock.CastShadow = false
	previewBlock.Color = color
	previewBlock.Size = size_v
	previewBlock.Anchored = true
	previewBlock.Parent = m
	return m
end

function weld(p0, p1)
	local w = Instance.new('Weld')
	w.Name = 'weld'
	w.Part0 = p0
	w.Part1 = p1
	w.Parent = p0
	w.Enabled = true
	return w
end

function place_onextents(client, p, side)
	local cf, ext_p, size_v = nil, nil, nil
	cf, size_v = client.ExtentsCFrame, client.ExtentsSize
	_, ext_p = p.ExtentsCFrame, p.ExtentsSize
	if side == SIDE_C then
		p:PivotTo(cf)
	elseif side == SIDE_L then
		p:PivotTo(cf + cf.RightVector * -size_v.X/2 + cf.RightVector * ext_p.X/2)
	elseif side == SIDE_R then
		p:PivotTo(cf + cf.RightVector * size_v.X/2 + cf.RightVector * -ext_p.X/2)
	elseif side == SIDE_TOP then
		p:PivotTo(cf + cf.UpVector * size_v.Y/2 + cf.UpVector * -ext_p.Y/2)
	elseif side == SIDE_BTM then
		p:PivotTo(cf + cf.UpVector * -size_v.Y/2 + cf.UpVector * ext_p.Y/2)
	elseif side == SIDE_F then
		p:PivotTo(cf + cf.LookVector * -size_v.Z/2 + cf.LookVector * ext_p.Z/2)
	elseif side == SIDE_B then
		p:PivotTo(cf + cf.LookVector * size_v.Z/2 + cf.LookVector * -ext_p.Z/2)
	end
end

function reposition_pivot(client, side)
	local pivot = create_dummy(Vector3.new(0.1, 0.1, 0.1), Color3.fromRGB(0*CHEX, 1*CHEX, 0*CHEX))
	weld(client.Part, pivot.Part)
	client.PrimaryPart = pivot.Part
	place_onextents(client.Part, client.PrimaryPart, side)
	pivot.Parent = client
end

create_wall()
listen()

starterplayerscripts:

local repl = game:GetService('ReplicatedStorage')
local plr_svc = game:GetService('Players')
local starter = game:GetService('StarterPlayer')
local sgui = game:GetService('StarterGui')
local uis = game:GetService('UserInputService')

local event_comm = repl.event_comm

local plr = plr_svc.LocalPlayer
local ch = plr.Character or plr.CharacterAdded:Wait()
local hum = ch:WaitForChild('Humanoid')
plr.CharacterAdded:Connect(function(character)
	ch = character
	hum = ch:WaitForChild('Humanoid')
end)
local pgui = plr:WaitForChild('PlayerGui')
local cam = workspace.CurrentCamera

WAITTIME = 1.000
function setup()
	local co = coroutine.create(function()	
		if not game:IsLoaded() then
			game.Loaded:Wait()
		end
	end)
	coroutine.resume(co)
end
task.wait(WAITTIME)
setup()

local ray_res:RaycastResult = nil
local rcast_par = RaycastParams.new()
rcast_par.FilterDescendantsInstances = {workspace.wall}
rcast_par.FilterType = Enum.RaycastFilterType.Include
local mmov_conn = nil
local lmb_conn = nil
local flag_dbn = nil
function track_mouse(props)
	mmov_conn = uis.InputChanged:Connect(function(input)
		if input.UserInputType == Enum.UserInputType.MouseMovement and flag_dbn == nil then
			debounce()
			ray_res = get_raypt(input)
			if ray_res ~= nil then
				place_bblock(ray_res)
			else
				remove_bblock()
			end
		end
	end)
	lmb_conn = uis.InputBegan:Connect(function(input)
		if ray_res ~= nil and input.UserInputType == Enum.UserInputType.MouseButton1 then
			mount_bblock(ray_res)
		end
	end)
end

local DBN = 0.050
dbn_fun = function()
	flag_dbn = true
	task.wait(DBN)
	flag_dbn = nil
end

function debounce()
	local co = coroutine.create(dbn_fun)
	coroutine.resume(co)
end

local RAY_LIM = 128
local MTRK_RANGE = 32
function get_raypt(input)
	local ray = cam:ScreenPointToRay(input.Position.X, input.Position.Y, 0)
	local isect_list = workspace:Raycast(ray.Origin, ray.Direction * RAY_LIM, rcast_par)
	if isect_list ~= nil and (isect_list.Position - ch.PrimaryPart.Position).Magnitude < MTRK_RANGE then
		return isect_list
	else
		return nil
	end
end

function place_bblock(raycast)
	event_comm:FireServer({
		['etype'] = 'place',
		['pos'] = raycast.Position,
		['nrm'] = raycast.Normal
	})
end

function remove_bblock(raycast)
	event_comm:FireServer({
		['etype'] = 'remove',
		['pos'] = nil,
		['nrm'] = nil
	})
end

function mount_bblock(raycast)
	event_comm:FireServer({
		['etype'] = 'mount',
		['pos'] = raycast.Position,
		['nrm'] = raycast.Normal
	})
end

track_mouse()
1 Like

Can you explain theses codes? No offense but this looks like a code decoded by a broken decoder

for it to stick to walls, you need to check Normals of the object ur mouse is, if its on lets say NormalId.Left then add vec3 1 0 0 or etc

I wrote this code on my phone, and if there are any syntax errors, please correct them

local UserInputService = game:GetService("UserInputService")
local Camera = workspace.CurrentCamera

local MouseMovement = Enum.UserInputType.MouseMovement

UserInputService.InputBegan:Connect(function(io)
  if io.UserInputType ~= MouseMovement then return end

  local ray = Camera:ScreenPointToRay(
    io.Position.X, io.Position.Y
  )
  local rayResult = workspace:RayCast(
    ray.Origin,
    ray.Direction * 1e4
  )

  if not rayResult then return end

  local position = rayResult.Position
     + rayResult.Normal * prewiewBlock.Size.Z/2

  prewiewBlock.CFrame = CFrame.lookAlong(position, rayResult.Normal)
end

thanks for the reply! but the problem has already been resolved

I had forgotten to tag resolved

thats good too btw´´´´´´´´´´´´´´´

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