I don’t know if this is the best way to do it but you could make it move with the mouse and use math.round(), clone this script into your game and see if this is close to what you want. This is only an example of it.
local RunService = game:GetService("RunService")
local plr = game.Players.LocalPlayer
local mouse = plr:GetMouse()
local part = Instance.new("Part")
part.Anchored = true
part.Parent = game.Workspace
part.CanQuery = false
part.CanTouch = false
part.CanCollide = false
local connection = RunService.RenderStepped:Connect(function ()
part.Position = Vector3.new(math.round(mouse.Hit.X), math.round(mouse.Hit.Y), math.round(mouse.Hit.Z))
end)
This isn’t exactly what I am trying to achieve.
I am trying to make the object snap to the surface and follow the grid only on the x and z axis while the y axis is the surface normal.
make a raycast and then use raycastresult.Instance to get the part that the raycast hit
then you can add the orientation of the part to your building when creating it
im still thinking about how to find which spot on the grid the building would be placed on
but in 2d the point that the mouse hits would be located at ( cos(angle), sin(angle) ) relative to where the point would be located at if it were a flat plane
you could also get the parts cframe and use its lookvector and rightvector multiplied in increments to find points located on the grid, and then search for the closest point to the mouse
Adding the orientation of the part wouldn’t really help in anything. Since let’s say that a square is rotated 180 degrees, then the object would also get turned 180 degrees without a reason.
Let’s say we’re trying to place the object on a sphere. I can rotate the sphere all kinds of ways and it would still look like a sphere, but the rotation would still be applied to the object.
local RunService = game:GetService("RunService")
local Players = game:GetService("Players")
local plr = Players.LocalPlayer
local mouse = plr:GetMouse()
local part = Instance.new("Part")
local RoundSize = 4
part.Anchored = true
part.Parent = game.Workspace
part.CanQuery = false
part.CanTouch = false
part.CanCollide = false
local function alignPartToSurface(hitPosition, hitNormal)
part.Position = hitPosition
local newCFrame
if math.abs(hitNormal.Y) > 0.5 then
newCFrame = CFrame.new(hitPosition) * CFrame.Angles(0, 0, 0)
else
local upVector = hitNormal
local forwardVector = Vector3.new(0, 1, 0):Cross(upVector).Unit
local rightVector = upVector:Cross(forwardVector).Unit
newCFrame = CFrame.fromMatrix(hitPosition, rightVector, upVector, forwardVector)
end
part.CFrame = newCFrame
end
local connection = RunService.RenderStepped:Connect(function()
local ray = Ray.new(mouse.UnitRay.Origin, mouse.UnitRay.Direction * 1000)
local hit, position, normal = workspace:FindPartOnRay(ray)
if hit then
alignPartToSurface(position, normal)
else
part.Position = mouse.Hit.Position
end
end)
Really sorry for the late response!
Looking through your code, it does help, more specifically the CFrame.fromMatrix(), although it still doesn’t help with the grid.
local RunService = game:GetService("RunService")
local Players = game:GetService("Players")
local plr = Players.LocalPlayer
local mouse = plr:GetMouse()
local part = Instance.new("Part")
local RoundSize = 4
part.Anchored = true
part.Parent = game.Workspace
part.CanQuery = false
part.CanTouch = false
part.CanCollide = false
local function roundToGrid(position, size)
return Vector3.new(
math.floor(position.X / size + 0.5) * size,
math.floor(position.Y / size + 0.5) * size,
math.floor(position.Z / size + 0.5) * size
)
end
local function alignPartToSurface(hitPosition, hitNormal)
local roundedPosition = roundToGrid(hitPosition, RoundSize)
part.Position = roundedPosition
local newCFrame
if math.abs(hitNormal.Y) > 0.5 then
newCFrame = CFrame.new(roundedPosition) * CFrame.Angles(0, 0, 0)
else
local upVector = hitNormal
local forwardVector = Vector3.new(0, 1, 0):Cross(upVector).Unit
local rightVector = upVector:Cross(forwardVector).Unit
newCFrame = CFrame.fromMatrix(roundedPosition, rightVector, upVector, forwardVector)
end
part.CFrame = newCFrame
end
local connection = RunService.RenderStepped:Connect(function()
local ray = Ray.new(mouse.UnitRay.Origin, mouse.UnitRay.Direction * 1000)
local hit, position, normal = workspace:FindPartOnRay(ray)
if hit then
alignPartToSurface(position, normal)
else
part.Position = roundToGrid(mouse.Hit.Position, RoundSize)
end
end)
How will welding it help? I am not trying to physically attach it to the part.
I am only trying to place it so that it’s attached to the surface while also snapping to a grid.
How it works is, using CFrames (:Inverse() or :ToObjectSpace()), I retrieve the position of the mouse relative to the closest corner of the target part (which includes). Then I round the relative position as you would in a simple grid building system, and finally transform it back into world coordinates using CFrame multiplication (equivalent to :ToWorldSpace())
There is more math to make the placing part’s rotation more consistent (like if the target part is rotated 195 degress, I want the part I’m pacing to only be rotated by 15 degrees (so it matches the surface it is being placed on), if the orientation setting is set to 0, 0, 0)
Doing such a system does require a good knowledge of CFrames
I can go more in depth with code examples if you’d like, and if this is what you are looking for