I am looking for some reedback and help fo the following. This script works perfectly fine, but I am trying to implement a grid into the placement system. I would like it to be so when a player moves their cursor, blocks snap to a 1 stud by 1 stud grid in order to make it easy align items. At the moment, there is no grid what so ever so it is difficult to place walls beside each other.
Script: (localscript)
wait(2)
local event = game.ReplicatedStorage.PlacementEvent
local Objects = game.ReplicatedStorage:WaitForChild("ObjectFolder")
local plr = game.Players.LocalPlayer
local char = plr.Character or plr.CharacterAdded:Wait()
local mouse = plr:GetMouse()
local frame = script.Parent:WaitForChild("Frame")
local textBox = script.Parent:WaitForChild("Frame").SizeBox
local ColorBox = script.Parent:WaitForChild("Frame").ColorBox
local MaterialBox = script.Parent:WaitForChild("Frame").MaterialBox
local uis = game:GetService("UserInputService")
local rs = game:GetService("RunService")
local PlacingObject = false
local RotatingObject = false
local FlippingObject = false
for i,v in pairs(frame:GetChildren()) do
if v:IsA("GuiButton") then
v.MouseButton1Click:Connect(function()
if PlacingObject == false then
PlacingObject = true
frame.Visible = false
local RotationAmount = 0
local FlippingAmount = 0
local PreviewObject = Objects:FindFirstChild(v.Name):Clone()
PreviewObject.Parent = game.Workspace
for a,b in pairs(PreviewObject:GetDescendants()) do
if b:IsA("BasePart") then
if b.Name == "MainPart" then
b.CanCollide = false
else
if b.Parent.Name == "Ball" then
b.Transparency = 1
b.CanCollide = false
else
b.Transparency = 0.5
b.CanCollide = false
end
end
end
end
uis.InputBegan:Connect(function(input)
if input.KeyCode == Enum.KeyCode.R then
RotatingObject = true
while RotatingObject == true do
wait()
RotationAmount += 2
end
end
if input.KeyCode == Enum.KeyCode.T then
FlippingObject = true
while RotatingObject == true do
wait()
FlippingAmount += 2
end
end
end)
uis.InputEnded:Connect(function(input)
if input.KeyCode == Enum.KeyCode.R then
RotatingObject = false
end
if input.KeyCode == Enum.KeyCode.T then
FlippingObject = false
end
end)
rs.RenderStepped:Connect(function()
if true == true then --this is where grid stuff will go
if PlacingObject == true then
mouse.TargetFilter = PreviewObject
if PreviewObject:FindFirstChild("MainPart") then
local objCFrame = CFrame.new(mouse.Hit.Position.X,mouse.Hit.Position.Y + PreviewObject.PrimaryPart.Size.Y / 2,mouse.Hit.Position.Z)
local objAngles = CFrame.Angles(0,math.rad(RotationAmount),math.rad(FlippingAmount))
PreviewObject:SetPrimaryPartCFrame(objCFrame * objAngles)
local SizeValues = textBox.Text:split(", ")
if #SizeValues == 3 then
PreviewObject.PrimaryPart.Size = Vector3.new(SizeValues[1],SizeValues[2],SizeValues[3])
end
local ColorValues = ColorBox.Text:split(", ")
if #ColorValues == 3 then
PreviewObject.PrimaryPart.Color = Color3.fromRGB(ColorValues[1],ColorValues[3],ColorValues[3])
end
mouse.Button1Up:Connect(function()
if PlacingObject == true then
PlacingObject = false
if #SizeValues == 3 then
if #ColorValues == 3 then
event:FireServer(PreviewObject.Name,PreviewObject.PrimaryPart.CFrame,SizeValues[1],SizeValues[2],SizeValues[3],ColorValues[1],ColorValues[2],ColorValues[3],MaterialBox.Text)
else
event:FireServer(PreviewObject.Name,PreviewObject.PrimaryPart.CFrame,SizeValues[1],SizeValues[2],SizeValues[3])
end
else
event:FireServer(PreviewObject.Name,PreviewObject.PrimaryPart.CFrame,MaterialBox.Text)
end
frame.Visible = true
PreviewObject:Destroy()
end
end)
end
end
end
end)
end
end)
end
end
There is also a serverscript, but let me know if that would help, although I think the grid logic would be placed in here.
local Part = Instance.new("Part")
Part.Anchored = true
Part.Parent = workspace
local Players = game:GetService("Players")
local Player = Players.LocalPlayer
local Mouse = Player:GetMouse()
Mouse.TargetFilter = Part
local GridOffset = 10
local function GetCoordinate(Position)
return math.round(Position) - (math.round(Position) % GridOffset)
end
Mouse.Move:Connect(function()
local X, Y, Z = GetCoordinate(Mouse.Hit.Position.X), Mouse.Hit.Position.Y + Part.Size.Y/2, GetCoordinate(Mouse.Hit.Position.Z)
Part.Position = Vector3.new(X, Y, Z)
end)
Here’s a script which moves a BasePart instance along a grid locked to every n studs, “n” in this case is any number value stored inside the variable named “GridOffset”.
The grid snapping systems that @Apicphis and @Forummer suggested are pretty good, but there are two things I would warn you about when using these systems:
1.) These systems work best for objects that are uniform sizes. (Like in a block game, having all blocks 4x4x4, for instance). Objects that overflow into multiple grid units can cause weird intersections with nearby objects. You can make a simple intersection test with :GetTouchingParts() to help alleviate this problem.
2.) Be warned about weird orientations on objects (like let’s say vector3.new(42.114,38.189,86.130) because they could potentially mess with the grid system with weird intersections and such too. :GetTouchingParts() may help with this too.
I just want a simple grid system that i can set an offset for, for example 4x4 grid spaces in order to make it super easy to align blocks, and other objects which would be in the size of the gridoffset. I am not sure how to implement the GridOffset GetCooridinates function that was posted above, so any help from anyone would be greatly appreciated.
I’ve tweaked your script a bit to incorporate a custom grid size. I’ve set it to 4 studs, but you can change that in the variable at the top.
wait(2)
local gridSize = 4
local event = game.ReplicatedStorage.PlacementEvent
local Objects = game.ReplicatedStorage:WaitForChild("ObjectFolder")
local plr = game.Players.LocalPlayer
local char = plr.Character or plr.CharacterAdded:Wait()
local mouse = plr:GetMouse()
local frame = script.Parent:WaitForChild("Frame")
local textBox = script.Parent:WaitForChild("Frame").SizeBox
local ColorBox = script.Parent:WaitForChild("Frame").ColorBox
local MaterialBox = script.Parent:WaitForChild("Frame").MaterialBox
local uis = game:GetService("UserInputService")
local rs = game:GetService("RunService")
local PlacingObject = false
local RotatingObject = false
local FlippingObject = false
for i,v in pairs(frame:GetChildren()) do
if v:IsA("GuiButton") then
v.MouseButton1Click:Connect(function()
if PlacingObject == false then
PlacingObject = true
frame.Visible = false
local RotationAmount = 0
local FlippingAmount = 0
local PreviewObject = Objects:FindFirstChild(v.Name):Clone()
PreviewObject.Parent = game.Workspace
for a,b in pairs(PreviewObject:GetDescendants()) do
if b:IsA("BasePart") then
if b.Name == "MainPart" then
b.CanCollide = false
else
if b.Parent.Name == "Ball" then
b.Transparency = 1
b.CanCollide = false
else
b.Transparency = 0.5
b.CanCollide = false
end
end
end
end
uis.InputBegan:Connect(function(input)
if input.KeyCode == Enum.KeyCode.R then
RotatingObject = true
while RotatingObject == true do
wait()
RotationAmount += 2
end
end
if input.KeyCode == Enum.KeyCode.T then
FlippingObject = true
while RotatingObject == true do
wait()
FlippingAmount += 2
end
end
end)
uis.InputEnded:Connect(function(input)
if input.KeyCode == Enum.KeyCode.R then
RotatingObject = false
end
if input.KeyCode == Enum.KeyCode.T then
FlippingObject = false
end
end)
rs.RenderStepped:Connect(function()
if true == true then --this is where grid stuff will go
if PlacingObject == true then
mouse.TargetFilter = PreviewObject
if PreviewObject:FindFirstChild("MainPart") then
local objCFrame = CFrame.new(math.floor(mouse.Hit.Position.X/gridSize+0.5)*gridSize,mouse.Hit.Position.Y + PreviewObject.PrimaryPart.Size.Y / 2,math.floor(mouse.Hit.Position.Z/gridSize+0.5)*gridSize)
local objAngles = CFrame.Angles(0,math.rad(RotationAmount),math.rad(FlippingAmount))
PreviewObject:SetPrimaryPartCFrame(objCFrame * objAngles)
local SizeValues = textBox.Text:split(", ")
if #SizeValues == 3 then
PreviewObject.PrimaryPart.Size = Vector3.new(SizeValues[1],SizeValues[2],SizeValues[3])
end
local ColorValues = ColorBox.Text:split(", ")
if #ColorValues == 3 then
PreviewObject.PrimaryPart.Color = Color3.fromRGB(ColorValues[1],ColorValues[3],ColorValues[3])
end
mouse.Button1Up:Connect(function()
if PlacingObject == true then
PlacingObject = false
if #SizeValues == 3 then
if #ColorValues == 3 then
event:FireServer(PreviewObject.Name,PreviewObject.PrimaryPart.CFrame,SizeValues[1],SizeValues[2],SizeValues[3],ColorValues[1],ColorValues[2],ColorValues[3],MaterialBox.Text)
else
event:FireServer(PreviewObject.Name,PreviewObject.PrimaryPart.CFrame,SizeValues[1],SizeValues[2],SizeValues[3])
end
else
event:FireServer(PreviewObject.Name,PreviewObject.PrimaryPart.CFrame,MaterialBox.Text)
end
frame.Visible = true
PreviewObject:Destroy()
end
end)
end
end
end
end)
end
end)
end
end