Been trying to make it so that it snaps to the edge of a block depending on where you’re pointing, also relative to size.
Works fine for full size, but any other size that isn’t the same goes to the VERY edge where half of it is leaning off of it, or it goes to the centre.
local mouse = game.Players.LocalPlayer:GetMouse()
local connection
game:GetService("RunService").Heartbeat:Connect(function()
local sizing = script.Parent.Properties.Size.Value
if script.Parent.Properties.DoNotApply.Mode.Value == 0 then
if connection then
connection:Disconnect()
end
if workspace.Client:FindFirstChild("PreviewBlock") then
workspace.Client:FindFirstChild("PreviewBlock"):Destroy()
end
if mouse.Target then
local hitpos = mouse.Hit.Position
local part = game.ReplicatedStorage.Files.BlockTypes:FindFirstChild(script.Parent.Properties.Shape.Value):Clone()
part.Size = sizing
part.Anchored = true
local gridpos = Vector3.new(
math.floor((hitpos.X + sizing.X / 2) / sizing.X) * sizing.X,
math.floor((hitpos.Y + sizing.Y / 2) / sizing.Y) * sizing.Y,
math.floor((hitpos.Z + sizing.Z / 2) / sizing.Z) * sizing.Z
)
local alignpos = gridpos + Vector3.new(0, sizing.Y / 2, 0)
part.CFrame = CFrame.new(alignpos)
part.Parent = workspace.Client
part.Name = "PreviewBlock"
connection = mouse.Button1Down:Connect(function()
local newblock = part:Clone()
newblock.Anchored = false
newblock.Parent = workspace
end)
end
elseif script.Parent.Properties.DoNotApply.Mode.Value == 1 then
end
end)
For reference, it’s meant to snap like this for example:
You should try raycasting with WorldRoot:Raycast(). It gives the exact point and normal of where the raycast (mouse)
local result = workspace:Raycast(
workspace.CurrentCamera.CFrame.Position, -- origin
(player:GetMouse().Hit.Position - workspace.CurrentCamera.CFrame.Position).Unit * 1000, -- direction
RaycastParams.new())
print(result.Position) -- the position it found (ignores bounding boxes)
print(result.Normal) -- the direction the surface is facing (useful for placing objects flat on others)
This is what it results when I’ve implemented it. It still seems to be offset.
game:GetService("RunService").Heartbeat:Connect(function()
local sizing = script.Parent.Properties.Size.Value
if script.Parent.Properties.DoNotApply.Mode.Value == 0 then
if connection then
connection:Disconnect()
end
if workspace.Client:FindFirstChild("PreviewBlock") then
workspace.Client:FindFirstChild("PreviewBlock"):Destroy()
end
if mouse.Target then
local hitpos = mouse.Hit.Position
local part = game.ReplicatedStorage.Files.BlockTypes:FindFirstChild(script.Parent.Properties.Shape.Value):Clone()
part.Size = sizing
part.Anchored = true
part.CanCollide = false
part.Color = script.Parent.Properties.Color.Value
part.Material = Enum.Material[script.Parent.Properties.Material.Value]
part.Transparency = script.Parent.Properties.Transparency.Value
part.Reflectance = script.Parent.Properties.Reflectance.Value
local result = workspace:Raycast(
workspace.CurrentCamera.CFrame.Position, -- origin
(game.Players.LocalPlayer:GetMouse().Hit.Position - workspace.CurrentCamera.CFrame.Position).Unit * 1000, -- direction
RaycastParams.new()
)
local finalpos
if result then
finalpos = result.Position
else
finalpos = (workspace.CurrentCamera.CFrame.Position + (game.Players.LocalPlayer:GetMouse().Hit.Position - workspace.CurrentCamera.CFrame.Position).Unit * 1000)
end
local gridSize = getgrid(sizing)
finalpos = Vector3.new(
math.floor(finalpos.X / gridSize) * gridSize,
math.floor(finalpos.Y / gridSize) * gridSize,
math.floor(finalpos.Z / gridSize) * gridSize
)
part.CFrame = CFrame.new(finalpos + Vector3.new(0, sizing.Y / 2, 0))
part.Parent = workspace.Client
part.Name = "PreviewBlock"
connection = mouse.Button1Down:Connect(function()
local newblock = part:Clone()
newblock.CanCollide = script.Parent.Properties.Collision.Value
newblock.Anchored = game.ReplicatedStorage.Files.BlockTypes:FindFirstChild(script.Parent.Properties.Shape.Value).Anchored
newblock.Parent = workspace
end)
end
elseif script.Parent.Properties.DoNotApply.Mode.Value == 1 then
end
end)
function getgrid(size)
local sizes = {size.X, size.Y, size.Z}
local counts = {}
for _, s in ipairs(sizes) do
counts[s] = (counts[s] or 0) + 1
end
local maxCount = 0
local commonSize = sizes[1]
for size, count in pairs(counts) do
if count > maxCount then
maxCount = count
commonSize = size
end
end
return commonSize
end