何らかの処理でユーザーを待たせる場合は、プログレスバーやローディングアニメーションを表示することが有効です。
今回はローディングアニメーションについて、UnityのDOTweenを用いていくつか実装してみました。
DOTweenはUnityのAssetStoreで入手できる無料のアセットです。
何かと便利になっている有料版もありますが、まずは無料版でも全く問題ないと思います。
(個人的には有料版がおすすめですが)
多くの種類が考えられるので、今回は円を用いたローディングアニメーションのみとしました。
後日【円編】以外も記事にするかもしれません。
円を用いたローディングアニメーション一覧
今回はこの8つを作ってみました。

似たようなものもありますが、どれも円のみを用いたローディングアニメーションです。
ひとつずつコードを紹介していきます。
最初の例でUnity上での使用方法を簡単に説明しています。
それ以降のアニメーションでも同様に行ってください。
ぐるぐる回るアニメーション

8つの円が円形に並んでいて、順番にフェードしていくアニメーション。
最もローディングアニメーションらしいアニメーションと言っても良いかもしれません。
コードはこちら。
using UnityEngine; using UnityEngine.UI; using DG.Tweening; public class LoadingAnimPlayer : MonoBehaviour { private const float DURATION = 1f; void Start() { Image[] circles = GetComponentsInChildren(); for (var i = 0; i < circles.Length; i++) { var angle = -2 * Mathf.PI * i / circles.Length; circles[i].rectTransform.anchoredPosition = new Vector2(Mathf.Cos(angle), Mathf.Sin(angle)) * 50f; circles[i].DOFade(0f, DURATION).SetLoops(-1, LoopType.Yoyo).SetDelay(DURATION * i / circles.Length); } } }
このスクリプトを親オブジェクトにアタッチし、その子オブジェクトに円のImageを8つ置いておきます。

円のImageは適当に配置しておいて大丈夫です。
スクリプト内で初期配置するようにしています。
今回は円のImageを事前に生成しておく方法をとりましたが、Imageの生成もスクリプト内でやってしまっても良いかもしれません。
あとはエディタ実行するだけで、ローディングアニメーションが再生されます。
ちなみに円の数は8つではなくても可能です。
これ以降のアニメーションも、自由に子オプジェクトの数を変えられるものがほとんどです。
横並びで順番に跳ねるアニメーション

コードはこちら。
using UnityEngine; using UnityEngine.UI; using DG.Tweening; public class LoadingAnimPlayer : MonoBehaviour { private const float DURATION = 1f; void Start() { Image[] circles = GetComponentsInChildren(); for (var i = 0; i < circles.Length; i++) { circles[i].rectTransform.anchoredPosition = new Vector2((i - circles.Length / 2) * 50f, 0); Sequence sequence = DOTween.Sequence() .SetLoops(-1, LoopType.Restart) .SetDelay((DURATION / 2) * ((float)i / circles.Length)) .Append(circles[i].rectTransform.DOAnchorPosY(30f, DURATION / 4)) .Append(circles[i].rectTransform.DOAnchorPosY(0f, DURATION / 4)) .AppendInterval((DURATION / 2) * ((float)(1 - i) / circles.Length)); sequence.Play(); } } }
広がって回って集まるアニメーション

コードはこちら。
using UnityEngine; using UnityEngine.UI; using DG.Tweening; public class LoadingAnimPlayer : MonoBehaviour { private const float DURATION = 0.5f; void Start() { Image[] circles = GetComponentsInChildren(); for (var i = 0; i < circles.Length; i++) { var angle = -2 * Mathf.PI * i / circles.Length; circles[i].rectTransform.anchoredPosition = Vector2.zero; Sequence sequence = DOTween.Sequence() .SetLoops(-1, LoopType.Yoyo) .AppendInterval(DURATION / 4) .Append(circles[i].rectTransform.DOAnchorPos(new Vector2(Mathf.Cos(angle), Mathf.Sin(angle)) * 50f, DURATION / 2)) .AppendInterval(DURATION / 4); sequence.Play(); } Sequence sequenceParent = DOTween.Sequence() .SetLoops(-1, LoopType.Incremental) .Append(transform.DOLocalRotate(Vector3.forward * (180f / circles.Length), DURATION / 4)) .AppendInterval(DURATION / 2) .Append(transform.DOLocalRotate(Vector3.forward * (180f / circles.Length), DURATION / 4)); sequenceParent.Play(); } }
横並びで順番に拡大縮小するアニメーション

コードはこちら。
using UnityEngine; using UnityEngine.UI; using DG.Tweening; public class LoadingAnimPlayer : MonoBehaviour { private const float DURATION = 1f; void Start() { Image[] circles = GetComponentsInChildren(); for (var i = 0; i < circles.Length; i++) { circles[i].rectTransform.anchoredPosition = new Vector2((i - circles.Length / 2) * 50f, 0); Sequence sequence = DOTween.Sequence() .SetLoops(-1, LoopType.Restart) .SetDelay((DURATION / 2) * ((float)i / circles.Length)) .Append(circles[i].rectTransform.DOScale(1.5f, DURATION / 4)) .Append(circles[i].rectTransform.DOScale(1f, DURATION / 4)) .AppendInterval((DURATION / 2) * ((float)(1 - i) / circles.Length)); sequence.Play(); } } }
横並びで順番にフェードするアニメーション

コードはこちら。
using UnityEngine; using UnityEngine.UI; using DG.Tweening; public class LoadingAnimPlayer : MonoBehaviour { private const float DURATION = 1f; void Start() { Image[] circles = GetComponentsInChildren(); for (var i = 0; i < circles.Length; i++) { circles[i].rectTransform.anchoredPosition = new Vector2((i - circles.Length / 2) * 50f, 0); Sequence sequence = DOTween.Sequence() .SetLoops(-1, LoopType.Restart) .SetDelay((DURATION / 2) * ((float)i / circles.Length)) .Append(circles[i].DOFade(0f, DURATION / 4)) .Append(circles[i].DOFade(1f, DURATION / 4)) .AppendInterval((DURATION / 2) * ((float)(1 - i) / circles.Length)); sequence.Play(); } } }
回転してフェードするアニメーション

コードはこちら。
using UnityEngine; using UnityEngine.UI; using DG.Tweening; public class LoadingAnimPlayer : MonoBehaviour { private const float DURATION = 0.5f; void Start() { Image[] circles = GetComponentsInChildren(); for (var i = 0; i < circles.Length; i++) { var angle = 2 * Mathf.PI * i / circles.Length; circles[i].rectTransform.anchoredPosition = new Vector2(Mathf.Cos(angle), Mathf.Sin(angle)) * 50f; Sequence sequence = DOTween.Sequence() .SetLoops(-1, LoopType.Yoyo) .AppendInterval(DURATION / 4) .Append(circles[i].DOFade(0f, DURATION / 2)) .AppendInterval(DURATION / 4); sequence.Play(); } Sequence sequenceParent = DOTween.Sequence() .SetLoops(-1, LoopType.Incremental) .Append(transform.DOLocalRotate(Vector3.forward * (360f / circles.Length), DURATION / 4)) .AppendInterval(DURATION / 2) .Append(transform.DOLocalRotate(Vector3.forward * (360f / circles.Length), DURATION / 4)); sequenceParent.Play(); } }
格子状に並んだ円がランダムフェードするアニメーション

コードはこちら。
using UnityEngine; using UnityEngine.UI; using DG.Tweening; public class LoadingAnimPlayer : MonoBehaviour { private const float DURATION = 1f; void Start() { Image[] circles = GetComponentsInChildren(); var size = (int)Mathf.Sqrt(circles.Length); for (var i = 0; i < circles.Length; i++) { var x = i % size - (float)(size - 1) / 2; var y = (int)(i / size) - (float)(size - 1) / 2; circles[i].rectTransform.anchoredPosition += new Vector2(x, y) * 50f; circles[i].DOFade(0f, DURATION / 2).SetLoops(-1, LoopType.Yoyo).SetDelay(Random.Range(0f, DURATION)); } } }
このアニメーションに関しては、円の数は4、9、16・・・などn^2個だときれいに見えると思います。
3D空間を回転するアニメーション

コードはこちら。
using UnityEngine; using UnityEngine.UI; using DG.Tweening; public class LoadingAnimPlayer : MonoBehaviour { private const float DURATION = 1f; void Start() { Image[] circles = GetComponentsInChildren(); for (var i = 0; i < circles.Length; i++) { var angle = 2 * Mathf.PI * i / circles.Length; circles[i].rectTransform.anchoredPosition3D = new Vector3(Mathf.Sin(angle), 0, Mathf.Cos(angle)) * 50f; circles[i].rectTransform.DOLocalRotate(-Vector3.up * (360f / circles.Length), DURATION).SetLoops(-1); circles[i].color = new Color(1f, 1f, 1f, 0.7f); } GetComponent ().DOLocalRotate(Vector3.up * (360f / circles.Length), DURATION).SetLoops(-1); } }
3D空間上のY軸を中心に回っているような感じのアニメーションです。
3つが一番きれいに見える気がします。
まとめ
円のみを使ったローディングアニメーションの例と、UnityのDOTweenを使った実装方法を紹介しました。
いろいろとカスタマイズ可能なので、そのゲームに合ったローディングアニメーションに作り変えたりしてみても良いのではないでしょうか。
コメント