Just recently I was playing around with some moving platforms I had created for my game Shadow of the Orient. My game has horizontal and vertical moving platforms but it also has circular moving platforms as seen in the video below:
I wanted to add a visual aid to the radius of the circle which the platform follows along but i wasn’t quite sure how to do that – so I looked around on Google and found an article that explained how to work with the Line Renderer. After some messing around I was able to get my visual aid working quite nicely. The reason I wanted the visual aid was to give players a clue as to how much the platform needs to move before it comes into reach. So without further ado below is how i created my circular moving platform with the visual aid.
Setting up the structure
To set this up I first created a parent game object (Circular_Platform) which contains my main scripts for moving the platform along with the LineRenderer component to draw the visual aid. I then created my platform game object (Spiked_Platform) and added it as a child element of the parent game object as seen in the following reference:

The Point_Gear_1 game object can be ignored for this tutorial – its the spinning gear i added to the center of the circle radius which rotates in the same direction as the moving platform.
Next I assigned the following two components to the “Circular_Platform” parent game object:
CircularMovement.cs
using UnityEngine;
public enum CircularDirection
{
Clockwise,
CounterClockwise
}
public class CircularMovement : MonoBehaviour
{
[SerializeField] private GameObject objectToMove;
[SerializeField] private bool reverseHalfway = false;
[SerializeField] CircularDirection circularDirection = CircularDirection.Clockwise;
[SerializeField, Range(0f, 20f)] private float startPosition = 0;
[SerializeField, Range(0f, 50f)] private float angularSpeed = 1;
[SerializeField, Range(0f, 50f)] private float rotationRadius = 20;
//Internal vars
private float _angle = 0f;
private float _posX, _posY = 0f;
private bool _flipDirection = false;
private Vector2 _objecToMovePosition;
private Transform _transform;
private void Awake()
{
_transform = transform;
}
private void Start()
{
if(startPosition > 0)
{
//Set a starting point on the radius
_posX = _transform.position.x + Mathf.Cos(startPosition) * rotationRadius;
_posY = _transform.position.y + Mathf.Sin(startPosition) * rotationRadius;
//Set the starting angle
_angle = startPosition;
//Assign the position to the moving object
_objecToMovePosition.Set(_posX, _posY);
objectToMove.transform.position = _objecToMovePosition;
}
}
void Update()
{
Move();
}
private void Move()
{
//Check if the moving object should reverse course back to the starting point
if (reverseHalfway)
{
if (Mathf.Abs(_angle) > 3.14)
_flipDirection = true;
else if (Mathf.Abs(_angle) <= 0.01f)
_flipDirection = false;
}
//Check which direction to move
if (circularDirection == CircularDirection.Clockwise)
_angle = _flipDirection ? _angle + Time.deltaTime * angularSpeed : _angle - Time.deltaTime * angularSpeed;
else
_angle = _flipDirection ? _angle - Time.deltaTime * angularSpeed : _angle + Time.deltaTime * angularSpeed;
//Calculate the angle of the x and y positions and include the rotation radius
_posX = _transform.position.x + Mathf.Cos(_angle) * rotationRadius;
_posY = _transform.position.y + Mathf.Sin(_angle) * rotationRadius;
//Assign the movment to the object that needs to be moved
_objecToMovePosition.Set(_posX, _posY);
objectToMove.transform.position = _objecToMovePosition;
}
#if UNITY_EDITOR
private void OnDrawGizmosSelected()
{
Gizmos.color = Color.yellow;
Gizmos.DrawWireSphere(transform.position, rotationRadius);
Gizmos.color = Color.green;
float _posX = transform.position.x + Mathf.Cos(_angle) * rotationRadius;
float _posY = transform.position.y + Mathf.Sin(_angle) * rotationRadius;
Gizmos.DrawCube(new Vector2(_posX, _posY), new Vector3(3, 3, 3));
}
#endif
}
This code is responsible for moving the platform along a circular path and includes settings for speed, radius, starting position and a few more. I also added a visual gizmo so you can see the radius of the circle update in the unity editor as seen in the video below:
CircleLineRenderer.cs
The next component is a script I came across on Google and I’m sharing it here so you have a point of reference.
using UnityEngine;
[RequireComponent(typeof(LineRenderer))]
public class CircleLineRenderer : MonoBehaviour
{
private const float DOTTED_LINE_TICKNESS_RATIO = 2.5f;
private const int NUM_CAP_VERTICES = 6;
[Tooltip("The radius of the circle perimeter")]
public float radius = 2;
[Tooltip("The width of the line for the circle perimeter")]
public float lineWidth = 0.05f;
[Tooltip("Check this to use the dotted line material for the circle perimeter line")]
public bool isDotted = false;
[Tooltip("The material for the plain line")]
public Material plainMaterial;
[Tooltip("The material for the dotted line")]
public Material dottedMaterial;
private LineRenderer lineRenderer;
void Start()
{
lineRenderer = GetComponent<LineRenderer>();
lineRenderer.useWorldSpace = false;
lineRenderer.numCapVertices = NUM_CAP_VERTICES;
SetRadius(radius);
}
void Update()
{
//While testing in-editor, refresh the circle each frame so we can test the circle by changing the fields in the inspector.
if (Application.isEditor) SetRadius(radius);
}
//Call this method from other scripts to adjust the radius at runtime
public void SetRadius(float pRadius)
{
radius = pRadius;
if (radius <= 0.1f)
{
lineRenderer.positionCount = 0;
return;
}
float tickness = lineWidth;
if (isDotted) tickness *= DOTTED_LINE_TICKNESS_RATIO;
lineRenderer.startWidth = tickness;
lineRenderer.endWidth = tickness;
//Calculate the number of vertices needed depending on radius so it always looks round.
//For instance, huge circles need proportionaly less vertices than smaller ones to look good.
//Source : http://stackoverflow.com/questions/11774038/how-to-render-a-circle-with-as-few-vertices-as-possible
float e = 0.01f; //constant ratio to adjust, reduce this value for more vertices
float th = Mathf.Acos(2 * Mathf.Pow(1 - e / radius, 2) - 1); //th is in radian
int numberOfVertices = Mathf.CeilToInt(2 * Mathf.PI / th);
lineRenderer.positionCount = numberOfVertices + 1;
for (int i = 0; i < numberOfVertices + 1; i++)
{
float angle = (360f / (float)numberOfVertices) * (float)i;
lineRenderer.SetPosition(i, radius * new Vector3(Mathf.Cos(Mathf.Deg2Rad * angle), Mathf.Sin(Mathf.Deg2Rad * angle), 0));
}
//Update material depending if its a dotted line or a plain one.
if (isDotted)
{
lineRenderer.material = dottedMaterial;
lineRenderer.materials[0].mainTextureScale = new Vector3(2 * Mathf.PI * radius * (1 / tickness), 1, 1);
}
else
{
lineRenderer.material = plainMaterial;
lineRenderer.materials[0].mainTextureScale = Vector3.one;
}
}
//Call this method from other scripts to adjust the width of the line at runtime
public void SetWidth(float pWidth)
{
lineWidth = pWidth;
SetRadius(radius);
}
//Call this method from other scripts to switch between plain and dotted line at runtime
public void SetIsDotted(bool pIsDotted)
{
if (isDotted != pIsDotted)
{
isDotted = pIsDotted;
SetRadius(radius);
}
}
}
This script creates the visual aid for my platform using the LineRenderer component. In order for this to work correctly you will need to create a material to get your visual aid to display in the game engine – in the image below you can see that I have the “Is Dotted” parameter checked on and i assigned a material called “Dotted_Line_Renderer” to the “Dotted Material” parameter.

The following image shows the material which i created:

It’s to important to note that the tiling needs to be set to 1,1 and below is the graphic which I assigned to the material slot:
![]()
And that’s about it in a nutshell. To be honest i had never used the LineRenderer component and only became aware of it because ChatGPT recommended using it for drawing a repeating pattern along a line in Unity…yup ChatGPT…the A.I. modeling language that’s going to change the world in a big, big way.
Have questions? Feel free to post them below in the comments section.








