(This probably is not going to be the best explanation D: )
Lets start at the manipulation of the radius of the circle.
The parameterization of a circle is x = cos(t) * radius, y = sin(t) * radius
.
Lets start on how we derive that parameterization first. I would like to try to explain this myself but I’m awful at explaining concepts, so I suggest reading this: Parametric Equation of a Circle - Math Open Reference
Using this we can see why we the number multiplied to the result of cos(t)
and sin(t)
is the the radius.
Now onto how I made the “smooth” effect. I have actually deceived you! My circle is not a collection of points that have been rotated, but instead a collection of lines rotated to point from the previous point and the next one. We can see this if we lower the amount of points in our polygon (to 10 for example):
I would prefer to show you the code (hey this code is like 8 or 9 months old so it might look weird) because I’m bad at explaining and it will probably be pretty beneficial for you to read.
Click HERE to see 1 year old code.
-- [[ Service Declarations ]] --
local workspace = game:GetService("Workspace")
-- [[ Prebuilt Library Declarations ]] --
--// Variables
local pi = math.pi
--// Functions
local cos = math.cos
local sin = math.sin
-- [[ Line Class Declarations ]] --
local line = {}
do
--// Line Methods
function line.new(positionA, positionB, lineWidth)
local newLine = Instance.new("Part")
local distance = (positionA - positionB).Magnitude
newLine.Anchored = true
newLine.Size = Vector3.new(lineWidth, lineWidth, distance)
newLine.CFrame = CFrame.new(positionA, positionB) * CFrame.new(lineWidth / 2, 0, -distance / 2)
newLine.Parent = workspace
return newLine
end
end
-- [[ Shape Class Declarations ]] --
local shape = {}
do
--// Shape Methods
function shape.new(pointCount, radius, lineWidth)
local newShape = {}
do
--// Calculate Points
local points = {}
local angle = (pi * 2) / pointCount
for i = 1, pointCount do
local currentAngle = angle * i
local xPosition = cos(currentAngle) * radius
local zPosition = sin(currentAngle) * radius
local position = Vector3.new(xPosition, 0, zPosition)
do
--// Render Point
local newPoint = Instance.new("Part")
newPoint.Anchored = true
newPoint.Transparency = .5
newPoint.Size = Vector3.new(1, 1, 1)
newPoint.CFrame = CFrame.new(position)
newPoint.Parent = workspace
end
points[#points + 1] = position
end
newShape.points = points
end
do
--// Generate Lines
local points = newShape.points
for i = 1, #points do
local index = (i % #points) + 1
local nextIndex = ((i + 1) % #points) + 1
local currentPoint = points[index]
local nextPoint = points[nextIndex]
line.new(currentPoint, nextPoint, lineWidth)
end
end
return newShape
end
end
-- [[ Init ]] --
do
--// Generate Shape
shape.new(24, 50, 1) --// shape.new(pointCount, radius, lineWidth)
end
Here we generate the points for our polygon. pi * 2
is the max radians in a circle and so if we want to draw a regular polygon of n
points our angle between each point would be (pi * 2) / n
. We would then multiply the current index of that angle
value to get the currentAngle
. Then we draw the coordinates of the circle at that given point in “time” (currentAngle)
Here is where the magic comes in that makes everything look “smooth”. (You will want to comment out the lines producing the point part in workspace which is line 64-77)
We create a new line by first getting the current point. (OK I might have over complicated the index
and newIndex
section but basically it makes “cyclic” index. For example if I have an array with 6 elements and I index for the 7th element it will instead return the 1st element. We do this because the last line will need to connect to the first line to connect everything together.
The line function is pretty reasonable. We just create a part with size lineWidth, lineWidth, distance
and then set its position to positionA
and pointing towards positionB
then offset it by half the negative distance. (Negative because Roblox’s Z plane flipped and division of distance because the side of a rectangle is derived from origin + size / 2 since the center of a rectangle is half the length of the rectangle away from the side [ok that sounds confusing but theres hope you might understand!])
When we set our first parameter of shape.new
to a high number like 100 (this means we make 100 parts) it will look “smooth” because we will have tons line segments.
If you go crazy and set it to 1000
points you can make a very convincing circle with a 1000-gon.