In previous part we have seen how a circle can be defined using the basic trigonometry equations. In this part we will see how to transform that knowledge into code and use it in an actual Unity project.
This tutorial is a part of tutorial series Unity – Draw Custom Debug Shapes
Extending Debug Class
In this tutorial we will create one additional Debug Draw method. To make future usage of that method as streamlined as possible, it is necessary to override/extend Unity’s Debug class. To do so, first create a new C# class and name it Debug.cs (personally I prefer to store them in Assets/Scripts folder, but for this example it is not crucial).
Inside of that file insert the following code:
using UnityEngine;
class Debug : UnityEngine.Debug
{
// UnityEngine class extensions
}
This new Debug class will be used as a base for all following extensions and tutorials.
As discussed in previous tutorial, circle approximation can be described with following properties:
- Center/origin
- Radius
- Number of segments
These properties need to be passed to the drawing function. Additionally, to make things prettier (and more useful), we can also pass desired drawing color. Therefore, a signature of the most basic version of the circle drawing method can look like this:
public static class DrawCircle(Vector3 position, float radius, float segments, Color color)
For the most basic implementation of this function, circle can be drawn in the XY plane (following tutorials will cover how to draw circles on different planes, as well as how to handle rotation).
To draw a circle, the method needs perform following steps:
- Check if radius is greater than zero,
- Check if number of segments is greater than zero,
- Calculate how many degrees each segment covers,
- For each segment, calculate start and end points,
- Offset those points by the location of origin/center,
- Connect those points using built-in Debug.DrawLine method, and using the passed color
public static void DrawCircle(Vector3 position, float radius, int segments, Color color)
{
// If either radius or number of segments are less or equal to 0, skip drawing
if (radius <= 0.0f || segments <= 0)
{
return;
}
// Single segment of the circle covers (360 / number of segments) degrees
float angleStep = (360.0f / segments);
// Result is multiplied by Mathf.Deg2Rad constant which transforms degrees to radians
// which are required by Unity's Mathf class trigonometry methods
angleStep *= Mathf.Deg2Rad;
// lineStart and lineEnd variables are declared outside of the following for loop
Vector3 lineStart = Vector3.zero;
Vector3 lineEnd = Vector3.zero;
for (int i = 0; i < segments; i++)
{
// Line start is defined as starting angle of the current segment (i)
lineStart.x = Mathf.Cos(angleStep * i) ;
lineStart.y = Mathf.Sin(angleStep * i);
// Line end is defined by the angle of the next segment (i+1)
lineEnd.x = Mathf.Cos(angleStep * (i + 1));
lineEnd.y = Mathf.Sin(angleStep * (i + 1));
// Results are multiplied so they match the desired radius
lineStart *= radius;
lineEnd *= radius;
// Results are offset by the desired position/origin
lineStart += position;
lineEnd += position;
// Points are connected using DrawLine method and using the passed color
DrawLine(lineStart, lineEnd, color);
}
}
To test the functionality of this method, we can create a simple example MonoBehavior class. To do so, create a new C# file named Example.cs, empty and an empty GameObject named Example, and place the newly created C# script on it. Also, reset its transform to make sure it is located at (0,0,0).
Inside of the Example.cs script change the Update method to following:
void Update()
{
// Draw circles at the position of the GameObject, with different radii, number of segments and colors
Debug.DrawCircle(transform.position, 2.0f, 32, Color.red);
Debug.DrawCircle(transform.position, 3.0f, 16, Color.yellow);
Debug.DrawCircle(transform.position, 4.0f, 8, Color.green);
// Draw circles with a certain offset from the position of the GameObject
Debug.DrawCircle(transform.position + new Vector3(-5.0f, -5.0f, 0), 0.5f, 16, Color.white);
Debug.DrawCircle(transform.position + new Vector3(5.0f, 5.0f, 0), 0.5f, 16, Color.white);
Debug.DrawCircle(transform.position + new Vector3(-5.0f, 5.0f, 0), 0.5f, 16, Color.white);
Debug.DrawCircle(transform.position + new Vector3(5.0f, -5.0f, 0), 0.5f, 16, Color.white);
}
As you may notice, transform.position of this GameObject is used as the origin of the circles. If everything was done correctly, after starting the game, you should receive similar results as shown below (please not that the location of the MainCamera is (0, 0, -10)):
The following tutorial will cover how to implement custom rotation of the circles, so they can be drawn in any plane.