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);
}
}
}






