UE4のアニメーションモンタージュを使ってコンボを実装してみる

## はじめに
この記事は[Unreal Engine 4 (UE4) その3 Advent Calendar 2020の8日目](https://qiita.com/advent-calendar/2020/ue4_tre)の記事です。

アドベントカレンダー初参加の
現在、絶賛UE4を勉強中のゲームプログラマーです。UE4タノシイ！

勉強の過程で、いわゆるコンボの実装を行うため、Animation Montage(アニメーションモンタージュ)という機能を利用しました。
そこで詰まってしまった所や、調べたことを共有して、もし同じような処理を組む方の参考にでもなればと思い、ここにやり方を記載させて頂きます。

## 前提
UE4バージョン 4.25.4
使用テンプレート Third Person

## 手順
* コンボ用のAnimation Sequenceの用意
* コンボ用のAnimation Montageを作成
    * Animation Montageに、Animation Sequenceを組み込む
    * Animation Montageに、Montage Sectionを追加する
    * Animation Montageに、通知処理を組み込む
* PlayerのBP改修
* Animation BluePrintの改修
    * Animation Montageからの通知を受け取り、Player BPへ流す
    * AnimGraphの調整

となります。では早速、やっていきます！

## コンボ用のAnimation Sequenceの用意
今回は、5つの剣攻撃アニメーション(Attack1～Attack5)をコンボさせてみようと思います。
以下の画像通り、5つのAnimation Sequenceを用意しました。
![0.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/12340/807c9d2f-75c8-d09e-0b53-bd1609d74814.png)

ここは各自好きなアニメーションを用意してください。

## コンボ用のAnimation Montageを作成
<b>Content Browserで右クリック→「Animation」→「Animation Montage」</b>で
対象のSkeletonを選択することで、アニメーションモンタージュを作成できます。

以下がアニメーションモンタージュのドキュメントになります。
https://docs.unrealengine.com/ja/Engine/Animation/AnimMontage/Creation/index.html

ここなのですが、少し画面のインターフェイスがドキュメントと異なり、自分も戸惑ったので、画面も添えて説明します。

### Animation Montageに、Animation Sequenceを組み込む
アニメーションモンタージュの画面を開いて、Asset BrowserからAnimation Sequenceを追加します。
今回はAttack1～Attack5のAnimation Sequenceを連続して配置します。
右下の「Asset Browser」からドラック＆ドロップで配置することができます。
![1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/12340/c7b23367-0393-b795-6f01-ae2d4c335e98.png)

### Animation Montageに、Montage Sectionを追加する
Montage Sectionと呼ばれるものを、アニメーションの好きなタイミングに入れることによって
BP上で「Montage Jump to Section」という関数を利用して、そのタイミングから、アニメーションを再生することができます。
ここは、利用するアニメーションによって、コンボ毎の適切なタイミングに仕込むことになります。

手順としては
<b>「Montage」のエリアの所で右クリック→「New Montage Section」→名前を入れる</b>
これによって、新しくMontage Sectionを追加することができます。

![2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/12340/4c6832bb-53a3-a937-3f7f-2a23b8f3d97b.png)
上図のように、Attack0～Attack4のMontage Sectionを、それぞれのアニメーションの再生開始位置に追加しました。
(名前と違って0から始まっていることに注意です)

この時に追加したMontage Sectionの名前は、上述の「Montage Jump to Section」で利用することになります。

その後、<b>Montage Sectionsのウィンドウを開き、Clear</b>を押しておきましょう。
これを押すと、それぞれのAttackアニメーションを分割して再生することができます。
逆に、Animation Sequenceをそのまま連続して、再生を行う場合は「Create Default」を押しておきます。

### Animation Montageに、通知処理を組み込む
続いて、アニメーションの特定タイミングで通知を飛ばすように設定していきます。
(ここが公式ドキュメントと微妙にインターフェイスが異なっていた所でした)

Notifiesの「▼」マークから「Add Notify Track」を押すことで、Notifyのトラックを追加することができます。
追加した、Notifiesトラックは、名前をクリックすることで、名前を変えることができます。
今回は、コンボのために以下のTrackを追加します。

<b>「NotifyActivateComboInTime」</b>
コンボを受け付ける、開始のタイミングを通知します。
コンボ受付中に、プレイヤーの入力があれば
そのときに再生している、Animation Sequenceの特定のタイミングで、指定したMontage Sectionへ再生を飛ばします。

<b>「NotifyDisActivateComboInTime」</b>
コンボの受付を終了するタイミングを通知します。
ユーザーがNotifyActivateComboInTime～NotifyDisActivateComboInTimeまでに
入力を行わなかった場合、次のアニメーションには繋げず、コンボはしない、ということです。

<b>「NotifyCheckJumpSection」</b>
コンボを受け付けたのかどうか、チェックするタイミングを通知します。
このタイミングで、コンボフラグが有効であれば、次のへアニメーションを飛ばして、コンボが繋がります。

Trackの追加が終わったら、それぞれのTrack上で<b>右クリック→Add Notify→New Notify</b>でNotifyを追加できます。
名前はTrackと同じ名前で良いでしょう。
それぞれのTrackにNotifyを追加していくと、下図のようになりました。

![3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/12340/afc7161a-ea6d-6f8f-be07-13b790366c43.png)
これでひとまず、アニメーションモンタージュの調整に関しては完了です！

## PlayerのBP改修
PlayerのBPを改修していきます。
(Third Parsonのテンプレートを利用している場合は、ThirdPersonCharacterがそのBPにあたります)

以下の変数を、コンボ用の変数として利用するので、追加しておきましょう。
isInvokeCombo...コンボ処理実行フラグ(bool)
isComboInTime...コンボ受付期間中フラグ(bool)
comboCount...現在のコンボカウント(int)

AttackSectionName...定数。今回の場合は「Attack」という文字列が入っています(string)

次に、上記で追記したそれぞれのNotifyが呼び出された時の処理を書いていきましょう。
### NotifyActivateComboTime(関数)
isComboInTimeをTrueにして、コンボを受付中とします
![5.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/12340/21194818-68ea-9258-6eb4-589938bfb526.png)

### NotifyDisactivateComboTime(関数)
isComboInTimeをFalseにして、コンボ受付期間を終了します
![4.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/12340/af949202-aa51-256f-5a9d-d1bc42e21a41.png)

### NotifyCheckJumpSection(関数)
各コンボのアニメーションを終了とさせたいタイミングで飛んできます。
![6.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/12340/3469b1c5-110e-41c6-e679-1c829c5e1a73.png)

isInvokeComboが呼ばれていない場合、コンボ処理は不要とされ、後述のEndCombo関数へ処理を流します。
逆にisInvokeComboが立っていた場合、コンボがユーザーによって行われたものとして
「Montage Jump to Section」を利用して、上記の作業で割り当てたMontage Sectionにアニメーションを飛ばすわけです。
Montage Jump to SectionMontageのMontage引数は、先程作成したアニメーションモンタージュを割り当ててください。

### ユーザーの攻撃ボタン押下時の通知処理(PlayerのBPのEvent Graph)
ユーザーが攻撃ボタンを押したタイミングで呼び出される処理になります。

![7.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/12340/e1353390-8003-35f6-2b36-fa0b3c7bcaf4.png)
comboCountが0のとき、まだ攻撃自体を開始していないものとして、上記で作成したコンボ用のAnimation Montageを再生します。

「Montage Play」関数になります。これを利用して、Animation Montageを再生することができます。
引数の「Montage to Play」には先程作成した、アニメーションモンタージュを割り当てます。

処理の流れとしては
コンボカウントが0を超えている
コンボカウントがMaxCombo(変数の一覧には記載していませんが、MaxComboは定数で、コンボの最大数が定義されています)を超えていない
コンボ受付期間中フラグ(isComboInTime)がTrue
の場合、コンボ処理実行フラグ(isInvokeCombo)をTrueにします。

※AttackRateは定数で、アニメーションのスピードが入っています。デフォルトは1です。

### EndCombo(関数)
![8.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/12340/593d7d8d-6447-0dc6-f3a6-3436ba20ae17.png)
コンボの終了時命令です。
今回の処理では変数をリセットしているだけになります。

以上でプレイヤーのBPの改修は終了です！

## Animation BluePrintの改修
最後に、プレイヤーのAnimation Blueprintを改修していきます。
(Third Parsonのテンプレートを利用している場合は、ThirdPerson_AnimBPがそのBPにあたります)

### Animation Montageからの通知を受け取り、Player BPへ流す
アニメーションモンタージュからの通知を受け付けて、Player BPへ命令が通知されるようにしましょう。
上記のアニメーションモンタージュの準備で追加した通知は、右クリックを押すと「AnimNotify～」という形で、出てくるようになっています。

![9.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/12340/5c2fe208-3e60-1ec1-e16b-cc03c3cd03f4.png)
BeginPlayで、ThirdPersonCharacterをキャッシュしておき、上記で記述した関数を呼び出していきます。

### AnimGraphの調整
最後にAnim Graphを開いて、<b>右クリック→「Slot 'Default Slot'」</b>を選んで、Default のStateとOutputPoseの間にはさみます。
ここは長くなるので細かいところは省きますが
DefaultSlotにアニメーションがある場合は、そちらを利用して、ない場合はDefault(State Machine)を利用する挙動になると思ってもらえればOKです。

![11.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/12340/4c3f6ea3-285f-dba3-e041-efc66ce69e48.png)

ここらへんなにかした記憶がないんだけど？となると思うのですが
作成したアニメーションモンタージュで、DefaultSlotがあらかじめ設定されている状態になっています。
![10.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/12340/f2093ecb-05c5-0a88-0743-12ebe7414b50.png)
以上でいざ、動かしてみると、無事にコンボの処理を組むことができました！
![preview.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/12340/d9c28edc-e202-7362-89db-f2ae2b34e633.gif)

## 終わり
以上、長々お付き合い頂きありがとうございました。

アニメーションモンタージュはとても多機能なようで、あくまで今回の使い方としては一例になると思います。
気になる方はぜひ調べてみて、シェアいただけるとうれしいです。

### 感謝

以下、今回の件とは関係ありませんが、アセット用意するにあたってのアニメーションのリターゲットやスケルトン管理方法など
UE4のアニメーションを勉強する際に参考になったリンクを挙げさせて頂きます。
https://www.slideshare.net/EpicGamesJapan/ue4animation-blueprint
https://www.slideshare.net/EpicGamesJapan/cedec2018-ue4-111104578

以上！