Beginner help - animating a UI component

Hi all, new to Unity here.

I need to create 2D planes in a 3D scene, in which 1 or more circles/dots each rotate around a distinct wider circular tarjectory. I need to be able to set each dot’s colour, rotational speed & direction independently, and to be able to get its (x,y) coordinates in the 2D plane whenever I want at runtime.

I’m good with C#, but not familiar with scripting for unity nor 3D & game development in general.

So far, I have used a UI Canvas for the 2D plane and populated it with the circles as scripted by @Senshi here.

First of all, is this a sound way to proceed? If yes/no please can you tell me why?

If I’m on the right track, can someone explain or point me to a (hopefully basic) documentation where I can get started with making those dots rotate in the 2D plane?

Cheers

If it’s any easier, here is the src to said circle script:

using UnityEngine;
using UnityEngine.UI;
using System.Collections.Generic;

[ExecuteInEditMode]
public class UICircle : Graphic
{
    [SerializeField]
    Texture m_Texture;
    [Range(0, 100)]
    public int fillPercent;
    public bool fill = true;
    public int thikness = 5;
    [Range(0, 360)]
    public int segments = 360;
    public override Texture mainTexture
    {
        get
        {
            return m_Texture == null ? s_WhiteTexture : m_Texture;
        }
    }
    /// <summary>
    /// Texture to be used.
    /// </summary>
    public Texture texture
    {
        get
        {
            return m_Texture;
        }
        set
        {
            if (m_Texture == value)
                return;
            m_Texture = value;
            SetVerticesDirty();
            SetMaterialDirty();
        }
    }
    void Update()
    {
        this.thikness = (int)Mathf.Clamp(this.thikness, 0, rectTransform.rect.width / 2);
    }
    protected UIVertex[] SetVbo(Vector2[] vertices, Vector2[] uvs)
    {
        UIVertex[] vbo = new UIVertex[4];
        for (int i = 0; i < vertices.Length; i++)
        {
            var vert = UIVertex.simpleVert;
            vert.color = color;
            vert.position = vertices[i];
            vert.uv0 = uvs[i];
            vbo[i] = vert;
        }
        return vbo;
    }
    //    protected override void OnFillVBO(List<UIVertex> vbo)
    protected override void OnPopulateMesh(Mesh toFill)
    {
        float outer = -rectTransform.pivot.x * rectTransform.rect.width;
        float inner = -rectTransform.pivot.x * rectTransform.rect.width + this.thikness;
        //        vbo.Clear();
        toFill.Clear();
        var vbo = new VertexHelper(toFill);
        UIVertex vert = UIVertex.simpleVert;
        Vector2 prevX = Vector2.zero;
        Vector2 prevY = Vector2.zero;
        Vector2 uv0 = new Vector2(0, 0);
        Vector2 uv1 = new Vector2(0, 1);
        Vector2 uv2 = new Vector2(1, 1);
        Vector2 uv3 = new Vector2(1, 0);
        Vector2 pos0;
        Vector2 pos1;
        Vector2 pos2;
        Vector2 pos3;
        float f = (this.fillPercent / 100f);
        float degrees = 360f / segments;
        int fa = (int)((segments + 1) * f);
        for (int i = 0; i < fa; i++)
        {
            float rad = Mathf.Deg2Rad * (i * degrees);
            float c = Mathf.Cos(rad);
            float s = Mathf.Sin(rad);
            float x = outer * c;
            float y = inner * c;
            uv0 = new Vector2(0, 1);
            uv1 = new Vector2(1, 1);
            uv2 = new Vector2(1, 0);
            uv3 = new Vector2(0, 0);
            pos0 = prevX;
            pos1 = new Vector2(outer * c, outer * s);
            if (fill)
            {
                pos2 = Vector2.zero;
                pos3 = Vector2.zero;
            }
            else
            {
                pos2 = new Vector2(inner * c, inner * s);
                pos3 = prevY;
            }
            prevX = pos1;
            prevY = pos2;
            vbo.AddUIVertexQuad(SetVbo(new[] { pos0, pos1, pos2, pos3 }, new[] { uv0, uv1, uv2, uv3 }));
        }
        if (vbo.currentVertCount > 3)
        {
            vbo.FillMesh(toFill);
        }
    }
}

FWIW I have kind of worked it out; I wrote a script that doest what i need:

using System;
using UnityEngine;

/// <summary>
/// This Unity script rotates a UI component in a 2D (x,y) plan according to the
/// parametric equation of the circle. The component will rotate from its
/// initial position around a given rotation centre at a given rotation speed.
///
/// Make sure that the parent Canvas' Rect Transform Anchors Min, Max and Pivot
/// are all set to 0.5 or the script doesn't work properly.
///
/// Source code can be clarified: some confusuions over period vs frequency
/// & over degrees vs radians.
///
/// More detail <see href="http://answers.unity3d.com/questions/596671/circular-rotation-via-the-mathematical-circle-equa.html">here</see>
/// </summary>
public class Rotator : MonoBehaviour {

    # region ATTRIBUTES
   
    // UI component's instant 2D coordinates :
    public float X { get; private set; }
    public float Y { get; private set; }

    // orbit center 2D coordinates:
    public float orbitCentreX;
    public float orbitCentreY;

    // positional angle, in degrees:
    private float theta;

    // time to complete a full revolution, in seconds:
    [Range((float)1, 35)]
    public float rotationTime;
    private float period;

    // circle radius:
    private float radius;

    // Rotation direction:
    public bool isClockwise;

    #endregion ATTRIBUTES

    #region METHODS

    #region Start() bloc

    void Start () {
        this.X = this.transform.localPosition.x;
        this.Y = this.transform.localPosition.y;

        this.period = getPeriod();
        this.radius = getRadius();
        this.theta = getTheta();

        // DEBUG:
        //print(this + "-----> this.period=" + this.period + "\n");
        //print(this + "-----> this.radius=" + this.radius + "\n");
        //print(this + "-----> this.theta=" + this.theta + "\n");

    }

    /*
     * Returns the the time of a rotation in seconds.
     */
    private float getPeriod()
    {
        // T=2*PI*f and f=1/rotationTime
        // so one rotation is completed in 'rotationTime' seconds:
        return (2 * Mathf.PI) / rotationTime;
    }

    /*
     * Returns the radius of the trajectory (Pythagoras' formula).
     */
    private float getRadius()
    {
        float a = orbitCentreX - X;
        float b = orbitCentreY - Y;

        return Mathf.Sqrt(a*a + b*b);
    }

    /*
     * Returns the UI component's instant positional angle.
     */
    private float getTheta()
    {
        return Mathf.Atan2(
                        Y - orbitCentreY,
                        X - orbitCentreX);
    }

    #endregion Start() bloc

    #region Update() bloc

    void Update () {
        updatePosition();
        this.period = getPeriod();
        updateTheta();
    }

    /*
     * Updates this script's internal (x,y) coordinates and moves the GameObject
     * in the 2D plane accordingly:
     */
    private void updatePosition()
    {
       
        X = orbitCentreX + (radius * Mathf.Cos(theta));
        Y = orbitCentreY + (radius * Mathf.Sin(theta));

        transform.localPosition = new Vector3(X, Y, 0);
    }

    /*
     * Returns the next rotational angle in degrees.
     */
    private void updateTheta()
    {
        theta = isClockwise ?
                    theta - (period * Time.deltaTime) % 360 :
                    theta + (period * Time.deltaTime) % 360;
    }

    #endregion Update() bloc

    #endregion METHODS
}

Any comments or improvement suggestion more than welcome :slight_smile: