· 

【Unity】揺れる体力ゲージを作る

Last Updated  2025.04.11


 まず初めに。

 エルツの "ダメージを受けたら体力ゲージがパリンパリン割れる" という演出を再現しようとしたんですが…… 

 結構な時間や試行錯誤を経た末、今の自分には無理 という結論に至りました。

▲コレです
▲コレです

 そもそもゲージを3Dモデルで作ってないですし、作ったら作ったで細かく砕ける仕組みや方法を作るのが、自分の手に負えない難易度っぽいんですよね。

 

 砕ける2Dスプライトやエフェクトを用意し、それを現在のゲージ上部に表示することで疑似的に再現する方法も試みたのですが、イメージ通りにはなりませんでした。

 

 ここは一旦断念し、別のアプローチを考えます。

今回作りたいもの

 そして本題である ゲージが揺れる という演出。

 

 《閃サム》で、特定の技に採用されているのが印象的でした。

閃サムの体力ゲージが揺れる演出

 今回はこれを再現してみようと思います。

具体的な実装方法

 揺れに関しては詳しく解説されているサイトがありましたので、そちらを参考にさせて頂きました。いつもお世話になっております。

 

 

 今回は衝撃感が欲しいので、パーリンノイズを使います。


▼自分なりに咀嚼して実装してみたスクリプトサンプル

using System;// これがないと[Serializable]が通らない
using UnityEngine;

// 体力ゲージをパーリンノイズで揺らすスクリプト
public class GaugeShake : MonoBehaviour
{
    // パーリンノイズ情報を格納する構造体(struct)
    [Serializable]
    private struct ShakeInfo
    {
        // 振幅
        public float amplitude;
        // 振動の速さ
        public float speed;
        // パーリンノイズのオフセット
        public float offset;

        // 乱数のオフセット値を指定
        public void SetRandomOffset()
        {
            offset = UnityEngine.Random.Range(0f, 256f);
        }

        // 指定時刻のパーリンノイズ値を取得する
        public float GetValue(float time)
        {
            // ノイズ位置を計算
            var noisePos = speed * time + offset;

            // -1~1の範囲のノイズ値を取得
            var noiseValue = 2 * (Mathf.PerlinNoise(noisePos, 0) - 0.5f);

            // 振幅を掛けた値を返す
            return amplitude * noiseValue;
        }
    }

    // パーリンノイズのXYZ情報
    [Serializable]
    private struct NoiseTransform
    {
        public ShakeInfo x, y ,z;

        // xyz成分に乱数のオフセット値を指定する
        public void SetRandomOffset()
        {
            x.SetRandomOffset();
            y.SetRandomOffset();
            z.SetRandomOffset();
        }

        // 指定時刻のパーリンノイズ値を取得する
        public Vector3 GetValue(float time)
        {
            return new Vector3
            (
                x.GetValue(time),
                y.GetValue(time),
                z.GetValue(time)
            );
        }
    }

    // 位置の揺れ情報
    [SerializeField]
    private NoiseTransform _noisePosition;

    private RectTransform _rectTransform;
    private Vector3 _defaultPosition;// UIの初期位置

    [SerializeField]
    private float duration = 0.15f;// 揺らす時間(間隔)
    [SerializeField]
    private float _totalShakeTime; // 揺れ経過時間

    public bool _isShake;// 揺らすフラグ

    void Start()
    {
        _rectTransform = GetComponent<RectTransform>();

        // ゲージの初期位置を保持
        _defaultPosition = _rectTransform.anchoredPosition;
    }

    // 振動処理
    void Update()
    {
        if(!_isShake) return;// フラグが入ってないなら何もしない

        // 計測時間
        var time = Time.time;

        // パーリンノイズの値を計測時間から取得
        var noisePos = _noisePosition.GetValue(time);

        // 各RectTransformにパーリンノイズの値を加算
        _rectTransform.anchoredPosition = _defaultPosition + noisePos;

        // 振動した時間
        _totalShakeTime += Time.deltaTime;

        if (_totalShakeTime >= duration)// 揺らしたい時間が経過時間を超えたら
        {
            _isShake = false;
            _totalShakeTime = 0.0f;
            // 体力ゲージの位置を初期設定に戻す
            _rectTransform.anchoredPosition = _defaultPosition;
        }
    }
}

struct (ストラクト) とは

 

 今まで自分が触れて来なかった要素として《 struct 》が登場してます。

 データ構造を定義するための機能だそうです。

 ▼参考元


躓いたポイント

 UIを揺らす場合、インスペクター上のRectTransformの値は

 《 anchoredPosition 》になるので注意が必要です。

 ※参考サイト様のはオブジェクトを揺らしてるため、Transformの使用例です

  

 Transformで宣言しても取れるけど、色々弄るならちゃんとRect~で宣言しないと、UIの表示位置が思い通りにならなかったり赤エラーが出ます。

 

 この辺は Colliderの時の経験 が活きました。

 

 RectTransformは2種類あって、Position指定ではなく ”anchoredPosition で指定するのが重要なんですね。

  この辺に関しては、忘れないように別記事にまとめる予定です。

【今後の課題】

 今回のUIを揺らす運用だとZ軸の設定や定義は不要なんじゃないかと思ったり、揺れてる時間は一瞬なので、もう少し理解が深まったら削れる部分や直せる部分を改修予定です。揺れ幅も、小さくと大きくの2種類あるとよさそう?

ダメージを受けた際にスイッチが入るようにする

 小パン程度で揺れてると煩わしいですし、いざ揺れた時の印象も薄れてしまうので、一定値以上のダメージが発生したときのみ条件が入るようにしています。

public bool _isShake;// 揺らすかどうかのチェック

 これは外部スクリプトからもオンオフするので『public』とし、ダメージが発生した際にチェックが入るよう設定します。

動作確認

Unity 揺れる体力ゲージのサンプル

 引きの画像だと解り難かったのでゲージ部分を拡大。

 1回目と2回目で揺れの大きさも変わってますね。

【Unity】揺れる体力ゲージと遅れて追従するゲージのサンプル

 全体像。ジャンプ攻撃後のワンツーでは揺れなかったり、赤ゲージでヒットの継続、非継続が確認できるかと思います。

最後に

 ゲーム性とは直接関係ない部分ですし、かけた時間に見合う成果はあるのかと聞かれると難しいのですが、新しく覚えた要素や再確認出来た要素もあるので、個人的にはいい勉強になりました。

 

 断念した『パリンパリン演出』も、自分の力量が追いついたら再挑戦してみたいと思います。