バイキング流UE4活用術 ~BPとお別れするまでの18ヶ月~

Preview:

Citation preview

#ue4fest

バイキング流UE4活用術~BPとお別れするまでの18ヶ月~

瀬田 宗治奥井 健芹沢 仁

株式会社バイキング

#ue4fest

株式会社バイキング

多人数の通信対戦アクションゲームをよく作っている会社です

© 2012 SQUARE ENIX CO., LTD. All Rights Reserved.

#ue4fest

瀬田 宗治プログラマーグレート

マジシャンズデッドではモーションセンサーを使ってモノを掴んで

投げたりするギミックを担当

芹沢 仁火事場のプログラマーサーバー周り、UI、ツール等幅広く開発を担当

奥井 健癒し系プログラマー「ガンスリンガーストラトス」「マジシャンズデッド」でカメラやアニメーションシステムを担当

#ue4fest

本日の話

•BP出会いから別れまでのストーリー

•BPからC++への移行

•モジュール分割

•プロジェクトの運用

•アニメーション

#ue4fest

「マジシャンズ・デッド」プロジェクト概要

• 開発人数プランナー: 6人プログラマ:18人モーション: 8人デザイナ :35人サウンド : 2人

• 開発期間約18ヶ月

• UEのバージョン4.6~4.12

• 非同期通信3対3オンラインアクションゲーム

• 非接触入力デバイス

#ue4fest

BP出会いから別れまでのストーリー

#ue4fest

初めてのUE4

どうしていいか分からなかったのでヒストリアさんにサポートをお願いしました

#ue4fest

S氏曰く

「まずはBPでロジックを組むといいよ」

「後でボトルネックになったとこをネイティブ化したらいいよ」

#ue4fest

この言葉で私たちは

「時代はBPだ!全部BPで書けば良いんだ!」

とBP信者になりました。

#ue4fest

BPだと同時に編集できない問題は

ActorComponentで分割すれば解決するはず!

とコンポーネント分割を推し進める

#ue4fest

BPでできたActorComponentを継承したBP、

さらにそれを継承したBP、どんどん複雑化していく部品たち

だんだんプロジェクトも大きくなってきた

アセットも増えてきた

#ue4fest

急に問題が出始める

#ue4fest

• BPインターフェースは検索に引っかからない!どういうことだ!!

• なんかコンパイルに待たされるようになってきた!

• フレームレートが出ない

• 処理の流れを確認したい、デバッグしよう、うん?なんか変数の値が見れないぞ?ファンクションライブラリに書くと見れない?

• やっぱりマージができない!

#ue4fest

• BPインターフェースは検索に引っかからない!どういうことだ!! (現在は解決済み)

• なんかコンパイルに待たされるようになってきた!

• フレームレートが出ない

• 処理の流れを確認したい、デバッグしよう、うん?なんか変数の値が見れないぞ?ファンクションライブラリに書くと見れない? (現在は解決済み)

• やっぱりマージができない!

#ue4fest

• なんかコンパイルに待たされるようになってきた!

• フレームレートが出ない

• 処理の流れを確認したい、デバッグしよう、うん?

• やっぱりマージができない!

#ue4fest

コンパイルに待たされるようになってきた!

どうやらBPの被参照数が多いほどコンパイルに時間がかかる事がわかった

#ue4fest

被参照数は以下の要領でどんどん増えていく

• 変数でBPを保持された• SpawnActorでBPを生成された• BPが継承された

コンパイルに待たされるようになってきた!

#ue4fest

被参照数は以下の要領でどんどん増えていく

• 変数でBPを保持された• SpawnActorでBPを生成された• BPが継承された→BPを1つ継承すると、継承元の全てのBPクラスの被参照数が増える

コンパイルに待たされるようになってきた!

#ue4fest

BpClass1

BpClass2

コンパイルに待たされるようになってきた!

#ue4fest

BpClass1

BpClass2

BpClass3

BpClass3

コンパイルに待たされるようになってきた!

#ue4fest

BpClass1

BpClass2

BpClass3

派生先の末端まで非参照として追加されるBpClass3

コンパイルに待たされるようになってきた!

#ue4fest

4 0.8sec8 1.6sec16 2.0sec32 3.8sec:

※Intel(R) Core(TM) i7-5820K 3.30GHz 6コアにて計測

実際にコンパイル時間を計測

コンパイルに待たされるようになってきた!

#ue4fest

4 0.8sec8 1.6sec16 2.0sec32 3.8sec:

256 33sec

※Intel(R) Core(TM) i7-5820K 3.30GHz 6コアにて計測

コンパイルに待たされるようになってきた!

実際にコンパイル時間を計測

#ue4fest

マジシャンズ・デッドでは350以上の参照を持つBPも!

コンパイルに待たされるようになってきた!

#ue4fest

マジシャンズ・デッドでは350以上の参照を持つBPも!基底クラスをC++化する事で改善

C++の基底クラスを用意

コンパイルに待たされるようになってきた!

#ue4fest

• なんかコンパイルに待たされるようになってきた!

• フレームレートが出ない

• 処理の流れを確認したい、デバッグしよう、うん?

• やっぱりマージができない!

#ue4fest

フレームレートが出ない

• BPの構造体は値渡し• 想定外の挙動

#ue4fest

フレームレートが出ない

GetArray、GetArray2がそれぞれ10個の配列を返す場合

10 10

#ue4fest

フレームレートが出ない

GetArrayは111回GetArray2は210回呼ばれる

#ue4fest

フレームレートが出ない

•Pure関数は参照時に実行される

#ue4fest

フレームレートが出ない

•Pure関数は参照時に実行される

•ForEachLoopマクロは要素数の取得の為、内部で要素数+1だけGetArrayを呼び出している

#ue4fest

フレームレートが出ない

•Pure関数は参照時に実行される

ForEachLoopマクロ内

#ue4fest

フレームレートが出ない

•Pure関数は参照時に実行される要素数比較

ForEachLoopマクロ内

要素毎の処理

#ue4fest

フレームレートが出ない

•Pure関数は参照時に実行される

•ForEachLoopマクロは要素数の取得の為、内部で要素数+1だけGetArrayを呼び出している

•ForEachLoopのArray Elementを参照する時も呼び出される

#ue4fest

フレームレートが出ない

110

100

11

100

Pure関数の呼び出し回数

10 10

#ue4fest

フレームレートが出ない

110

100

11

100

Pure関数の呼び出し回数

10 10

#ue4fest

フレームレートが出ない

Pure関数の呼び出し回数

UFUNCTION(BlueprintPure)

const TArray<FVector>& GetArrayNative() const { return m_array; }

UFUNCTION(BlueprintPure)

const TArray<FVector>& GetArrayNative2() const { return m_array2; }

GetArray、GetArray2をC++に置き換えた

#ue4fest

フレームレートが出ない

Pure関数の呼び出し回数•GetArray 0.134ms→0.057ms

•GetArray2 0.146ms→0.083ms

GetArray、GetArray2をC++に置き換えた

UFUNCTION(BlueprintPure)

const TArray<FVector>& GetArrayNative() const { return m_array; }

UFUNCTION(BlueprintPure)

const TArray<FVector>& GetArrayNative2() const { return m_array2; }

負荷が軽減!

#ue4fest

• なんかコンパイルに待たされるようになってきた!

• フレームレートが出ない

• 処理の流れを確認したい、デバッグしよう、うん?

• やっぱりマージができない!

#ue4fest

デバッグしよう、うん?

• アタッチでメンバ変数が見づらい• アタッチでスタックトレース追うのが大変• スタンドアローンでしか起きない不具合

#ue4fest

デバッグしよう、うん?

• アタッチでメンバ変数が見づらい• アタッチでスタックトレース追うのが大変• スタンドアローンでしか起きない不具合

#ue4fest

デバッグしよう、うん?

• アタッチでメンバ変数が見づらい• アタッチでスタックトレース追うのが大変• スタンドアローンでしか起きない不具合

#ue4fest

デバッグしよう、うん?

• アタッチでメンバ変数が見づらい• アタッチでスタックトレース追うのが大変• スタンドアローンでしか起きない不具合→結果、ログを残して再発を待つデバッグに

#ue4fest

• なんかコンパイルに待たされるようになってきた!

• フレームレートが出ない

• 処理の流れを確認したい、デバッグしよう、うん?

• やっぱりマージができない!

#ue4fest

みんなBPがいやになってくる

#ue4fest

BP部分のNative化が始まる

#ue4fest

Native化に苦しめられる

#ue4fest

Native化に苦しめられる

•失って気づくBPのやさしさ

•BpEnum、Bp構造体の問題

#ue4fest

•失って気づくBPのやさしさ・nullptrをアクセスする事によるハング

•BpEnum、Bp構造体の問題

Native化に苦しめられる

#ue4fest

•失って気づくBPのやさしさ・nullptrをアクセスする事によるハング

•BpEnum、Bp構造体の問題・ Native化しようとしているBpで使用されている全てのBpEnum、Bp構造体をC++に変更しないとNative化できない

Native化に苦しめられる

#ue4fest

結局、全部をNative化することはできなかった

#ue4fest

マジシャンズデッドでのBPガイドライン

•デザイナが触るBPとプログラマが触るBPをできるだけ分ける

•BPクラスを継承したBPクラスを作らない

•BPクラスは自作のC++クラスを継承させる

•Enum、構造体はC++で定義する

•メンバ変数はC++で用意する

#ue4fest

マジシャンズデッドでのBPガイドライン

•デザイナが触るBPとプログラマが触るBPをできるだけ分ける→競合対策

•BPクラスを継承したBPクラスを作らない

•BPクラスは自作のC++クラスを継承させる

•Enum、構造体はC++で定義する→Native化対策

•メンバ変数はC++で用意する→デバッグ対策

#ue4fest

まとめ

•BP、C++の使い分けを考える

•BPからC++への移行はコストがかかる

#ue4fest

まとめ

•BP、C++の使い分けを考える・試作などは編集と反映のサイクルを短くできる・デザイナのUIとして・複数人で同時にBPを触るような規模のプロジェクトになるとつらい

•BPからC++への移行はコストがかかる

#ue4fest

まとめ

•BP、C++の使い分けを考える・試作などは編集と反映のサイクルを短くできる・デザイナのUIとして・複数人で同時にBPを触るような規模のプロジェクトになるとつらい

•BPからC++への移行はコストがかかる・移行する可能性があるなら最初からC++で作る

#ue4fest

結論

Blueprintは 恋人

結婚するなら C++

#ue4fest

BPからC++への移行モジュール分割UE4プロジェクトの運用

#ue4fest

BPからC++への移行

1. SpawnActorに引数を渡したい場合

2. GC起因の不正アクセス

#ue4fest

SpawnActorに引数を渡したい

#ue4fest

BPの場合

1. Actorを作成

2. BPに変数を作成

3. 変数を選択して

Editable と

Expose on Spawn に

チェックを入れる

#ue4fest

BPの場合4. SpawnActorFromClassノードでアクタを指定

5. 引数がノードにあらわれるので設定

#ue4fest

C++の場合

1. SpawnActor の代わりに SpawnActorDeferred を使用

2. 変数を書き換えたり、関数呼び出したりする

3. FinishSpawningActorを呼び出す

OnConstruction や BeginPlay が呼ばれる前に値を設定可能

#ue4fest

C++の記述例

UWorld* World = GetWorld();FTransform Transform(FVector(0.0f, 0.0f, 100.0f));FVector Speed(10.0f, 0.0f, 0.0f);

auto* MyActor = World->SpawnActorDeferred<AMyActor>(AMyActor::StaticClass(), Transform);

MyActor->bAttack = true; //攻撃状態で出現MyActor->SetSpeed(Speed); //速度設定

MyActor->FinishSpawning(Transform); // OnConstruction,BeginPlayが呼ばれる

#ue4fest

GC(ガベージコレクション)起因のクラッシュ

#ue4fest

GC(ガベージコレクション)によるクラッシュ

•何もしていないのにクラッシュ

•クラッシュのタイミングが不定

•BPで組んでいたときは発生していなかった

•突然ポインタの先が壊れる

GCによるクラッシュの可能性があります。

立っていただけなのにクラッシュ??

#ue4fest

UE4のGC(ガベージコレクション)

•不要となった UObject を定期的に自動削除する機能

•不要かどうかの判定は参照ツリーに含まれるかどうか

•GCの対象から外すためには UPROPERTY をつける

UPROPERTY

#ue4fest

参照ツリー

root set

Actor UObject

UObject

UObject

Actor

UPROPERTY

UPROPERTY

参照されていないUObjectはGC対象となる

#ue4fest

変数に UPROPERTY() をつけて参照を持つ.hclass GAME_API UMyObject : public UObject{}

class GAME_API AMyActor : public AActor{

UPROPERTY()UMyObject* MyObject;

};

.cpp

{

MyObject = NewObject<UMyObject>();

}

#ue4fest

参照ツリーに追加されているか注意

• クラスや構造体をメンバに持つ場合にも注意

• メンバを含んだクラスや構造体にも UPROPERTY が必要

• root set から参照がたどれているかを意識する

#ue4fest

参照ツリーから外れているケース.hUSTRUCT()struct FMyData{

UPROPERTY()UObject* MyObject; // 参照を持っているつもり

};

UCLASS()class GAMEMODULE_API AMyActor : public AActor{

GENERATED_BODY()

FMyData MyData; // ここで参照が切れている};

#ue4fest

途中で切れた参照ツリー

root set MyActor UMyObjectUPROPERTY

参照されていないためGC対象となる

FMyData

#ue4fest

参照ツリーにつながっているケース.hUSTRUCT()struct FMyData{

UPROPERTY()UObject* MyObject; // 参照を持つ

};

UCLASS()class GAMEMODULE_API AMyActor : public AActor{

GENERATED_BODY()

UPROPERTY()FMyData MyData; // 参照を持つ

};

#ue4fest

参照ツリーに繋がっている

root set MyActor UMyObjectUPROPERTY

参照されているためGC対象とならない

FMyDataUPROPERTY

#ue4fest

TArrayに格納する場合も同様.hUSTRUCT()struct FMyData{

UPROPERTY()UObject* MyObject; // 参照を持つ

};

UCLASS()class GAMEMODULE_API AMyActor : public AActor{

GENERATED_BODY()

UPROPERTY() // 参照を持つTArray<FMyData*> MyData;

};

#ue4fest

参照ツリーを意識しよう!

#ue4fest

モジュール構成

#ue4fest

UE4のモジュール

•エンジンそのものがモジュールの集まりで構成されている

•ゲームも複数のモジュールに分割することができる

#ue4fest

モジュール分割した経緯

•ビルド時間の短縮が見込めるはず

•ソースの依存度を減らしてスッキリ

•ツールやデバッグの機能も分割、リリース時は除外

とにかくやってみたかった!

#ue4fest

ソースの依存度を減らしたい

オブジェクト

オブジェクト

オブジェクト

適当に組むとこうなりがち

#ue4fest

ソースの依存度を減らしたい

オブジェクト

オブジェクト オブジェクト

こうしたい!

#ue4fest

モジュール単位でのコントロールは可能

拡張モジュール1

基本モジュール

拡張モジュール2

許可されていない方向の参照はビルドエラーにできる!

#ue4fest

モジュールの参照ルール

•モジュール間の依存度を下げるため一方通行の参照を設定

《ルール》• 各モジュールにレベルを設定• 下のレベルから上のレベルへの参照は可• 同じレベル内での水平参照も不可

《注意》• 相互依存はコンパイル時間に関して問題がある• 変数の静的初期化で問題を生じる場合がある

#ue4fest

モジュールの参照イメージ

中位のモジュール

下位のモジュール 下位のモジュール

上位のモジュール

参照

参照

参照

参照

#ue4fest

マジシャンズデッドのモジュール構成

レベル モジュール

L0 EngineModule

L1 SystemModule

L2 NetworkModule, USBIOModule

L3 CommonDataModule, UserDataModule, ResidentModule

L4 ActorModule, ControllerModule, ServerModule

L5 BppGame, BppGameEd

L6 CharacterModule, HudModule

L7 OutGameModule

L8 BattleAIModule, BattleCharacterModule

L9 DebugModule

L10 DevelopEditorModule

参照

方向

#ue4fest

メリットは享受できたと思うのですが

#ue4fest

分割しすぎた

#ue4fest

モジュール分割のデメリット

•モジュール間の依存関係が複雑になる

•どのモジュールに作成すべきか考えないといけない

•モジュール間の移動に手間がかかる

#ue4fest

モジュール間を移動すると

クラス や 構造体 を異なるモジュールに移動

BPの参照が切れてアセットが壊れる

#ue4fest

モジュール間を移動するには

#ue4fest

ActiveClassRedirects に指定

モジュール間を移動した場合は移動先のモジュールと名前をDefaultEngine.iniのActiveClassRedirectsに記述する

Game/Config/DefaultEngine.ini

[/Script/Engine.Engine]+ActiveClassRedirects=(OldClassName=“MyClass",NewClassName="/Script/BattleModule.MyClass ")

クラス名を変更したときにも使えるので便利!

#ue4fest

モジュール構成の提案

プロジェクト規模にもよりますがゲーム部分は数モジュールの分割で十分かも

例)• System

• Common

• Battle / OutGame

• Primary(ゲームプロジェクト名)

※ ツール、デバッグなどのモジュールは除く

#ue4fest

Systemモジュール

• System• システム共有の実装(他タイトルでも使用可能)

• アセット参照不可

• 可能なものは出来るだけプラグイン化を検討する

描画、アニメーション、サウンド、I/Oストレージなどの基本機能

• Common

• Battle / OutGame

• プライマリ

#ue4fest

モジュール構成図System

#ue4fest

Commonモジュール

• System

• Common• ゲームごとの実装ではあるが、

ゲームを通して共通の処理

• アセット参照可

ゲーム共通のアニメーション

• Battle / OutGame

• プライマリ

#ue4fest

モジュール構成図System

Common

#ue4fest

Battle/OutGameモジュール

• System

• Common

• Battle / OutGame• バトルとアウトゲームでは必要な機能が異なることが

多いので、それぞれ固有の実装はモジュールを分けるようにしてシンプルにする。

• プライマリ

#ue4fest

モジュール構成図System

Common

Battle OutGame

#ue4fest

モジュール構成例

• System

• Common

• Battle / OutGame

• Primary• とりあえず必要なのでこのへんに

• 全てのモジュールにアクセス可能な存在

• なるべく使用しない

#ue4fest

モジュール構成図System

Battle OutGame

Common

Primary

#ue4fest

UE4プロジェクトの運用

#ue4fest

作業PCスペック

•OS Windows10 Pro 64-bit

•CPU Intel Core i7 5820K 3.3GHz

•メモリ 16 GB

•グラフィック NVIDIA GeForce GTX 960

•SSD 500 GB

•HDD 2 TB

公式推奨よりもかなりイイ

#ue4fest

オススメはSSD

いまならNVMeのSSDがなおよし

#ue4fest

SSDの使用を推奨

大幅に作業時間が短縮できました

•ビルド時間の短縮

•UE4起動時間の短縮

•アセット読み込み・保存時間の短縮

•いろいろはかどります

#ue4fest

プロジェクト管理

Subversionを使用

• UE4インテグレートがされている

• スタッフの習熟度がPerforceよりも高い

• Gitはbeta版なので見送り

• 無料

#ue4fest

非プログラマの場合

• エディタのソースコントロールを使用

• エディタからコミット

• アセットがコミット対象

メリット

• 手軽でわかりやすい

デメリット

• 参照時にsvnのステータスをサーバに問い合わせるので動作が重い(サーバの混雑度合いによる)

#ue4fest

プログラマの場合

• コミット対象• BPソースファイル

• Cソースファイル

• exe

• dll

• pdb(デバッグに必要)

など

• TortoiseSVNを使用

#ue4fest

プログラマの作業フロー

1. プロジェクト更新

2. Cソースを更新して実装

3. ビルドして実行確認

4. Cソース、モジュールのdll、pdbをコミット

#ue4fest

ちょっと問題が

#ue4fest

dllコミット時にコンフリクトが発生

•Cソースは基本的にはマージされますが、dllはバイナリのためマージ不可。

•同じモジュールのCソースを同時に編集した場合コンフリクトが起きる。

#ue4fest

dllはコミットせず自動で作成!

#ue4fest

Jenkinsによる自動ビルド

•プログラマはソースファイルをコミット

• Jenkinsがコミットを検知してdllを作成

•作成したdllをコミット

dllのコンフリクトが解決された!

#ue4fest

commit時のdllコンフリクトは解決されたが

#ue4fest

今度はupdate時にdllコンフリクトが発生

#ue4fest

excludeを指定

•プログラマはdllをローカルでビルドするためコンフリクトが発生

•ローカルのものだけを信用すればよいのでリポジトリのdllは不要

•exclude指定することでローカルのみSubversion管理から外す

svn update --set-depth exclude BppGame¥Binaries¥Win64¥UE4Editor-SystemModule.dll

#ue4fest

他にも問題が

#ue4fest

プロジェクトの更新時間が長い?

#ue4fest

pdbファイルが原因

•サイズが大きいためストレージとネットワークの帯域を消費してしまう。

•通常は不要だけどデバッグ時に必要なので管理はしたい

Subversion管理せず、シンボルサーバを利用

#ue4fest

Jenkinsに任せていたこと

•dllのビルドと更新

•dllビルドエラーチェック

•パッケージ作成

•筐体へのインストール&ゲーム起動

#ue4fest

ビルドエラーが発生した場合

• JenkinsからSlackでプログラマにエラーを通知して知らせる

エラー時とエラー復帰時に通知

#ue4fest

まとめ

•参照ツリーを意識する

•モジュールは分割しすぎない

(無理に分割する必要はない)

•SSDがおすすめ

#ue4fest

アニメーション

1.アニメーションの共有、

2.ステート管理、3.AnimGraphはどう作ればええの?

#ue4fest

1.アニメーションの共有

•モデルが変わると同じアニメーションが再生できない??

•AnimGraphが共有できない??

Skeletonを1個にする!

結論

#ue4fest

•1つのSkeletonに全キャラの骨がマージされる(722本あった)

•モデルに存在しない骨は無視されるので大丈夫!

•骨の名前がかぶらないように注意

ドラゴンも一緒

#ue4fest

とりあえずこれをやれば再生できる1

骨ごとにリターゲットの設定

キャラ固有骨、顔 Animation

アニメーションで骨の位置を動かす骨 AnimationScale

アニメーションで骨の位置を動かさない骨 Skeleton

#ue4fest

とりあえずこれをやれば再生できる2

•SkeletonのRetargetManagerで設定

•キャラ固有モーションを作る時に必要(後で説明)

•登録するモデルはメモリ削減のためマテリアル無しのモデルにする

リターゲットソース

キャラモデルへの参照がいっぱい

#ue4fest

足が浮く!埋まる!

「骨の構造に問題がある場合1」

Root

COG

(腰の移動値)

これ、ダメ

•腰の移動値を入れる骨とRootの間に骨を追加してはいけない

•ボーンスペースのTrans値を元に倍率が計算されるので途中に骨があると正しい倍率でリターゲットされない

•ただし、Rootと同じ位置に追加する分には大丈夫

#ue4fest

足が浮く!埋まる!

「骨の構造に問題がある場合2」

極端な例

•「ひざ上」と「ひざ下」の比率が違うと足を曲げた時に高さが変わる。左の例は直立している時は同じ長さだけど曲げるとズレる

•よくあるのが「ハイヒール」

•すこしくらいならIKでごまかす

#ue4fest

足が浮く!埋まる!

キャラ固有モーションとは?•リターゲットしなくてもいいモーション

•キャラ専用のリグで出力したモーションのこと

この設定を間違えると足が浮いたり埋まったりする

ここでどのキャラ固有なのかを指定しないといけない

リターゲットマネージャで登録した名前が出てくる

#ue4fest

足が浮く!埋まる!

この設定、アセットごとに手動で設定しないといけない・・・

そんなんいややー!

#ue4fest

自動化しました• アニメーションインポートプラグインを作成した

• コンテンツブラウザの右クリックにアイコンを追加

• 特定のキャラのモーションを一括でインポート

• 更新されているかはハッシュ値で比較

• インポートするフォルダ名からリターゲットソースの値を生成して設定

• Additive設定、Notify、MetaDataなどの設定はテンプレート(主人公)から自動でコピー

• モンタージュやブレンドスペースの自動生成、AnimBPのアセットの参照付け替えの自動化

プラグインの作り方:http://historia.co.jp/archives/367

#ue4fest

アセットのロード•ファイル名でStaticLoadする。キャラごとのアセット名は同じ

例:

•ゲーム起動時に各キャラごとにアニメーションアセットのパスを生成

•パスの生成ルールは以下の順にファイルの存在チェックをして優先度の高いものが使われる

キャラ固有モーション 性別共通 共通

Pl001/Animation/co0000_Idle

Pl200/Animation/co0000_Idle

#ue4fest

アニメーション使う時•標準のPlayAnimationは直接使わなかった

• 引数にアセット設定したらコードを再利用できない

• Idを指定して再生するPlayAnimationを作った

•こうしておくとキャラを新規追加してもすぐにゲームでプレイできる

•データがない場合は共通モーション(主人公のモーション)が再生される

#ue4fest

骨の階層を変更しようとすると面倒

対処法1. 古いモデルを削除

2. 共通スケルトンを開き、TransrationRetargettingの設定をメモ(3番の手順をするとずれてしまうので)

3. Asset→RemoveUnusedBonesFromSkeletonを実行し、古い骨を削除

4. 新しい骨のモデルをインポート

5. メモしておいたTransrationRetargettingの設定を見ながらずれている部分を修正

6. リターゲットマネージャでリターゲットソースを再設定

7. 全モーション再インポート

#ue4fest

共通だけど変えたい(´・ω・`)•ヤラレは共通モーション

•武器を持っていると手が不自然、小物がめり込んじゃう

•部分的に上書きしたい、データドリブンに・・・

•DyanmicLayerBlendというノード実装した

修正前 修正後

#ue4fest

使用したデータ

#ue4fest

2.ステート管理について

BeginAction アクション起動時によばれる

EndAction アクション終了時によばれる

ActionTick アクションが起動中のみ毎フレよばれる

LocalActionTick クライアントのみよばれる版

CheckShiftableAction 指定アクションへの遷移が可能かを定義

•Actionという単位でクラスを作ってそれを切り替えて管理

•ながらアクションが可能なようにMainとSubの2レイヤー使えるようにした

#ue4fest

2.ステート管理について

ゲームシステム側のステートマシンは良いとして

↑これ、AnimBPのステートマシンを使うべきか、使わざるべきか

#ue4fest

AnimBPステートマシンのメリット・デメリット

■メリット•通信量が抑えられる

•ゲームシステム側のステートや移動量などすでに同期済みのステートを参照してアニメーションを切り替える場合

■デメリット•キャラごとにカスタマイズできない

•ゲームシステムのステートマシンと二重管理になる

•通常行動でモンタージュが使いづらい

#ue4fest

•マジシャンズデッドでは使わなかった

•もっと大人数の通信対戦だったら使ったほうがいいかもしれない

マジシャンズデッドではどうしたか

#ue4fest

ネットワーク同期はアニメーション単位

•アクション遷移はRPCで送って同期する

•アクション個別の処理は基本クライアントのみLocalActionTickに書く

•アニメーションの再生タイミングをRPCで同期する

#ue4fest

エフェクトやSe、ヒット判定など同期は?

•可能な限りAnimNotifyに仕込む

•AnimNotifyとはアニメーションの特定フレームでイベントを発生させるための機能です

•→はとある格闘3段目のNotify

#ue4fest

アニメーションの再生タイミングさえ同期しとけばなんとかなる!

#ue4fest

3.AnimGraph

#ue4fest

#ue4fest

AnimGraph親指

人差し指

中指

薬指

小指

#ue4fest

AnimGraph

#ue4fest

アニメーションが無い=歩き

•アニメーションはSlotに流す

•Slotが空だとSourceのブレンドスペース(歩き)が出る

•攻撃中はエイミングポーズを上半身にブレンド

#ue4fest

補助骨やキャラ固有処理はどこに書く?

•Post Process AnimBPに書くと良い

•UE4.14で実装された。もっと早く欲しかった・・・

•「SkeletalMeshに設定できる」第2のAnimBP

•ラグドールなど物理の後に実行されるので補助骨に最適

#ue4fest

まとめ

AnimBPはSkeletonと結合しているので再利用性が低くなりがち。でも大丈夫!

Skeletonを1個にすれば乗り切れる!

#ue4fest

おしまい

#ue4fest

ご清聴ありがとうございました

#ue4fest

Recommended