UE5でPaperZDを使ってHD2D風にキャラを歩かせたかった備忘録

目的

2Dスプライトキャラクターを、3D空間上で歩かせたかった。
PaperZDというプラグインの使い方を忘れそうなので残したかった。

注意

ほぼ全て下の動画で解説されている通り。

Cobra Code氏による超超ステキ動画。正直こちらの方がずっと分かりやすいのでこっち見た方が早い。全部英語だけど。

用意するもの

  • 歩行グラフィック画像
    今回は「やさぐれひよこ素材」置き場-CarasOhmi氏からひよこレディさんを使用した。
    できればひよこさんのように、グリッドできれいに分けられるようになっているもの(32×32、96×32とかで等分に分けられるもの)をおすすめする。
    今回は前後左右4方向にアニメーションするものを選んだが、8方向でも16方向でも大丈夫。

  • PaperZDプラグイン
    必須。EpicGamesマーケットプレイスのサイトからダウンロードしてくる。
    新たにUnrearEngineで新規プロジェクトを作成(既にプロジェクトがある場合はそれを開く)し、
    編集 → プラグインを選択する。検索バーに「PaperZD」を入力して、ダウンロードしたPaperZDにチェックを入れる。

「今すぐ再起動」をクリックしたら準備完了。

スプライトの作成

コンテンツドロワー上の適当な場所に、新たにフォルダを作成する。ここに用意した歩行グラフィック画像を入れる。

今回はHiyokoLadyフォルダにひよこレディさんのデータを入れた。

この歩行グラフィック画像を右クリックして、下画像のように「Paper2Dテクスチャ設定を適用」をクリックする。

そうしないとぼやけることがある。

ではこれを元にスプライトを抽出する。スプライトアクションタブ → スプライトを抽出 をクリックする。

すると新たなウィンドウが出てきて、スプライト抽出設定を行えるようになる。
設定プルダウンメニューからスプライト抽出モードグリッドに設定する。グリッドメニューが出てくるので、手持ちの画像に合わせてセルの幅、高さ、マージン等を設定する。

補足

冒頭でグリッドがきれいに分けられるような画像が望ましいとしたが、ここの設定が大幅に楽になるためである。

抽出ボタンを押せば完了。

これは任意だが、どのスプライトがどの動きに関わるのかに応じてフォルダ分けを行うと次からの作業がやりやすい。
例えばUp,Down,Left,Right等。斜め方向もある場合はフォルダが増えるけど、スプライトを探す手間が減る。
今回はUp,Down,Left,Right,Idle(上下左右)の5フォルダを作成し、スプライトを仕分けた。


アニメーション(フリップブック)設定

まずはDownから設定する。
Downフォルダ内のすべてのスプライトを選択し、右クリック → フリップブックを作成をクリック。わかりやすいように名前を付ける。
今回はFPLady_Downとした。

フリップブックを開くと、ひよこさんのアニメーションが見れる。が、違和感がすごい。

まず早すぎるので詳細タブからFrames Per Secondの数値を減らす。自分は8とした。
また、
右足を出す→何も出さない→左足を出す→右足を出す→何も出さない…
と動きが怪しいので、画面下部のタイムラインらしき部分でキーフレームの設定を行う。
「どちらの足も出さない」画像のキーフレームを右クリック→複製で増やす。増やした方のキーフレームを最後に持ってくると、きれいに歩いてくれる。


保存し、同じことを全ての方向について行う。


ブループリントの作成

適当なフォルダで右クリック → ブループリントクラスをクリック。

全てのクラスの検索バーにPaperZDと入力し、PaperZDCharacterを選択する。
これを開き、コンポーネントからSpriteを選択する。
右側の詳細タブにSource Flipbookという設定項目が出るので、これにIdleフリップブックを選択する。

次に、マテリアル設定項目のプルダウンを開き、下画像の歯車マークをクリックしてエンジンのコンテンツを表示にチェックを入れる。
この状態でMaskedLitSpriteMaterialを選択しよう。

次に、詳細タブの検索バーにshadowと入力する。するとCast Shadowという設定項目が一番上に表示されるので、チェックを入れる。

POINT

これでこのブループリントに設定したキャラクターはライティングの影響を受ける。具体的に言うとスプライトに影ができたりとか、日陰に入ると暗く見えたりだとかする。ちょっとおしゃれ。


キャラクターの大きさ設定

このままだとひよこレディさんがちょっと小さすぎるので、大きくする。この辺りは手持ちの画像にもよるので、いらなければすっ飛ばして構わない。

アニメーションに関わる全ての画像の大きさを編集したいので、次に示す方法を用いる。

画像赤丸部分をクリックし、スプライトでフィルタリングする。
続いて作成したフリップブックを全選択し、右クリック → アセットアクション → プロパティマトリクスで一斉編集を選択。

新たなウィンドウが開いたら、右上歯車マーク横の四角いマークを押す。これで選択対象を表示することができた。(最初から表示されている場合もあるかも)

選択対象をすべてアクティブにして、(全ての選択肢が青くなっていればOK)

Pixels per unitの項目の値を0.3にする。
これで全てのスプライトが約3.3倍の大きさになった。
ファイル → すべて保存をクリックし、ウィンドウを閉じてブループリントに戻ろう。


コリジョン設定・カメラ設定等

コンポーネントからCapsule Componentを選択し、詳細タブの形状タブ等からキャラクターに合わせてコリジョンを編集する。

お好みのコリジョンができたら、カメラ設定を行う。
Capsule Component選択状態で、コンポーネントタブから追加をクリックする。Spring Armを追加しよう。
今度はSpring Arm選択状態で、Cameraを追加する。

Spring Armの詳細タブの設定を行う。
ここからは個人の裁量によるが、参考がてら基準となりそうな値を記録しておく。

トランスフォームタブ、回転のZ軸に-90を、Y軸に-30を入力する。
カメラタブ、Target Arm Lengthの値を450くらいに設定する。

POINT

当たり前なことかもしれないが、回転はカメラ角を、Target Arm Lengthはプレイヤーとカメラとの距離を設定する要素。


入力設定

入力アクションの設定を行う。

コンテンツドロワー上で右クリックして、新たにInputフォルダを作成する。この中に入力アクション・マップ等の設定ファイルを格納する。

右クリック → 入力 → 入力アクションを選択(IAという)。IA_MoveLady(好きな名前でいい)と名付ける。
これを開き、ValueTypeAxis2D(Vector2D)とする。ジャンプさせたいとかだったらAxis3Dがいいかも。
一度これを閉じて、コンテンツドロワー上で右クリック → 入力 → 入力マッピングコンテキストを選択する(IMCという)。

適当に名前を付けてこれを開く。

Mappingsの隣にある+ボタンをクリックする。
「なし」となっているドロップダウンから、先ほど作った入力アクションファイルを選ぶ。
キーボードマークをクリックし、その後キーボードのWをタイプする。自動的にドロップダウンにWが当てはまったはず。
入力アクションを設定したドロップダウンの隣にある+ボタンをクリックし、同様にS、A、Dにも設定する。

  • Wの設定
    Modifiersの+ボタンをクリックし、エレメントを追加する。
    Swizzle Input Axis Valuesを選択する。

  • Sの設定
    Wと同じ要領でエレメントを2つ追加する。
    ひとつはSwizzle Input Axis Valuesを、もう一つはNegateを設定する。

  • Aの設定
    Negateのみを設定する。

  • Dの設定
    Modifiersにエレメントは追加しない。


入力イベントグラフの作成

再度キャラクターのブループリントを開き、イベントグラフモードに切り替える。
グラフ上で右クリックし、Get Controllerを呼び出す。
ここからリンクを伸ばし、Cast To PlayerControllerを接続する。
これをイベントBeginPlayと繋げ、さらにAs Player Controllerピンからリンクを伸ばしてEnhanced input Local Player Subsystemを接続する。ここからリンクを伸ばして、Add Mapping Contextを接続する。これとAs Player Controllerも接続する。


こんな感じ。
Add Mapping ContextノードのMapping Contextピンには、先に作ったIMCファイルを適用する。

歩行の設定を行う。
イベントグラフ上で右クリックし、先ほど作成した入力アクションを検索する。

こんな感じで「強化されたアクションイベント」の中にある方を使う。
ピンのうち、Action Valueのピンを右クリック→「構造体ピンを分割」をクリックする。XとYに分かれたと思う。
Triggeredピンからリンクを伸ばして、Add Movement Inputノードを接続する。Action Value Xピンと、Scale Valueピンとを接続する。また、World DirectionのX値を1.0とする。

コメント枠は置いといて現状こんな感じであればヨシ。

このAdd Movement Inputに、もうひとつAdd Movement Inputノードを接続する
このノードのScale Valueピンと、Action Value Yピンとを接続する。また、World DirectionのY値を-1.0(マイナス)とする

こうなっていればヨシ。

次に、変数タブ横の+ボタンをクリックし、変数を追加する。
名前をDirectionality、タイプをVector 2Dとする。これをドラッグ&ドロップしてSetで呼び出し、Add Movement Inputの続きとして接続する。
Directionalityピンを右クリックして、構造体ピンを分割する。先頭のノードのAction Value XとAction Value Yを、DirectionalityX、Yにそれぞれ接続する。


こうなっていればヨシ。


新たなゲームモードの作成と動作確認テスト

ここで一度ミスがないか確認のためにも動作テストを行う。

適当なフォルダで右クリック → ブループリントクラス → GameMode Baseを選択。名前をGM_Baseとする。

編集タブからプロジェクト設定を開き、マップ&モードの設定を開く。
ここのデフォルトのゲームモードを先ほど作ったGM_Baseに設定する。
また、Default Pawn Classについても、先ほど作ったキャラクターのブループリントを設定する。


BP_Ladyは自分が作ったひよこレディさんのブループリント。

ついでに、

  • 検索バーにアンチエイリアスと入力して、Default Settingsのアンチエイリアス手法をFXAAにする
  • 検索バーにMotion blurと入力して、モーションブラーのチェックを外す

といいらしい。なんでだろう。

設定を閉じ、レベル上で右クリック → アクタを配置 → PlayerStartを選択。一度動かしてみよう。

アニメーションはおかしいが、WASDで前後左右に動けていればOK

POINT

なんかおかしいかも!というときに確認してほしい項目
1.PlayerStartの詳細タブ内 トランスフォームの回転に角度が設定されていないか?→0,0,0と設定しよう
2.IMC(Imput Mapping Context)のWASD設定が違わないか?→実際ミスってたことが多い


歩行アニメーション設定

PaperZDを使う。
適当なフォルダで右クリック → PaperZD → AnimationSourceをクリック。

これを開き、AddNewボタンをクリックしてNew Animation Sequenceを選択。
まずはIdle状態から作成する。

右側のAssetDetailsタブ内のMulti-Directional Sequenceにチェックを入れる。

各方向で停止したときのアニメーション(静止状態だから動かないけど)が欲しいので、各方向の四角をクリックしてフリップブックを当てはめる。方向の数を増やしたい場合はNの値を変えよう。

AddボタンからNew Animation Sequenceをもう一度クリックし、Walkと名前を付けて、同様に各方向のフリップブックを当てはめる。

保存して一度アニメーションソース設定を閉じる。コンテンツドロワー内で右クリック → PaperZD → PaperZD AnimBPを選択する。先ほど作ったアニメーションソースブループリントを選択し、名前を付ける。

これを開いてコンパイル・保存したら、一度先ほどまで編集していたキャラクターブループリントを開き、Animation Componentを選択状態とする。

詳細タブ内のPaperZD内、Anim Instance Classに、先ほど作成したアニメーションブループリントを設定する。

再度アニメーションブループリントを開き、グラフリストからAnimGraphを選択する。

Output Animationと書かれた大きなノードが表示されたらOK。Resultピンからリンクを伸ばして、Set Directionalityを接続する。更に、Animationピンからリンクを伸ばしてPlay Walk(歩くアニメーション設定を行ったアニメーションシーケンス名)を接続する。

次にイベントグラフを開き、最初から配置されているイベント On Initノードからリンクを伸ばしてCast to (キャラクターブループリント名)を接続する。
ObjectピンにはGet Owning Actorノードを呼び出して接続する。
As (キャラクターブループリント名)ピンを右クリックして、変数に昇格する。(自分はこの変数の名前をBP Ladyに変更した。)


ひとまずこうなっていればヨシ。

AnimGraphに戻り、変数から先ほど作成した変数をGetで呼び出す。ドラッグ&ドロップするとやりやすい。
ここからリンクを伸ばして、Directionalityを取得する。これとSet DirectionalityのInputピンとを接続する。
Set DirectionalityノードのAnimationピンからリンクを伸ばして、Select Animation by Boolノードを接続する。True AnimationピンにはPlay Walkを、False AnimationピンにはPlay Idle(アイドル状態を設定したアニメーションの名前)を接続する。


POINT

ここに書いてあることを実装しても普通に動く。
しかし、壁に衝突したときにキャラクターが止まってしまう。キャラクターの停止をそこまで気にしない場合は、これを作成して終わり。
気にする場合は次の「壁に衝突したときの動き」を作る。

変数(ここで言うBP Lady)をGetで呼び出すかコピペして、ここからリンクを伸ばしてGet Velocityを接続する。さらにここからリンクを伸ばしてVector Lengthを接続し、Returun Valueピンにより大きい(>)ノードを接続する。
この右側の赤いピンと、Select Animation by BoolノードのSelect Valueピンとを接続する。True AnimationピンにはPlay Walkを、False AnimationピンにはPlay Idle(アイドル状態を設定したアニメーションの名前)ノードを接続する。

こうなっていればヨシ。


壁に衝突したときの動き

よくポケモン等で見る「壁にぶつかっている間も歩行アニメーションが再生され、アニメーションはゆっくりになり、ぶつかり音がする」処理を実装する。

再度キャラクターのブループリントのイベントグラフを開く。先頭ノードから新たにリンクを伸ばして別のノードを接続するので、気になる場合は作ってあったノードをまとめて右側にずらしておく。

変数タブ横の+ボタンから、変数を追加する。
名前をisHoldingMove、タイプをBooleanとする。
これを先頭ノード近くにSetで呼び出し、Startedピンに接続する。このノードのisHoldingMoveピンにはチェックを入れる

isHoldingMoveのセットノードをコピペして、もう一つ配置する。これをCompletedピンに接続して、isHoldingMoveピンのチェックは外す

こうなっていればヨシ。

またアニメーションブループリントに戻り、AnimGraphを編集する。
変数(ここで言うBP Lady)をGetで呼び出し、ここからリンクを伸ばして、isHoldingMoveをGetで呼び出して接続する。ここからリンクを伸ばして、Select Animation by BoolSelect Valueピンに接続する。


こうなっていればヨシ。

POINT

これでも正直違和感のない動きにはなるので、これでいい場合はここで終了にしても大丈夫。


歩行をゆっくりにする処理

ふたたびキャラクターのブループリントのイベントグラフに移る。
関数タブ横の+ボタンから関数を追加する。名前をisStuckとする。
詳細タブの純粋(Pure)にチェックを入れる。
アウトプット横の+ボタンを押してアウトプット引数を追加する。名前をisStuckとする。

変数タブ横+ボタンを押し、変数も追加する。
名前をStuchThreshold、タイプをFloatとする。
これを選択し、詳細タブのデフォルト値を50とする。

グラフ上を右クリックしてGet Velocityを呼び出し、ここからリンクを伸ばしてVector Lengthを接続する。
Vector LengthのReturn Valueピンからリンクを伸ばして、より少ない(<)ノードを接続する。
このノードの左下ピンに、StuckThresholdをドラッグ&ドロップで接続する。

今度はisHoldingMoveをGetで呼び出し、ここからリンクを伸ばしてAnd Booleanノードを接続する。
AndBooleanノードの左下ピンと、より少ないノードを接続する。AndBooleanノードと、リターンノードのisStuckピンとを接続する。


こうなっていればヨシ。

コンパイル・保存し、またアニメーションブループリントに戻る。
PlayWalkノードを選択状態とし、詳細タブのPlay Rate横のチェックボックスにチェックを入れる。
新たに生成されたPlay Rateピンからリンクを伸ばして、Select(選択する)ノードを接続する。
変数BPLadyをコピペして、ここからリンクを伸ばしてIs Stuckを呼び出す。これとselectノードの左下ピンとを接続する。

SelectノードのFalseには1.0を、Trueには0.4を入力する。


こうなっていればヨシ。


音を鳴らす処理

アニメーションソースを開き、Walkアニメーションをダブルクリックで開く。

これね。

アニメーションのタイムライン上の内、1の右横のエリアで右クリックし、

通知を追加・NewNotifyを選択。

名前をStuckSoundとする。

でてきたラベルを右クリックして、NotifyFrame1を入力する。(もとから入っているけど入力しなおした方がいいのかも)

これをコンパイル保存して、アニメーションブループリントに戻ると、関数にReceive Notify:StuckSoundが自動で作成されていることと思う。

これを開く。
先頭ノードからリンクを伸ばして、ブランチを接続する。
変数BPLadyをGetで呼び出し、ここからリンクを伸ばしてisStuckノードを接続する。isStuckピンとブランチのConditionピンとを接続する。
ブランチのTrueピンからリンクを伸ばしてPlay Sound at Locationを接続する。
BPLadyをコピペしてもう一つ配置し、そこからリンクを伸ばしてGet Actor Locationを接続。
これとPlay SoundノードのLocationピンとを接続する。
Soundピンには好きな効果音を入れる。

こうなっていればヨシ。


おまけ(ジャンプを入れる)


こちらのLearning Dev氏による動画を参考にジャンプ・着地アニメーションを作成した。Learning Dev氏も神。

補足

PeperZDやるならこの方の再生リストを総なめするのが手っ取り早いかも。

Walk等と同じ要領でJumpアニメーション、Jump入力アクションを作る。落ちる場合のアニメーションもあれば作っておく。入力マッピングコンテキストにもJump用のキーを追加する。

作れたらキャラクターのブループリントのイベントグラフを開き、Walkと同じ要領で次の画像のようにノードを配置する。

次にアニメーションブループリントのAnimGraphに移動し、Output AnimationのResultピンにStateMachineノードを繋げる。(今まで作ってきたノードも再利用するので残しておく。)

これをダブルクリックする。Outというノードからリンクを伸ばして、AnimationStateを選択。名前をIdle/Walkに変更する。

これをダブルクリックして表示されるOutput Animationノードに、今まで作ってきたAnimGraphのノードをコピペして接続する。

StateMachineに戻り、右クリックしてJumpノードを配置する。名前をInAirと変更し、同様にAnimationStateノードを接続する。Stateの名前はJumpingとする。
Jumpingからさらにリンクを伸ばして、もう一つAnimationStateノードを接続する。これでジャンプから別のアニメーションに遷移できるようになる。名前をFallingとする。ここからリンクを伸ばして、Idle/Walkノードに接続する。


こんな感じになっていればヨシ。

ではJumpingを開く。
Output AnimationにPlay Jump(ジャンプアニメーションの名前)を接続する。

Fallingも開く。
Output Animationに、あれば落下用のアニメーションノードを、なければジャンプと同じアニメーションを追加する。

アニメーション切り替え用のアニメーション(例えばジャンプからの着地とか)が欲しい場合は、StateMachine中の左右矢印マークを一度クリックし、詳細タブのUse Transitional Animationsにチェックを入れる。
チェックを入れるとグラフリストの中にtrans animationとカッコ書きされたグラフが追加されるので、そこにアニメーション遷移用のアニメーションを追加する。

POINT

遷移用のアニメーションは一度しか再生されないので、お好みに合わせてフリップブックの時点で長めに設定しておくといいかもしれない。

アニメーションが再生されるルールを設定する。
まずグラフからJumping to Falling(rule)を開き、BPLadyをGetで呼び出す。これにGet Velocityを接続して、構造体ピンを分割する。落ちるときのZ方向Velocityは0未満なので、Zピンにより少ない(<)を接続する。これの右側ピンとResultノードを接続すればOK。

こうなっていればヨシ。

続いてFalling to Idle/Walk(rule)を開く。
BPLadyを同様にGetで呼び出し、今度はis Walking(CharacterMovement)を接続する。
これとResultノードを接続する。

こうなっていればヨシ。


キャラクターのブループリントに戻る。
コンポーネント一覧からAnimationComponentをドラッグ&ドロップする。

これ。

ここからリンクを伸ばして、Anim Instanceを取得を選択、接続。ここから更にリンクを伸ばして、Jump to Nodeを接続する。
JumpNameにはInAir(ジャンプアニメーションを配置したノードの名前)を入力する。
StateMachineNameは、作成したStateMachineが一つの場合はNoneでいいらしい。複数の場合は良しなにしてくれるらしい。

Jump to Nodeノードの左上ピンに、イベント on Walking Off LedgeおよびイベントOnJumpedを右クリックで呼び出して接続する。

こうなっていればヨシ。


ジャンプアニメーションと着地アニメーションが両方できた。


まとめ

以上。お疲れさまでした。