1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Unityでオリジナルのロードスピナーを作る

Posted at

はじめに

UnityのUIは通常、Image や Text といった標準コンポーネントを使うことが多いですが、Graphic を継承することで自作の図形を描画することもできます。
今回、UI上に円を描き、その円を組み合わせて「ロード中アニメーション風のスピナー」を実装しました。

完成イメージ

実行すると、UIキャンバス上に複数の円が並び、それぞれが拡縮しながら回転運動しているように見せます。
無題の動画 ‐ Clipchampで作成.gif

手順

  1. Unityでプロジェクトを用意する
  2. Unityで新規プロジェクトを作成
  3. Hierarchy に Canvas を作成(UI → Canvas)
  4. その下に Empty GameObject を作成
  5. 作成したGameObjectにスクリプト「Spinner」をアタッチ
    (Circle.csはSpinner.csから呼ばれます)

コード

Spinner.cs:円を組み合わせてアニメーション

次に、複数の円を組み合わせてスピナーを構成します。
次に、複数の円を生成して動かすスクリプトです。
中央の円がぐるぐると回り、全体として「ロード中アニメーション」風に見える

役割

  • Start() で複数の円を円形に一定間隔で配置
  • Update() で時間経過に応じて大きさや位置をアニメーション
  • main_circle は円周上をぐるぐる回る

アニメーションの仕組み

  • circle_list[i].radius を時間依存の Cos 関数で変化 → 円が「膨らんだり縮んだり」する
  • main_circle は円周上を回転運動する
Spinner.cs
using UnityEngine;

[RequireComponent(typeof(CanvasRenderer))]
// このコンポーネントをアタッチするGameObjectには必ずCanvasRendererを付けるよう指定
// → UI上に描画するために必須の仕組み

public class Spinner : MonoBehaviour
{
    public int numCircle = 8; // 円の数。Inspectorから編集可能
    public float radius = 100; // 円を配置する半径

    Circle[] circle_list;
    Circle main_circle;
    float time;
    float sectorAngle;

    void Start()
    {
        circle_list = new Circle[numCircle];

        // メインの円を生成して配置
        main_circle = MakeCircleObject(new Vector2(radius, 0));
        main_circle.radius = 20;

        // 各小円を円周上に配置する
        sectorAngle = 2f * Mathf.PI / numCircle;
        for (int i = 0; i < numCircle; i++)
            circle_list[i] = MakeCircleObject(new Vector2(radius * Mathf.Cos(sectorAngle * i), radius * Mathf.Sin(sectorAngle * i)));
    }

    Circle MakeCircleObject(Vector2 position)
    {
        var gameObject = new GameObject("circle");
        gameObject.transform.parent = this.transform; // Spinnerオブジェクトを親に設定
        var circle = gameObject.AddComponent<Circle>();
        circle.radius = 0;
        circle.numDivisions = 100; // 円を分割する数(100なら滑らかな円)
        circle.SetPosition(position);

        return circle;
    }

    void Update()
    {
        time += Time.deltaTime;

        for (int i = 0; i < numCircle; i++)
        {
            float rad = (float)((2 * time + 0.5 * i * sectorAngle) % Mathf.PI);
            // cos波を利用して円の半径を拡縮させる
            circle_list[i].radius = (float)(10 * (Mathf.Cos(rad) + 1)); 
            // 半径を変更したので再描画をリクエスト
            circle_list[i].SetVerticesDirty();
        }

        // メインの円を時間に応じて円軌道上に移動
        main_circle.SetPosition(new Vector2(radius * Mathf.Sin(4 * time + Mathf.PI / 2), radius * Mathf.Cos(4 * time + Mathf.PI / 2)));
    }
}

Circle.cs:UIに円を描くクラス

まずは「円を描画する」クラスです。このクラスを使うことで、UIキャンバス上に円を描画できます。

ポイント

  • UnityEngine.UI.Graphic を継承し、OnPopulateMesh をオーバーライド
  • 頂点(Vertex)を放射状に配置し、三角形でつなぐことにより円を表現
  • numDivisions の数を増やすほど滑らかな円になる
  • SetPosition でUI座標上に配置を制御できる
Circle.cs
using UnityEngine;
using UnityEngine.UI;

[RequireComponent(typeof(CanvasRenderer))]
// このコンポーネントをアタッチするGameObjectには必ずCanvasRendererを付けるよう指定
// → UI上に描画するために必須の仕組み

public class Circle : Graphic
{
    public float radius = 100; // 円の半径
    public int numDivisions = 8; // 円周をいくつの分割で近似するか(多いほど滑らかになる)

    protected override void OnPopulateMesh(VertexHelper vh)
    {
        vh.Clear();

        // 円周を numDivisions 個に分割した角度を計算
        float sectorAngle = 2f * Mathf.PI / numDivisions;

        var center_position = Vector2.zero;

        // 頂点0番目として円の中心点を追加
        vh.AddVert(new UIVertex
        {
            position = center_position,
            color = this.color
        });

        // 円周上の分割点を順番に計算
        for (int i = 0; i < numDivisions; i++)
        {
            var vertex = new UIVertex
            {
                position = center_position + new Vector2(radius * Mathf.Cos(sectorAngle * i), radius * Mathf.Sin(sectorAngle * i)),
                color = this.color
            };

            vh.AddVert(vertex);
        }
        // 三角形を順番に作る
        for (int i = 0; i < numDivisions; i++)
        {
            vh.AddTriangle(0, (i + 1) % numDivisions + 1, i % numDivisions + 1);
        }
    }

    public void SetPosition(Vector2 position)
    // 円をUI座標上に配置する
    {
        this.rectTransform.anchoredPosition = position;
    }
}

まとめ

Graphic を継承すれば、Unity UI 上に自由な図形を描けることが分かりました。円を組み合わせて動かすことで、独自のスピナーアニメーションを実現できます。

1
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?