PaperSloth’s diary

主にゲーム開発関連についての記事を書きます。

UE4 ダメージの差分だけ徐々に減るHPゲージの実装

環境

UE4.25.3

概要

こういうやつを作ります
(録画に失敗して緑のノイズが入っちゃいましたが、イメージは伝わるかと)
f:id:PaperSloth:20200924200027g:plain

HPゲージの実装方法については前々回の記事を参照いただければです。
papersloth.hatenablog.com

Widgetの実装

Materialを使ってメインカラー、差分ダメージカラーを表現することも可能ですが
今回は一番実装が楽な「Progress Bar」を2つ使う方法で実装していきます。

Widgetを開いて前面の緑の「Progress Bar」と背景の赤い「Progress Bar」を用意します。
f:id:PaperSloth:20200924200350p:plain

前面の緑のProgress Bar「HPProgressBar」では背景が不要なので「Style -> Background Image -> Tint のAlpha(A)」を0.0にして
緑色にしたいので、「Fill Color and Opacity」を「0, 1, 0, 1」に設定します。
f:id:PaperSloth:20200924200632p:plain

続いて背景の赤いProgress Bar「DeltaHPProgressBar」では「Fill Color and Opacity」を「1, 0, 0, 1」に設定します。
f:id:PaperSloth:20200924200817p:plain

次にWidgetのBlueprint Graphに切り替えて
前面のProgress Bar更新用のイベント「UpdateProgress」と
背景のProgress Bar更新用のイベント「UpdateDeltaProgress」を用意します。
f:id:PaperSloth:20200924200931p:plain

HPを持ったキャラクターのBlueprintの実装

まずは変数を3つ用意します。
1. 最大HPを設定した「MaxHealth」
2. 差分HPを保持する「DeltaHealth」
3. 現在のHPを表す「Health」

今回の例では「MaxHealth」を「100」にしています。
f:id:PaperSloth:20200924201355p:plain
3つの変数にはそれぞれ同じ値を与えて初期化しますが
値を調整した時に都度全てを更新していては手間なので「MaxHealth」にだけ初期値を設定して
他の2つには同一の値で初期化するようにします。
f:id:PaperSloth:20200924201443p:plain

次にダメージ処理を組んでいきます。
解説に入る前に全体像を貼っておきます。
なお、今回はノード量が多くなったため、本質とは関係ない敵のHPが0になった時の死亡処理は省いてあります。
f:id:PaperSloth:20200924204455p:plain

ダメージ処理のほとんどは前々回の記事で組んだものをそのまま流用して拡張してもらえれば早いですが
今回も同じように組んでいきます。

先ずは通常のダメージを受けた際の残りHPの計算と前面のProgress Barの更新処理です。
f:id:PaperSloth:20200924202150p:plain

現HPからダメージを引いて、最大HPからの割合を求めてProgress Barを更新しています。

次に差分ダメージのアニメーション処理を行いますが
処理が横長になってしまうため「Sequence」ノードを追加して下に流します。
あるいはCustom Eventを作成したり関数を作成して処理を分割するのもよいでしょう。
f:id:PaperSloth:20200924202422p:plain

アニメーションをさせるにあたって
最初に、ダメージアニメーションを開始するまで待つ処理を組みます。
これがないと以下のような挙動になってしまうためです。

以下の実装は2つ問題があります。
1. ダメージアニメーションがいきなり開始される
2. ダメージを受けた時に赤いバーが伸びている
f:id:PaperSloth:20200924202718g:plain

これら2つの問題を回避するため、ダメージアニメーション開始までの待ち時間を設けます。
新規に「AnimationWaitTime」という変数を追加します。
今は「1.0」を設定しているため、最後にダメージを受けてから1秒後にアニメーションが開始するようになります。
f:id:PaperSloth:20200924203005p:plain

続いて先程の「Sequence」ノードから「Retriggerable Delay」を呼び出します。
f:id:PaperSloth:20200924203049p:plain

通常のDelayノードでは攻撃が連続ヒットした場合に
最初にダメージを受けてから 1秒後にアニメーションが開始されてしまいます。
それを回避するため、呼び出される度にタイマーがリセットされる「Retriggerable Delay」を使用しています。
以下はDelayの場合の挙動
f:id:PaperSloth:20200924203415g:plain


次に実際のアニメーション処理です。
まずは「Timeline」ノードを追加します。
設定内容は「Length」が「1.0」で
Keyは2つ打って「Time/Value 0.0」と「Time/Value 1.0」です。
つまり、1秒間のアニメーション処理で値が0 から 1に増えるようなカーブを作成しています。
アニメーション時間を変更したい場合はLengthと2つ目のKeyのTimeを調整してやればよいです。
f:id:PaperSloth:20200924203611p:plain
f:id:PaperSloth:20200924203820p:plain


最後にこのタイムラインに沿って背景のProgress Barを更新するだけです。
f:id:PaperSloth:20200924204011p:plain

「Lerp(線形補間)」を使用しているため、タイムラインは0 - 1でアニメーションするように設定しました。
まずはLerpで「DeltaHealth」から「Health」に補間するようにしていますが
「DeltaHealth」にはダメージを受ける前のHPを設定しています。
ゲーム開始時であれば最大HPが、ダメージアニメーション終了後は残りHPをそれぞれセットしています。

あとは通常のHP同様に最大HPとの割合を求めてProgress Barに反映するだけです。

以上で最初に貼った完成イメージのような挙動が組めたのではないでしょうか。

まとめ

今回はダメージを受けてからTimelineによってアニメーションさせる方法でしたが
他にもTickとInterp Toを使用する方法など、いくつかありますが
個人的にはこの方法が特に管理しやすいと感じています。

アニメーション開始までの待ち時間(Animation Wait Time)と
アニメーション再生時間のTimelineの2つだけでそこそこ調整がしやすいためです。

以上です!