Drawing a circle in a 2D game.

I’d like to draw circles in my 2D game.
I need that they will be scalable and be used in animations…

Do I have to use sprites for this or can I draw circles directly?

You can do it with a sprite, though I wrote a little shader for doing ‘perfect’ circles a little while ago. That said - they could be made more perfect!

Here’s the shader code (suitable for use on a sprite material)

Shader "Custom/circle" 
{
    Properties
    {
        [PerRendererData] _MainTex ("Sprite Texture", 2D) = "white" {}
        _InnerColor ("InnerColor", Color) = (1,1,1,1)
        _BorderColor ("BorderColor", Color) = (1,1,1,1)
		_InnerRadiusU ("Inner Radius U", Float) = 0.15
		_HalfMinusInnerRadiusU ("Half Minus Inner Radius U", Float) = 0.35

    }

	CGINCLUDE
    #include "UnityCG.cginc"
	struct appdata_t
    {
        float4 vertex   : POSITION;
        float4 color    : COLOR;
        float2 texcoord : TEXCOORD0;
    };
 
    struct v2f
    {
        float4 vertex   : SV_POSITION;
        fixed4 color    : COLOR;
        half2 texcoord  : TEXCOORD0;
    };
           
    sampler2D _MainTex;
 
    v2f vert(appdata_t IN)
    {
        v2f OUT;
        OUT.vertex = mul(UNITY_MATRIX_MVP, IN.vertex);
        OUT.texcoord = IN.texcoord;
        OUT.color = IN.color;
        return OUT;
    }
 
	half _InnerRadiusU;
	half _HalfMinusInnerRadiusU;
	half4 _InnerColor;
	half4 _BorderColor;
 
    fixed4 frag(v2f IN) : COLOR
    {
        half4 texcol = tex2D (_MainTex, IN.texcoord);       
				
		half2 local_pos = IN.texcoord-fixed2(0.5,0.5);
		half dist = length(local_pos);
		half border_t = saturate((dist - _InnerRadiusU) / _HalfMinusInnerRadiusU);
		half4 col = lerp(_InnerColor,_BorderColor,border_t);
		texcol.xyz *= col;
		texcol.w = border_t >= 0.999 ? 0 : 1;
        return texcol;
    }
	ENDCG
 
    SubShader
    {
        Tags
        {
            "Queue"="Transparent"
            "IgnoreProjector"="True"
            "RenderType"="Transparent"
            "PreviewType"="Plane"
            "CanUseSpriteAtlas"="True"
        }
 
        Cull Off
        Lighting Off
        ZWrite Off
        Fog { Mode Off }
        Blend SrcAlpha OneMinusSrcAlpha
 
        Pass
        {
        CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag
            #pragma multi_compile DUMMY PIXELSNAP_ON
        ENDCG
        }
    }
    Fallback "Sprites/Default"
}

You’ll notice the input parameters are a little odd - this is to minimize computation inside the shader. I have an extra script I use to setup those parameters:

using UnityEngine;
using System.Collections;

public class circlesetup : MonoBehaviour {

    public float borderWidth = 5;

    Material renderer_material;

	// Use this for initialization
	void Start () {
        renderer_material = GetComponent<SpriteRenderer>().material;
	}
	
	// Update is called once per frame
	void Update () {

        Vector4 sz = new Vector4(transform.lossyScale.x, transform.lossyScale.y);

        float rad = sz.x * 0.5f;
        float inner_rad_u = Mathf.Max((rad - borderWidth) / sz.x,0);
        renderer_material.SetFloat("_InnerRadiusU", inner_rad_u);
        renderer_material.SetFloat("_HalfMinusInnerRadiusU", 0.5f-inner_rad_u);
    }
}

I use that for drawing circular sprites on screen. It takes the circle’s radius as the sprite’s x size, then does some calculations to get the correct parameters into the shader.

Note that really all this shader is doing is calculating the distance of each pixel from the centre of the sprite, and if it is less than the desired radius of your circle, drawing it. All the complicated bits are for optimisation.

-Chris

edit: I noticed that for my own purposes I have ZWrite and culling turned off in that shader - that’s up to you - its for my own purposes so might not be what you want