90.5K Views
October 12, 17
スライド概要
2017/10/8(日)に行われたUNREAL FEST EAST 2017における株式会社バイキング様の講演「バイキング流UE4活用術 ~BPとお別れするまでの18ヶ月~」で使用された資料です。
https://unrealevent.eventcloudmix.com/
スライドに埋め込まれた動画に関しましては、以下のURLにてご確認ください。
https://youtu.be/15CKcLAWSFU
Unreal Engineを開発・提供しているエピック ゲームズ ジャパンによる公式アカウントです。 勉強会や配信などで行った講演資料を公開しています。 公式サイトはこちら https://www.unrealengine.com/ja/
バイキング流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 BpClass3 BpClass2 BpClass3 #ue4fest
コンパイルに待たされるようになってきた! BpClass1 BpClass3 BpClass2 BpClass3 #ue4fest 派生先の末端まで 非参照として 追加される
コンパイルに待たされるようになってきた! 実際にコンパイル時間を計測 4 8 16 32 : 0.8sec 1.6sec 2.0sec 3.8sec ※Intel(R) Core(TM) i7-5820K 3.30GHz 6コアにて計測 #ue4fest
コンパイルに待たされるようになってきた! 実際にコンパイル時間を計測 4 8 16 32 : 256 0.8sec 1.6sec 2.0sec 3.8sec 33sec ※Intel(R) Core(TM) i7-5820K 3.30GHz 6コアにて計測 #ue4fest
コンパイルに待たされるようになってきた! マジシャンズ・デッドでは350以上の参照を持つBPも! #ue4fest
コンパイルに待たされるようになってきた! マジシャンズ・デッドでは350以上の参照を持つBPも! 基底クラスをC++化する事で改善 C++の基底クラスを用意 #ue4fest
• なんかコンパイルに待たされるようになってきた! • フレームレートが出ない • 処理の流れを確認したい、デバッグしよう、うん? • やっぱりマージができない! #ue4fest
フレームレートが出ない • BPの構造体は値渡し • 想定外の挙動 #ue4fest
フレームレートが出ない 10 10 GetArray、GetArray2がそれぞれ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
フレームレートが出ない 10 10 11 110 100 100 Pure関数の呼び出し回数 #ue4fest
フレームレートが出ない 10 10 11 110 100 100 Pure関数の呼び出し回数 #ue4fest
フレームレートが出ない GetArray、GetArray2をC++に置き換えた UFUNCTION(BlueprintPure) const TArray<FVector>& GetArrayNative() const { return m_array; } UFUNCTION(BlueprintPure) const TArray<FVector>& GetArrayNative2() const { return m_array2; } Pure関数の呼び出し回数 #ue4fest
フレームレートが出ない GetArray、GetArray2をC++に置き換えた UFUNCTION(BlueprintPure) const TArray<FVector>& GetArrayNative() const { return m_array; } UFUNCTION(BlueprintPure) const TArray<FVector>& GetArrayNative2() const { return m_array2; } 負荷が軽減! •GetArray 0.134ms→0.057ms Pure関数の呼び出し回数 •GetArray2 0.146ms→0.083ms #ue4fest
• なんかコンパイルに待たされるようになってきた! • フレームレートが出ない • 処理の流れを確認したい、デバッグしよう、うん? • やっぱりマージができない! #ue4fest
デバッグしよう、うん? • アタッチでメンバ変数が見づらい • アタッチでスタックトレース追うのが大変 • スタンドアローンでしか起きない不具合 #ue4fest
デバッグしよう、うん? • アタッチでメンバ変数が見づらい • アタッチでスタックトレース追うのが大変 • スタンドアローンでしか起きない不具合 #ue4fest
デバッグしよう、うん? • アタッチでメンバ変数が見づらい • アタッチでスタックトレース追うのが大変 • スタンドアローンでしか起きない不具合 #ue4fest
デバッグしよう、うん? • アタッチでメンバ変数が見づらい • アタッチでスタックトレース追うのが大変 • スタンドアローンでしか起きない不具合 →結果、ログを残して再発を待つデバッグに #ue4fest
• なんかコンパイルに待たされるようになってきた! • フレームレートが出ない • 処理の流れを確認したい、デバッグしよう、うん? • やっぱりマージができない! #ue4fest
みんなBPがいやになってくる #ue4fest
BP部分のNative化が始まる #ue4fest
Native化に苦しめられる #ue4fest
Native化に苦しめられる •失って気づくBPのやさしさ •BpEnum、Bp構造体の問題 #ue4fest
Native化に苦しめられる •失って気づくBPのやさしさ ・nullptrをアクセスする事によるハング •BpEnum、Bp構造体の問題 #ue4fest
Native化に苦しめられる •失って気づくBPのやさしさ ・nullptrをアクセスする事によるハング •BpEnum、Bp構造体の問題 ・ Native化しようとしているBpで使用されている全 てのBpEnum、Bp構造体を C++に変更しないと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);
#ue4fest
MyActor->bAttack = true;
MyActor->SetSpeed(Speed);
//攻撃状態で出現
//速度設定
MyActor->FinishSpawning(Transform);
// OnConstruction,BeginPlayが呼ばれる
GC(ガベージコレクション)起因のクラッシュ #ue4fest
GC(ガベージコレクション)によるクラッシュ • 何もしていないのにクラッシュ • クラッシュのタイミングが不定 • BPで組んでいたときは発生して いなかった • 突然ポインタの先が壊れる GCによるクラッシュの可能性が あります。 #ue4fest 立っていただけなのにクラッシュ??
UE4のGC(ガベージコレクション) • 不要となった UObject を定期的に自動削除する機能 • 不要かどうかの判定は参照ツリーに含まれるかどうか • GCの対象から外すためには UPROPERTY をつける UPROPERTY #ue4fest
参照ツリー Actor UPROPERTY UObject Actor UPROPERTY UObject root set 参照されていないUObjectはGC対象となる UObject #ue4fest
変数に UPROPERTY() をつけて参照を持つ
.h
class GAME_API UMyObject : public UObject
{
}
class GAME_API AMyActor : public AActor
{
UPROPERTY()
UMyObject* MyObject;
};
.cpp
{
MyObject = NewObject<UMyObject>();
}
#ue4fest
参照ツリーに追加されているか注意 • クラスや構造体をメンバに持つ場合にも注意 • メンバを含んだクラスや構造体にも UPROPERTY が必要 • root set から参照がたどれているかを意識する #ue4fest
参照ツリーから外れているケース .h USTRUCT() struct FMyData { UPROPERTY() UObject* MyObject; }; // 参照を持っているつもり UCLASS() class GAMEMODULE_API AMyActor : public AActor { GENERATED_BODY() FMyData MyData; }; #ue4fest // ここで参照が切れている
途中で切れた参照ツリー 参照されていないためGC対象となる root set #ue4fest MyActor FMyData UPROPERTY UMyObject
参照ツリーにつながっているケース .h USTRUCT() struct FMyData { UPROPERTY() UObject* MyObject; }; // 参照を持つ UCLASS() class GAMEMODULE_API AMyActor : public AActor { GENERATED_BODY() UPROPERTY() FMyData MyData; }; #ue4fest // 参照を持つ
参照ツリーに繋がっている 参照されているためGC対象とならない root set #ue4fest MyActor UPROPERTY FMyData UPROPERTY UMyObject
TArrayに格納する場合も同様
.h
USTRUCT()
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 参照 参照 下位のモジュール 参照 中位のモジュール 下位のモジュール
マジシャンズデッドのモジュール構成 参照方向 #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
モジュール間を移動すると クラス や 構造体 を異なる モジュールに移動 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 #ue4fest OutGame
モジュール構成例 • System • Common • Battle / OutGame • Primary • とりあえず必要なのでこのへんに • 全てのモジュールにアクセス可能な存在 • なるべく使用しない #ue4fest
モジュール構成図 System Common Battle OutGame Primary #ue4fest
UE4プロジェクトの運用 #ue4fest
作業PCスペック • OS • CPU • メモリ • グラフィック • SSD • HDD Windows10 Pro 64-bit Intel Core i7 5820K 3.3GHz 16 GB NVIDIA GeForce GTX 960 500 GB 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 骨ごとにリターゲットの設定 #ue4fest キャラ固有骨、顔 Animation アニメーションで骨の位置を動かす骨 AnimationScale アニメーションで骨の位置を動かさない骨 Skeleton
とりあえずこれをやれば再生できる2 リターゲットソース • SkeletonのRetargetManagerで設定 • キャラ固有モーションを作る時に必要(後で説明) • 登録するモデルはメモリ削減のためマテリアル無し のモデルにする #ue4fest キ ャ ラ モ デ ル へ の 参 照 が い っ ぱ い
足が浮く!埋まる! 「骨の構造に問題がある場合1」 • 腰の移動値を入れる骨とRootの間に 骨を追加してはいけない • ボーンスペースのTrans値を元に倍率 COG が計算されるので途中に骨があると (腰の移動値) 正しい倍率でリターゲットされない これ、ダメ Root #ue4fest • ただし、Rootと同じ位置に追加する 分には大丈夫
足が浮く!埋まる! 「骨の構造に問題がある場合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.ステート管理について • Actionという単位でクラスを作ってそれを切り替えて管理 • ながらアクションが可能なようにMainとSubの2レイヤー 使えるようにした BeginAction アクション起動時によばれる EndAction アクション終了時によばれる ActionTick アクションが起動中のみ毎フレよばれる LocalActionTick クライアントのみよばれる版 CheckShiftableAction 指定アクションへの遷移が可能かを定義 #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
#ue4fest