MRが楽しい

MRやVRについて学習したことを書き残す

UniTaskを使って徐々に変化するゲージバーを作成する

本日はUniTaskの小ネタ枠です。
UniTaskを使って徐々に変化するゲージバーを作成する方法を記事に残します。

前回記事

今回は以下の前回記事で作成したゲージバーのサンプルシーンを利用します。
bluebirdofoz.hatenablog.com

UniTaskの環境構築手順は以下を参照ください。
bluebirdofoz.hatenablog.com

UniTask.Yield

UniTaskが戻り値の関数であればUniTask.Yieldを使ってフレーム待機することができます。
これを使って関数内で簡単にフレーム待機の処理を制御できます。

public async UniTask WaitFrame()
{
    // 現在のフレーム番号を取得する
    var startFrame = Time.frameCount;

    // 1フレームだけ待機する
    await UniTask.Yield(PlayerLoopTiming.Update, new CancellationToken());

    // 経過フレームを表示する
    Debug.Log($"現在の経過フレーム:{Time.frameCount - startFrame}");
}

サンプルスクリプト

前回作成したスクリプトを改修して増加関数を呼び出すとゲージを少しずつ増加させるようにしました。
・SmoothStretchGaugeTest.cs

using System.Threading;
using Cysharp.Threading.Tasks;
using UnityEngine;

public class SmoothStretchGaugeTest : MonoBehaviour
{
    /// <summary>
    /// 全体のサイズ
    /// </summary>
    [SerializeField] private RectTransform _totalRectTransform;
    
    /// <summary>
    /// 青ゲージ
    /// </summary>
    [SerializeField] private RectTransform _blueRectTransform;

    /// <summary>
    /// 赤ゲージ
    /// </summary>
    [SerializeField] private RectTransform _redRectTransform;

    /// <summary>
    /// 現在の青ゲージの比率
    /// </summary>
    [SerializeField] private float _currentBlueRatio = 0.0f;

    /// <summary>
    /// アニメーションの排他制御
    /// </summary>
    private SemaphoreSlim _semaphoreSlim = new (1,1);

    void Start()
    {
        ChangeGauge(_currentBlueRatio);
    }
    
    [ContextMenu("IncrementGauge")]
    public void IncrementGauge()
    {
        var nextRatio = _currentBlueRatio + 10;
        if (nextRatio > 100)
        {
            nextRatio = 100;
        }

        ChangeGaugeAnimationAsync((int)nextRatio).Forget();
    }

    public async UniTask ChangeGaugeAnimationAsync(
        int changeRatio,
        float tweenTime = 1.0f)
    {
        float animationTime = 0;

        // アニメーション中は排他制御を行い、アニメーションが終わるまで待機する
        await _semaphoreSlim.WaitAsync();

        var animationStartRatio = _currentBlueRatio;
        var animationEndRatio = changeRatio;

        while (animationTime < tweenTime)
        {
            // ゲージを徐々に変化させる
            animationTime += Time.deltaTime;
            var progressRatio = (int)Mathf.Lerp(animationStartRatio, animationEndRatio,
                animationTime / tweenTime);
            ChangeGauge(progressRatio);
            await UniTask.Yield();
        }

        ChangeGauge(animationEndRatio);
        _currentBlueRatio = changeRatio;
        
        // アニメーションが終わったら排他制御を解除する
        _semaphoreSlim.Release();
    }

    private void ChangeGauge(float blueRatio)
    {
        var totalGaugeWidth = _totalRectTransform.rect.width;
        var blueGaugeWidth = totalGaugeWidth * blueRatio / 100.0f;
        var redGaugeWidth = totalGaugeWidth - blueGaugeWidth;
        
        _blueRectTransform.offsetMin = new Vector2(0, 0);
        _blueRectTransform.offsetMax = new Vector2(-1.0f * redGaugeWidth, 0);

        _redRectTransform.offsetMin = new Vector2(blueGaugeWidth, 0);
        _redRectTransform.offsetMax = new Vector2(0, 0);
    }
}

シーンを再生してIncrementGauge関数を呼び出します。

フレームに合わせてゲージが増加することでスムーズにゲージが変化します。