I mean something like BedWars or SkyWars where when you look in front of you, you can see a transparent block.
I made this for my game.
It’s a bit buggy but it does the job done.
Place a Local Script in a Tool.
Place a Normal script in the tool.
Place a Folder named “PartsFolder” in the workspace and place all the parts you want in the map.
Place a Folder named “PartsPreview” in the workspace for the prediction block.
Place a Remote event named “PlaceBlock” in the tool
This is the code for the Local Script:
local PlaceBlockEvent = script.Parent.PlaceBlock
local equipped = false
local uis = game:GetService("UserInputService")
local mouse = game.Players.LocalPlayer:GetMouse()
local character = game.Players.LocalPlayer.Character or game.Players.LocalPlayer.CharacterAdded:Wait()
local cam = workspace.CurrentCamera
local function findClosestPart(preview)
local lowestMagParts = {}
local currentPart = nil
local currentClosestDir = nil
local currentClsoestmag = nil
for _,v in pairs(game.Workspace.PartsFolder:GetDescendants()) do
if v:IsA("BasePart") then
local magnitude1 = (character.PrimaryPart.Position - v.Position).Magnitude
if magnitude1 <= 25 then
table.insert(lowestMagParts, v)
end
end
end
local lowestMagnitude = nil
for _,v in pairs(lowestMagParts) do
if v:IsA("BasePart") then
local mouse3DPos = character.PrimaryPart.Position + (mouse.Hit.Position - character.PrimaryPart.Position).Unit * (character.PrimaryPart.Position - v.Position).Magnitude
local mag = (v.Position - mouse3DPos).Magnitude
if not lowestMagnitude then
lowestMagnitude = mag
currentPart = v
continue
end
if mag < lowestMagnitude then
lowestMagnitude = mag
currentPart = v
end
end
end
local surfaceIDs = {
top = currentPart.Position + Vector3.new(0,25,0),
bottom = currentPart.Position - Vector3.new(0,25,0),
left = currentPart.Position - Vector3.new(25,0,0),
right = currentPart.Position + Vector3.new(25,0,0),
front = currentPart.Position - Vector3.new(0,0,25),
back = currentPart.Position + Vector3.new(0,0,25),
}
for surfaceId, pos in pairs(surfaceIDs) do
local mag = ((character.PrimaryPart.Position + (mouse.Hit.Position - character.PrimaryPart.Position).Unit * 25) - pos).Magnitude
if not currentClsoestmag then
currentClsoestmag = mag
currentClosestDir = surfaceId
continue
end
if mag < currentClsoestmag then
currentClsoestmag = mag
currentClosestDir = surfaceId
end
end
if currentClosestDir ~= nil then
table.clear(lowestMagParts)
return currentPart, currentClosestDir
end
end
local connection = nil
script.Parent.Equipped:Connect(function()
if equipped == false then
equipped = true
local clonePreview = Instance.new("Part")
clonePreview.Parent = game.Workspace:WaitForChild("PartsPreview")
clonePreview.Name = script.Parent.Parent.Name.."Preview"
clonePreview.Transparency = 1
clonePreview.Size = Vector3.new(3,3,3)
clonePreview.CanCollide = false
clonePreview.Anchored = true
local selection = Instance.new("SelectionBox", clonePreview)
selection.Visible = true
selection.Adornee = clonePreview
selection.LineThickness = 0.05
selection.Color3 = Color3.fromRGB(0,0,0)
for _,v in pairs(game.Workspace.PartsPreview:GetChildren()) do
if v ~= clonePreview then
v:Destroy()
end
end
mouse.TargetFilter = clonePreview
task.defer(function()
while wait() do
if equipped == true then
local mouseX,mouseY,mouseZ = mouse.Hit.X, mouse.Hit.Y, mouse.Hit.Z
local mouseTarget = mouse.TargetSurface
if mouse.Target ~= nil then
if mouseTarget == Enum.NormalId.Top then
clonePreview.CFrame = (CFrame.new(mouse.Target.Position + Vector3.new(0,3, 0))) --- the 3 is the size of the block
elseif mouseTarget == Enum.NormalId.Bottom then
clonePreview.CFrame = (CFrame.new(mouse.Target.Position - Vector3.new(0,3, 0))) --- the 3 is the size of the block
elseif mouseTarget == Enum.NormalId.Left then
clonePreview.CFrame = (CFrame.new(mouse.Target.Position - Vector3.new(3, 0,0))) --- the 3 is the size of the block
elseif mouseTarget == Enum.NormalId.Right then
clonePreview.CFrame = (CFrame.new(mouse.Target.Position + Vector3.new(3,0, 0))) --- the 3 is the size of the block
elseif mouseTarget == Enum.NormalId.Front then
clonePreview.CFrame = (CFrame.new(mouse.Target.Position - Vector3.new(0,0, 3))) --- the 3 is the size of the block
elseif mouseTarget == Enum.NormalId.Back then
clonePreview.CFrame = (CFrame.new(mouse.Target.Position + Vector3.new(0,0, 3))) --- the 3 is the size of the block
end
elseif mouse.Target == nil then
local closestPart, direction = findClosestPart(clonePreview)
if tostring(direction) == "top" then
clonePreview.CFrame = (CFrame.new(closestPart.Position + Vector3.new(0,3, 0))) --- the 3 is the size of the block
elseif tostring(direction) == "bottom" then
clonePreview.CFrame = (CFrame.new(closestPart.Position - Vector3.new(0,3, 0))) --- the 3 is the size of the block
elseif tostring(direction) == "left" then
clonePreview.CFrame = (CFrame.new(closestPart.Position - Vector3.new(3,0,0))) --- the 3 is the size of the block
elseif tostring(direction) == "right" then
clonePreview.CFrame = (CFrame.new(closestPart.Position + Vector3.new(3,0, 0))) --- the 3 is the size of the block
elseif tostring(direction) == "front" then
clonePreview.CFrame = (CFrame.new(closestPart.Position - Vector3.new(0,0, 3))) --- the 3 is the size of the block
elseif tostring(direction) == "back" then
clonePreview.CFrame = (CFrame.new(closestPart.Position + Vector3.new(0,0, 3))) --- the 3 is the size of the block
end
closestPart = nil
direction = nil
end
end
end
end)
connection = mouse.Button1Down:Connect(function()
if equipped == true then
for _,v in pairs(game.Workspace:WaitForChild("PartsFolder"):GetDescendants()) do
if v:IsA("BasePart") then
if clonePreview.Position == v.Position then
return
end
end
end
local primaryPart = clonePreview.CFrame
PlaceBlockEvent:FireServer(primaryPart)
end
end)
end
end)
script.Parent.Unequipped:Connect(function()
if equipped == true then
equipped = false
if workspace.PartsPreview:FindFirstChild(script.Parent.Parent.Name.."Preview") then
local preview = workspace.PartsPreview:FindFirstChild(script.Parent.Parent.Name.."Preview")
preview:Destroy()
end
end
connection:Disconnect()
connection = nil
end)
Here is the code for the Normal script:
local event = script.Parent.PlaceBlock
local part = game.ReplicatedStorage:WaitForChild("Wood Plank") ---- name of the part in the replicated storage you want to clone for the block placement system
event.OnServerEvent:Connect(function(plr, pos)
local Clone = part:Clone()
Clone.Parent = game.Workspace:WaitForChild("PartsFolder")
Clone.CFrame = pos
end)
This is my first time making a reply so let me know if you have problems!
Also here’s a video clip of the tool. It’s a bit lag since I’m on a laptop
robloxapp-20220302-2138143.wmv (3.4 MB)
Thank you so much for your help! I’ve been looking around for something like this.
However, it does not seem to work. There is currently nothing in the output.
I’ve followed your directions and re-checked the script…
EDIT: Fixed the problem, i didnt have a handle lol
However, for some odd reason, I get this error.
Here’s where it’s causing the issue.
It seems to be happening when I take the mouse off the map.
Thanks anyways, you are a lifesaver!
Add this if so that the error will go away.
if currentPart ~= nil then
local surfaceIDs = {
top = currentPart.Position + Vector3.new(0,25,0),
bottom = currentPart.Position - Vector3.new(0,25,0),
left = currentPart.Position - Vector3.new(25,0,0),
right = currentPart.Position + Vector3.new(25,0,0),
front = currentPart.Position - Vector3.new(0,0,25),
back = currentPart.Position + Vector3.new(0,0,25),
}
for surfaceId, pos in pairs(surfaceIDs) do
local mag = ((character.PrimaryPart.Position + (mouse.Hit.Position - character.PrimaryPart.Position).Unit * 25) - pos).Magnitude
if not currentClsoestmag then
currentClsoestmag = mag
currentClosestDir = surfaceId
continue
end
if mag < currentClsoestmag then
currentClsoestmag = mag
currentClosestDir = surfaceId
end
end
if currentClosestDir ~= nil then
table.clear(lowestMagParts)
return currentPart, currentClosestDir
end
end
Alright! I’ll see if it works once I get back.
i have a problem with the first line
of the local script
Blockquote
Are there any errors? If you’re talking about this line:
1 | local PlaceBlockEvent = script.Parent.PlaceBlock
A remote event is needed inside the tool.
i do that but its not working its just the preview that does not destroy
I will work on a solution. Thanks for informing me!
ok thx bruh this thing it saying i need characters
hey did you find a solution for the fix
Hey nvm i found the problem on the script it was so easy