Good news! Last night we got the last script posted here working and we also added a couple more features. It now handles both halves of each wall (inner / outer or in other words left / right) differently so that when coloring them they don’t glitch the graphics where they overlap. In addition, we discovered that when the smallest angle between the walls is less than 90 degrees, the walls can’t be brought together to form a clean point. Doing so makes the wall’s thickness stick out the other end and form an hour glass looking shape around the poll. So, one wall is chosen to form the end and the other wall stops inside of that wall. This code also handles multiple-wall intersections by resizing the left half with the right half of the wall on its left side, and the right half with the left half of the wall on its right side (forward being toward the poll).
If anyone runs across a similar issue at some point, here is the code. Sorry if the math variables are not well named, there so many related in various special ways that it became difficult to find good names for them.
local WALL_HEIGHT = 12
local WALL_OFFSET = Vector3.new(0, WALL_HEIGHT, 0)
local UP = Vector3.new(0, 1, 0)
local WALL_HALF_THICKNESS = 0.2
local abs = math.abs
local function absVector3(v3)
return Vector3.new(
abs(v3.X),
abs(v3.Y),
abs(v3.Z)
)
end
local function setSize(wall, half, length)
local delta = length - wall.length[half]
local dir = wall.dir * delta
local part = wall[half]
local offset = part.CFrame:VectorToObjectSpace(dir)
part.Size = part.Size + math.sign(delta) * absVector3(offset)
part.CFrame = part.CFrame + dir / 2
wall.length[half] = length
end
local function adjust(wall, other)
local angle = math.acos(wall.rightDir:Dot(-other.rightDir))
local wallLength, otherLength
if math.abs(angle - math.pi/2) < 0.001 then
if wall.dir:Dot(other.rightDir - wall.rightDir) > 0 then
wallLength = WALL_HALF_THICKNESS
otherLength = 0
else
wallLength = 0
otherLength = -WALL_HALF_THICKNESS
end
elseif angle > math.pi/2 then
local otherAngle = math.acos(wall.dir:Dot(other.dir))
local sign = -math.sign(wall.rightDir:Dot(other.dir))
wallLength = sign * WALL_HALF_THICKNESS / math.tan(otherAngle)
otherLength = sign * math.sqrt(wallLength^2 + WALL_HALF_THICKNESS^2)
else
wallLength = math.tan(angle / 2) * WALL_HALF_THICKNESS
otherLength = wallLength
end
setSize(wall, 'left', wallLength)
setSize(other, 'right', otherLength)
end
local POLL_KEY = '%d %d %d'
local function getWalls(polls, pos)
local key = POLL_KEY:format(pos.X, pos.Y, pos.Z)
local walls = polls[key]
if not walls then
walls = {}
polls[key] = walls
end
return walls
end
local function addToPoll(polls, poll, otherPoll, model)
local walls = getWalls(polls, poll)
local dir = (poll - otherPoll).Unit
local rightDir = dir:Cross(UP)
local right, left = model.Wall1, model.Wall2
local toRight = right.Position - left.Position
if toRight:Dot(rightDir) < 0 then
right, left = left, right
end
local wall = {
length = {
left = 0;
right = 0;
};
model = model;
right = right;
left = left;
dir = dir;
rightDir = rightDir;
}
if not next(walls) then
walls[wall] = true
return
end
local leftIsFound
local leftDot
local leftWall
local rightIsFound
local rightDot
local rightWall
for otherWall in next, walls do
local dot = dir:Dot(otherWall.dir)
local isRight = rightDir:Dot(otherWall.dir) < 0
if isRight then
if not rightIsFound or not rightDot or dot > rightDot then
rightIsFound = true
rightDot = dot
rightWall = otherWall
end
if not leftIsFound and (not leftDot or dot < leftDot) then
leftDot = dot
leftWall = otherWall
end
else
if not rightIsFound and (not rightDot or dot < rightDot) then
rightDot = dot
rightWall = otherWall
end
if not leftIsFound or not leftDot or dot > leftDot then
leftIsFound = true
leftDot = dot
leftWall = otherWall
end
end
end
adjust(wall, leftWall)
adjust(rightWall, wall)
walls[wall] = true
end
local function placeWall(polls)
local mouse = game.Players.LocalPlayer:GetMouse()
mouse.Button1Down:Wait()
local pollA = snapToGrid(mouse.Hit.p)
mouse.Button1Down:Wait()
local pollB = snapToGrid(mouse.Hit.p)
local model = wallModel:Clone()
model:SetPrimaryPartCFrame(CFrame.fromMatrix(
(pollA + pollB) / 2 + WALL_OFFSET,
(pollA - pollB).Unit,
UP
))
addToPoll(polls, pollA, pollB, model)
addToPoll(polls, pollB, pollA, model)
model.Parent = workspace
end