はじめに
UnityのUIは通常、Image や Text といった標準コンポーネントを使うことが多いですが、Graphic を継承することで自作の図形を描画することもできます。
今回、UI上に円を描き、その円を組み合わせて「ロード中アニメーション風のスピナー」を実装しました。
完成イメージ
実行すると、UIキャンバス上に複数の円が並び、それぞれが拡縮しながら回転運動しているように見せます。
手順
- Unityでプロジェクトを用意する
- Unityで新規プロジェクトを作成
- Hierarchy に Canvas を作成(UI → Canvas)
- その下に Empty GameObject を作成
- 作成した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 上に自由な図形を描けることが分かりました。円を組み合わせて動かすことで、独自のスピナーアニメーションを実現できます。