この記事は、「アンリアルクエスト5に挑戦! 初級・中級解説編」の続きです。初級・中級の解説を見たい方はリンクより前記事を参照してみてください。
2日目上級クエスト「敵の攻撃を弾く仕組みを作ろう」
2日目初級の上級クエストは「敵の攻撃を弾く仕組みを作ろう」でした。クエスト発表時には「敵の攻撃モーションは剣を振り下ろす直前に一瞬止まるタイミングがあるので、その時にプレイヤーの攻撃を当てたら敵の攻撃がキャンセルされるように」という解説があったので、それをそのまま実装していきたいと思います。
なお、前回同様ですが分かりやすさを優先する為、アンリアルクエスト5用のプロジェクトを一旦リセットした状態(プロジェクトデータの配布状態)からの実装を前提に解説していきます。
重要なのは敵の攻撃アニメーションのタイミングを取得すること
敵の攻撃アニメーションの中から、剣を振り上げて一瞬止まるタイミングさえ取得できれば、今回のクエストはそれほど難しくはありません。
アニメーションのタイミングは「AnimNotify」「AnimNotifyState」を使用します。AnimNotifyはアニメーションの中の1コマのタイミングをピンポイントで取得する場合に、AnimNotifyStateはアニメーションのあるコマからあるコマまでのタイミングを取得する場合に使用します。
今回は敵が剣を振り上げて、振り下ろすまでのタイミングを取得したいので「AnimNotifyState」を使用してみましょう。
AnimNotifyStateを作成するには、コンテンツドロワー上で右クリックし、ブループリントクラスを新規作成します。”すべてのクラス”を選択し”AnimNotifyState”と入力すると、AnimNotifyStateを新規で作成することができます。名前は”ANS_ParryTiming”としておきます。


作成したら、ダブルクリックで編集してみましょう。

こんな画面が表示されたら右側の「マイブループリント」の「関数」にカーソルを合わせると「オーバーライド」というドロップダウンが表示されるので、それをクリックします。

ここに表示されている”Received Notify Begin”で敵が剣を振り上げた時の処理を、”Received Notify End”で敵が剣を振り下ろす直前の処理を記述しますが、アニメーションと絡めて話しをしないと分かりにくいと思いますので、まずはこれらの名前だけ覚えておいてください。
ということで、敵の攻撃アニメーションモンタージュファイルを開いてみます。場所は/UnrealQuest5/Characters/Mannequins/Animations/UQ5配下の”AM_Enemy_Attack01″ですね。

開くと敵が刀で攻撃してくるアニメーションが表示されます。画面下側にある一時停止ボタンをクリックしてアニメーションを止めてみましょう。
アニメーションを一時停止した状態で、画面中央より少し下あたりにある赤いスライダーを左右に動かしてみると、攻撃アニメーションをコマ送りすることができます。コマ送りしながら、敵が剣を振り上げた瞬間にスライダーを移動させてください。

そこで、画面中央下部のタイムラインで、左側にある「通知」の下にある「1」と書いてある行と、現在コマ送りで止めているスライダーの交わる部分で右クリックして「通知ステートを追加」から「ANS_ParryTiming」を選択してください。

すると、「通知」の「1」の行と、タイミングの行に何かが追加されました。「通知」の「1」行に追加されたANS_ParryTimingというバーは伸縮可能な為、赤いスライダーを動かしながら敵が剣を振り下ろすタイミングを探ってみて、そこまでバーを伸ばしてみてください。

こんな感じになればOKです。
次に、敵キャラクターのBP(BP_UQ5_Enemy)を開き、攻撃が弾かれてしまうタイミングを判断する為の変数を追加します。タイミングを判断するだけなので、Boolean型で”IsParryTiming”としました。

ここまで来れば何をしたいか分かってくるかと思います。
敵の攻撃アニメーションで剣を振り上げたら敵BPの”IsParryTiming”にTrueを設定し、剣を振り下ろしたタイミングでFalseを設定します。”IsParryTiming”がTrueの時にプレイヤーの攻撃が当たった場合は、攻撃を弾かれたアニメーションを再生するだけで実装は完了です。
ということで、攻撃アニメーションと”IsParryTiming”を紐づける処理をANS_ParryTimingの”Received Notify Begin”と”Received Notify End”に書いていきましょう。
先ほど解説したオーバーライドから”Received Notify Begin”を選択すると、以下のようなイベントグラフが表示されます。

こでは剣を振り上げたタイミングで呼ばれる処理なので、敵BPの”IsParryTiming”にTrueを入れる処理を書きます。Received Notify BeginのMeshCompは敵キャラクターのスケルタルメッシュなので、そこからGetOwnerでBP_UQ5_Enemyを取得します。これをBP_UQ5_Emenyにキャストし、先ほど定義した”IsParryTiming”にTrueを設定して処理を終わります。

次に”Received Notify End”を書いていきますが、”Received Notify Begin”との違いは”IsParryTiming”をFalseにするだけです。

最後にプレイヤーの攻撃処理と、敵が攻撃を受けた場合の処理を実装する必要がありますが、これは初級・中級の解説編や1日目上級編でも解説しているので、詳細は割愛します。(一応、プレイヤーのBPは貼り付けておきます)

なお、今回の解説では敵はHPを持っていないし死ぬ処理も書かない為、敵BPの処理については一旦AnyDamageのみとします。

あ、、、攻撃を弾かれた際のアニメーションを忘れていました。アンリアルクエスト5では攻撃弾かれアニメーションもアセットとして提供されていたので、それを使いましょう。
“AS_GotParried”からアニメーションモンタージュを作成し、名前は”AM_GotParried”にします。

敵BPに戻り、AnyDamageの処理を以下のように書きます。とは言っても単純に”IsParryTiming”がTrueの場合は、先ほど作成した弾かれアニメーションモンタージュを再生するだけです。(今回の解説は弾かれる実装に特化している為、通常の攻撃が当たる処理については解説していません)

これで実装完了です。
敵の攻撃を弾くことができました。これだと少し寂しいので、エフェクトを入れてみましょう。
エフェクトの為に新規でNiagaraを作成します。コンテンツドロワー上で右クリックし、FXから「Niagaraシステム」選択してください。

「選択したエミッタに基づく新しいシステム」を選択。

「OmnidirectionalBurst」を選択した状態でプラスボタンを押し、終了をクリックしてください。

名前は”NS_ParryAttack”としました。

編集すると以下の画面が表示されます。

OmnidirectionalBurstの”Initialize Particle”を選択し、PointAttributesのColorModeのColorを赤っぽい色にしてください。(どこか分からなければやらなくても大丈夫です)

敵BPに戻って、弾かれアニメーションの後に作成したナイアガラを表示します。表示位置は剣の座標としましたので、こんな感じになります。

これで完成です。見てみましょう。
これで、2日目の上級クエストの解説は終了します。アニメーションから必要なタイミングを取得して処理に反映するという実装方法が理解できたかと思います。
No responses yet