I didn’t quite get you, but by reading the post I assume you want to snap rotation of the wall too along with movement. Here’s a quick snap code I wrote that achieves that using some basic trigonometry:
local function snap(vector1, vector2)
if vector2 then
local angle = math.round(math.atan2(vector2.Z - vector1.Z, vector2.X - vector1.X) / ROTATION_CONSTRAINT) * ROTATION_CONSTRAINT;
local dist = math.abs((vector1 - vector2).Magnitude);
vector1 += Vector3.new(dist * math.cos(angle), 0, dist * math.sin(angle));
end
local snapped = {}
for i,axis in ipairs{ "X", "Y", "Z" } do
snapped[i] = math.round(vector1[axis] / MOVE_CONSTRAINT) * MOVE_CONSTRAINT;
end
return Vector3.new(table.unpack(snapped));
end
And here’s the code I used to test:
local userInputService = game:GetService("UserInputService");
local workspace = game:GetService("Workspace");
local camera = workspace.CurrentCamera;
local MOVE_CONSTRAINT = 4;
local ROTATION_CONSTRAINT = math.rad(45);
local cPole1, cWall, cPole2;
local function snap(vector1, vector2)
if vector2 then
local angle = math.round(math.atan2(vector2.Z - vector1.Z, vector2.X - vector1.X) / ROTATION_CONSTRAINT) * ROTATION_CONSTRAINT;
local dist = math.abs((vector1 - vector2).Magnitude);
vector1 += Vector3.new(dist * math.cos(angle), 0, dist * math.sin(angle));
end
local snapped = {}
for i,axis in ipairs{ "X", "Y", "Z" } do
snapped[i] = math.round(vector1[axis] / MOVE_CONSTRAINT) * MOVE_CONSTRAINT;
end
return Vector3.new(table.unpack(snapped));
end
local function updateWall(wall, p1, p2)
wall.Size = Vector3.new(1, 15, math.abs((p1 - p2).Magnitude));
wall.CFrame = CFrame.new((p1 + p2) / 2, p2);
end
local function createWall()
local wall = Instance.new("Part");
wall.Name = "Wall";
wall.Anchored = true;
wall.Parent = workspace;
return wall;
end
local function updatePole(pole, p)
p = cPole1 and snap(cPole1.Position, p) or snap(p);
pole.Position = p;
end
local function createPole(pos)
local newPole = cPole1 and cPole1:Clone();
if not newPole then
newPole = Instance.new("Part");
newPole.Size = Vector3.new(1, 15, 1);
newPole.Transparency = 0.5;
newPole.CanCollide = false;
newPole.Anchored = true;
end
updatePole(newPole, pos);
if cPole1 then
cWall = createWall(cPole1.Position, newPole.Position);
cPole2 = newPole;
else
cPole1 = newPole;
end
newPole.Position = pos;
newPole.Parent = workspace;
return newPole;
end
local function preview(pos)
if cWall then
updatePole(cPole2, pos);
updateWall(cWall, cPole1.Position, cPole2.Position);
else
if cPole1 then updatePole(cPole1, pos); end
end
end
local function getWorldPosition(sPos)
local unit = camera:ScreenPointToRay(sPos.X, sPos.Y);
local res = workspace:Raycast(unit.Origin, unit.Direction * 30, RaycastParams.new());
if res then return res.Position; end
end
userInputService.InputBegan:Connect(function(key, processed)
if processed then return; end
if key.UserInputType ~= Enum.UserInputType.MouseButton1 then return; end
if cPole1 and cPole2 and cWall then
cPole1 = nil;
cPole2 = nil;
cWall = nil;
return;
end
local pos = getWorldPosition(key.Position);
if pos then
createPole(pos);
end
end);
userInputService.InputChanged:Connect(function(key, processed)
if processed then return; end
if key.UserInputType ~= Enum.UserInputType.MouseMovement then return; end
local pos = getWorldPosition(key.Position);
if pos then
preview(pos);
end
end);
EDIT:
- Fixed a bug where the 2nd pole position didn’t snap after rotating
- Implemented preview for fun (which made me detect the first bug)