Advertisement

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

エピック・ゲームズ・ジャパン Epic Games Japan
Oct. 12, 2017
Advertisement

More Related Content

Slideshows for you(20)

Advertisement

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

More from エピック・ゲームズ・ジャパン Epic Games Japan(20)

Advertisement

Recently uploaded(20)

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

  1. #ue4fest バイキング流UE4活用術 ~BPとお別れするまでの18ヶ月~ 瀬田 宗治 奥井 健 芹沢 仁 株式会社バイキング
  2. #ue4fest 株式会社バイキング 多人数の通信対戦アクションゲームをよく作っている会社です © 2012 SQUARE ENIX CO., LTD. All Rights Reserved.
  3. #ue4fest 瀬田 宗治 プログラマーグレート マジシャンズデッドではモーショ ンセンサーを使ってモノを掴んで 投げたりするギミックを担当 芹沢 仁 火事場のプログラマー サーバー周り、UI、ツール等幅広く開発を担当 奥井 健 癒し系プログラマー 「ガンスリンガーストラトス」「マジシャンズデッド」で カメラやアニメーションシステムを担当
  4. #ue4fest 本日の話 •BP出会いから別れまでのストーリー •BPからC++への移行 •モジュール分割 •プロジェクトの運用 •アニメーション
  5. #ue4fest 「マジシャンズ・デッド」 プロジェクト概要• 開発人数 プランナー: 6人 プログラマ:18人 モーション: 8人 デザイナ :35人 サウンド : 2人 • 開発期間 約18ヶ月 • UEのバージョン 4.6~4.12 • 非同期通信3対3オンラインアクションゲーム • 非接触入力デバイス
  6. #ue4fest BP出会いから別れまでのストーリー
  7. #ue4fest 初めてのUE4 どうしていいか分からなかったので ヒストリアさんにサポートをお願いしました
  8. #ue4fest S氏曰く 「まずはBPでロジックを組むといいよ」 「後でボトルネックになったとこをネイティブ化したらいいよ」
  9. #ue4fest この言葉で私たちは 「時代はBPだ!全部BPで書けば良いんだ!」 とBP信者になりました。
  10. #ue4fest BPだと同時に編集できない問題は ActorComponentで分割すれば解決するはず! とコンポーネント分割を推し進める
  11. #ue4fest BPでできたActorComponentを継承したBP、 さらにそれを継承したBP、どんどん複雑化していく 部品たち だんだんプロジェクトも大きくなってきた アセットも増えてきた
  12. #ue4fest 急に問題が出始める
  13. #ue4fest • BPインターフェースは検索に引っかからない! どういうことだ!! • なんかコンパイルに待たされるようになってきた! • フレームレートが出ない • 処理の流れを確認したい、デバッグしよう、うん? なんか変数の値が見れないぞ?ファンクションライブラリに書 くと見れない? • やっぱりマージができない!
  14. #ue4fest • BPインターフェースは検索に引っかからない! どういうことだ!! (現在は解決済み) • なんかコンパイルに待たされるようになってきた! • フレームレートが出ない • 処理の流れを確認したい、デバッグしよう、うん? なんか変数の値が見れないぞ?ファンクションライブラリに書 くと見れない? (現在は解決済み) • やっぱりマージができない!
  15. #ue4fest • なんかコンパイルに待たされるようになってきた! • フレームレートが出ない • 処理の流れを確認したい、デバッグしよう、うん? • やっぱりマージができない!
  16. #ue4fest コンパイルに待たされるようになってきた! どうやらBPの被参照数が多いほど コンパイルに時間がかかる事がわかった
  17. #ue4fest 被参照数は以下の要領でどんどん増えていく • 変数でBPを保持された • SpawnActorでBPを生成された • BPが継承された コンパイルに待たされるようになってきた!
  18. #ue4fest 被参照数は以下の要領でどんどん増えていく • 変数でBPを保持された • SpawnActorでBPを生成された • BPが継承された →BPを1つ継承すると、継承元の全てのBPク ラスの被参照数が増える コンパイルに待たされるようになってきた!
  19. #ue4fest BpClass1 BpClass2 コンパイルに待たされるようになってきた!
  20. #ue4fest BpClass1 BpClass2 BpClass3 BpClass3 コンパイルに待たされるようになってきた!
  21. #ue4fest BpClass1 BpClass2 BpClass3 派生先の末端まで 非参照として 追加されるBpClass3 コンパイルに待たされるようになってきた!
  22. #ue4fest 4 0.8sec 8 1.6sec 16 2.0sec 32 3.8sec : ※Intel(R) Core(TM) i7-5820K 3.30GHz 6コアにて計測 実際にコンパイル時間を計測 コンパイルに待たされるようになってきた!
  23. #ue4fest 4 0.8sec 8 1.6sec 16 2.0sec 32 3.8sec : 256 33sec ※Intel(R) Core(TM) i7-5820K 3.30GHz 6コアにて計測 コンパイルに待たされるようになってきた! 実際にコンパイル時間を計測
  24. #ue4fest マジシャンズ・デッドでは350以上の参照を持つBPも! コンパイルに待たされるようになってきた!
  25. #ue4fest マジシャンズ・デッドでは350以上の参照を持つBPも! 基底クラスをC++化する事で改善 C++の基底クラスを用意 コンパイルに待たされるようになってきた!
  26. #ue4fest • なんかコンパイルに待たされるようになってきた! • フレームレートが出ない • 処理の流れを確認したい、デバッグしよう、うん? • やっぱりマージができない!
  27. #ue4fest フレームレートが出ない • BPの構造体は値渡し • 想定外の挙動
  28. #ue4fest フレームレートが出ない GetArray、GetArray2がそれぞれ10個の配列を返す場合 10 10
  29. #ue4fest フレームレートが出ない GetArrayは111回GetArray2は210回呼ばれる
  30. #ue4fest フレームレートが出ない •Pure関数は参照時に実行される
  31. #ue4fest フレームレートが出ない •Pure関数は参照時に実行される •ForEachLoopマクロは要素数の 取得の為、内部で要素数+1だ けGetArrayを呼び出している
  32. #ue4fest フレームレートが出ない •Pure関数は参照時に実行される ForEachLoopマクロ内
  33. #ue4fest フレームレートが出ない •Pure関数は参照時に実行される 要素数比較 ForEachLoopマクロ内 要素毎の処理
  34. #ue4fest フレームレートが出ない •Pure関数は参照時に実行される •ForEachLoopマクロは要素数の 取得の為、内部で要素数+1だ けGetArrayを呼び出している •ForEachLoopのArray Element を参照する時も呼び出される
  35. #ue4fest フレームレートが出ない 110 100 11 100 Pure関数の呼び出し回数 10 10
  36. #ue4fest フレームレートが出ない 110 100 11 100 Pure関数の呼び出し回数 10 10
  37. #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++に置き換えた
  38. #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; } 負荷が軽減!
  39. #ue4fest • なんかコンパイルに待たされるようになってきた! • フレームレートが出ない • 処理の流れを確認したい、デバッグしよう、うん? • やっぱりマージができない!
  40. #ue4fest デバッグしよう、うん? • アタッチでメンバ変数が見づらい • アタッチでスタックトレース追うのが大変 • スタンドアローンでしか起きない不具合
  41. #ue4fest デバッグしよう、うん? • アタッチでメンバ変数が見づらい • アタッチでスタックトレース追うのが大変 • スタンドアローンでしか起きない不具合
  42. #ue4fest デバッグしよう、うん? • アタッチでメンバ変数が見づらい • アタッチでスタックトレース追うのが大変 • スタンドアローンでしか起きない不具合
  43. #ue4fest デバッグしよう、うん? • アタッチでメンバ変数が見づらい • アタッチでスタックトレース追うのが大変 • スタンドアローンでしか起きない不具合 →結果、ログを残して再発を待つデバッグに
  44. #ue4fest • なんかコンパイルに待たされるようになってきた! • フレームレートが出ない • 処理の流れを確認したい、デバッグしよう、うん? • やっぱりマージができない!
  45. #ue4fest みんなBPがいやになってくる
  46. #ue4fest BP部分のNative化が始まる
  47. #ue4fest Native化に苦しめられる
  48. #ue4fest Native化に苦しめられる •失って気づくBPのやさしさ •BpEnum、Bp構造体の問題
  49. #ue4fest •失って気づくBPのやさしさ ・nullptrをアクセスする事によるハング •BpEnum、Bp構造体の問題 Native化に苦しめられる
  50. #ue4fest •失って気づくBPのやさしさ ・nullptrをアクセスする事によるハング •BpEnum、Bp構造体の問題 ・ Native化しようとしているBpで使用されている全 てのBpEnum、Bp構造体を C++に変更しないとNative化できない Native化に苦しめられる
  51. #ue4fest 結局、全部をNative化することは できなかった
  52. #ue4fest マジシャンズデッドでのBPガイドライン •デザイナが触るBPとプログラマが触るBPをできるだけ分ける •BPクラスを継承したBPクラスを作らない •BPクラスは自作のC++クラスを継承させる •Enum、構造体はC++で定義する •メンバ変数はC++で用意する
  53. #ue4fest マジシャンズデッドでのBPガイドライン •デザイナが触るBPとプログラマが触るBPをできるだけ分ける →競合対策 •BPクラスを継承したBPクラスを作らない •BPクラスは自作のC++クラスを継承させる •Enum、構造体はC++で定義する →Native化対策 •メンバ変数はC++で用意する →デバッグ対策
  54. #ue4fest まとめ •BP、C++の使い分けを考える •BPからC++への移行はコストがかかる
  55. #ue4fest まとめ •BP、C++の使い分けを考える ・試作などは編集と反映のサイクルを短くできる ・デザイナのUIとして ・複数人で同時にBPを触るような規模のプロジェク トになるとつらい •BPからC++への移行はコストがかかる
  56. #ue4fest まとめ •BP、C++の使い分けを考える ・試作などは編集と反映のサイクルを短くできる ・デザイナのUIとして ・複数人で同時にBPを触るような規模のプロジェク トになるとつらい •BPからC++への移行はコストがかかる ・移行する可能性があるなら最初からC++で作る
  57. #ue4fest 結論 Blueprintは 恋人 結婚するなら C++
  58. #ue4fest BPからC++への移行 モジュール分割 UE4プロジェクトの運用
  59. #ue4fest BPからC++への移行 1. SpawnActorに引数を渡したい場合 2. GC起因の不正アクセス
  60. #ue4fest SpawnActorに引数を渡したい
  61. #ue4fest BPの場合 1. Actorを作成 2. BPに変数を作成 3. 変数を選択して Editable と Expose on Spawn に チェックを入れる
  62. #ue4fest BPの場合 4. SpawnActorFromClassノードでアクタを指定 5. 引数がノードにあらわれるので設定
  63. #ue4fest C++の場合 1. SpawnActor の代わりに SpawnActorDeferred を使用 2. 変数を書き換えたり、関数呼び出したりする 3. FinishSpawningActorを呼び出す OnConstruction や BeginPlay が呼ばれる前に値を設定可能
  64. #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が呼ばれる
  65. #ue4fest GC(ガベージコレクション)起因のクラッシュ
  66. #ue4fest GC(ガベージコレクション)によるクラッシュ •何もしていないのにクラッシュ •クラッシュのタイミングが不定 •BPで組んでいたときは発生して いなかった •突然ポインタの先が壊れる GCによるクラッシュの可能性が あります。 立っていただけなのにクラッシュ??
  67. #ue4fest UE4のGC(ガベージコレクション) •不要となった UObject を定期的に自動削除する機能 •不要かどうかの判定は参照ツリーに含まれるかどうか •GCの対象から外すためには UPROPERTY をつける UPROPERTY
  68. #ue4fest 参照ツリー root set Actor UObject UObject UObject Actor UPROPERTY UPROPERTY 参照されていないUObjectはGC対象となる
  69. #ue4fest 変数に UPROPERTY() をつけて参照を持つ .h class GAME_API UMyObject : public UObject { } class GAME_API AMyActor : public AActor { UPROPERTY() UMyObject* MyObject; }; .cpp { MyObject = NewObject<UMyObject>(); }
  70. #ue4fest 参照ツリーに追加されているか注意 • クラスや構造体をメンバに持つ場合にも注意 • メンバを含んだクラスや構造体にも UPROPERTY が必要 • root set から参照がたどれているかを意識する
  71. #ue4fest 参照ツリーから外れているケース .h USTRUCT() struct FMyData { UPROPERTY() UObject* MyObject; // 参照を持っているつもり }; UCLASS() class GAMEMODULE_API AMyActor : public AActor { GENERATED_BODY() FMyData MyData; // ここで参照が切れている };
  72. #ue4fest 途中で切れた参照ツリー root set MyActor UMyObjectUPROPERTY 参照されていないためGC対象となる FMyData
  73. #ue4fest 参照ツリーにつながっているケース .h USTRUCT() struct FMyData { UPROPERTY() UObject* MyObject; // 参照を持つ }; UCLASS() class GAMEMODULE_API AMyActor : public AActor { GENERATED_BODY() UPROPERTY() FMyData MyData; // 参照を持つ };
  74. #ue4fest 参照ツリーに繋がっている root set MyActor UMyObjectUPROPERTY 参照されているためGC対象とならない FMyDataUPROPERTY
  75. #ue4fest TArrayに格納する場合も同様 .h USTRUCT() struct FMyData { UPROPERTY() UObject* MyObject; // 参照を持つ }; UCLASS() class GAMEMODULE_API AMyActor : public AActor { GENERATED_BODY() UPROPERTY() // 参照を持つ TArray<FMyData*> MyData; };
  76. #ue4fest 参照ツリーを意識しよう!
  77. #ue4fest モジュール構成
  78. #ue4fest UE4のモジュール •エンジンそのものがモジュールの集まりで構成されている •ゲームも複数のモジュールに分割することができる
  79. #ue4fest モジュール分割した経緯 •ビルド時間の短縮が見込めるはず •ソースの依存度を減らしてスッキリ •ツールやデバッグの機能も分割、リリース時は除外 とにかくやってみたかった!
  80. #ue4fest ソースの依存度を減らしたい オブジェクト オブジェクト オブジェクト 適当に組むとこうなりがち
  81. #ue4fest ソースの依存度を減らしたい オブジェクト オブジェクト オブジェクト こうしたい!
  82. #ue4fest モジュール単位でのコントロールは可能 拡張モジュール1 基本モジュール 拡張モジュール2 許可されていない方向の参照はビルドエラーにできる!
  83. #ue4fest モジュールの参照ルール •モジュール間の依存度を下げるため一方通行の参照を設定 《ルール》 • 各モジュールにレベルを設定 • 下のレベルから上のレベルへの参照は可 • 同じレベル内での水平参照も不可 《注意》 • 相互依存はコンパイル時間に関して問題がある • 変数の静的初期化で問題を生じる場合がある
  84. #ue4fest モジュールの参照イメージ 中位のモジュール 下位のモジュール 下位のモジュール 上位のモジュール 参照 参照 参照 参照
  85. #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 参照方向
  86. #ue4fest メリットは享受できたと思うのですが
  87. #ue4fest 分割しすぎた
  88. #ue4fest モジュール分割のデメリット •モジュール間の依存関係が複雑になる •どのモジュールに作成すべきか考えないといけない •モジュール間の移動に手間がかかる
  89. #ue4fest モジュール間を移動すると クラス や 構造体 を異なる モジュールに移動 BPの参照が切れて アセットが壊れる
  90. #ue4fest モジュール間を移動するには
  91. #ue4fest ActiveClassRedirects に指定 モジュール間を移動した場合は移動先のモジュールと名前を DefaultEngine.iniのActiveClassRedirectsに記述する Game/Config/DefaultEngine.ini [/Script/Engine.Engine] +ActiveClassRedirects=(OldClassName=“MyClass",NewClassName="/Script/BattleModule.MyClass ") 例 クラス名を変更したときにも使えるので便利!
  92. #ue4fest モジュール構成の提案 プロジェクト規模にもよりますが ゲーム部分は数モジュールの分割で十分かも 例) • System • Common • Battle / OutGame • Primary(ゲームプロジェクト名) ※ ツール、デバッグなどのモジュールは除く
  93. #ue4fest Systemモジュール • System • システム共有の実装(他タイトルでも使用可能) • アセット参照不可 • 可能なものは出来るだけプラグイン化を検討する 例 描画、アニメーション、サウンド、I/O ストレージなどの基本機能 • Common • Battle / OutGame • プライマリ
  94. #ue4fest モジュール構成図 System
  95. #ue4fest Commonモジュール • System • Common • ゲームごとの実装ではあるが、 ゲームを通して共通の処理 • アセット参照可 例 ゲーム共通のアニメーション • Battle / OutGame • プライマリ
  96. #ue4fest モジュール構成図 System Common
  97. #ue4fest Battle/OutGameモジュール • System • Common • Battle / OutGame • バトルとアウトゲームでは必要な機能が異なることが 多いので、それぞれ固有の実装はモジュールを分ける ようにしてシンプルにする。 • プライマリ
  98. #ue4fest モジュール構成図 System Common Battle OutGame
  99. #ue4fest モジュール構成例 • System • Common • Battle / OutGame • Primary • とりあえず必要なのでこのへんに • 全てのモジュールにアクセス可能な存在 • なるべく使用しない
  100. #ue4fest モジュール構成図 System Battle OutGame Common Primary
  101. #ue4fest UE4プロジェクトの運用
  102. #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 公式推奨よりもかなりイイ
  103. #ue4fest オススメはSSD いまならNVMeのSSDがなおよし
  104. #ue4fest SSDの使用を推奨 大幅に作業時間が短縮できました •ビルド時間の短縮 •UE4起動時間の短縮 •アセット読み込み・保存時間の短縮 •いろいろはかどります
  105. #ue4fest プロジェクト管理 Subversionを使用 • UE4インテグレートがされている • スタッフの習熟度がPerforceよりも高い • Gitはbeta版なので見送り • 無料
  106. #ue4fest 非プログラマの場合 • エディタのソースコントロールを使用 • エディタからコミット • アセットがコミット対象 メリット • 手軽でわかりやすい デメリット • 参照時にsvnのステータスをサーバに 問い合わせるので動作が重い (サーバの混雑度合いによる)
  107. #ue4fest プログラマの場合 • コミット対象 • BPソースファイル • Cソースファイル • exe • dll • pdb(デバッグに必要) など • TortoiseSVNを使用
  108. #ue4fest プログラマの作業フロー 1. プロジェクト更新 2. Cソースを更新して実装 3. ビルドして実行確認 4. Cソース、モジュールのdll、pdbをコミット
  109. #ue4fest ちょっと問題が
  110. #ue4fest dllコミット時にコンフリクトが発生 •Cソースは基本的にはマージされますが、 dllはバイナリのためマージ不可。 •同じモジュールのCソースを同時に編集した場合 コンフリクトが起きる。
  111. #ue4fest dllはコミットせず自動で作成!
  112. #ue4fest Jenkinsによる自動ビルド •プログラマはソースファイルをコミット •Jenkinsがコミットを検知してdllを作成 •作成したdllをコミット dllのコンフリクトが解決された!
  113. #ue4fest commit時のdllコンフリクトは解決されたが
  114. #ue4fest 今度はupdate時にdllコンフリクトが発生
  115. #ue4fest excludeを指定 •プログラマはdllをローカルでビルドするためコンフリクトが発生 •ローカルのものだけを信用すればよいのでリポジトリのdllは不要 •exclude指定することでローカルのみSubversion管理から外す svn update --set-depth exclude BppGame¥Binaries¥Win64¥UE4Editor-SystemModule.dll 例
  116. #ue4fest 他にも問題が
  117. #ue4fest プロジェクトの更新時間が長い?
  118. #ue4fest pdbファイルが原因 •サイズが大きいためストレージとネットワークの帯域を消費し てしまう。 •通常は不要だけどデバッグ時に必要なので管理はしたい Subversion管理せず、シンボルサーバを利用
  119. #ue4fest Jenkinsに任せていたこと •dllのビルドと更新 •dllビルドエラーチェック •パッケージ作成 •筐体へのインストール&ゲーム起動
  120. #ue4fest ビルドエラーが発生した場合 •JenkinsからSlackでプログラマにエラーを通知して知らせる エラー時とエラー復帰時に通知
  121. #ue4fest まとめ •参照ツリーを意識する •モジュールは分割しすぎない (無理に分割する必要はない) •SSDがおすすめ
  122. #ue4fest アニメーション 1.アニメーションの共有、 2.ステート管理、 3.AnimGraphはどう作ればええの?
  123. #ue4fest 1.アニメーションの共有 •モデルが変わると同じアニメーションが再生できな い?? •AnimGraphが共有できない?? Skeletonを1個にする! 結論
  124. #ue4fest •1つのSkeletonに全キャ ラの骨がマージされる (722本あった) •モデルに存在しない骨は 無視されるので大丈夫! •骨の名前がかぶらないよ うに注意 ドラゴンも一緒
  125. #ue4fest とりあえずこれをやれば再生できる1 骨ごとにリターゲットの設定 キャラ固有骨、顔 Animation アニメーションで骨の位置を動かす骨 AnimationScale アニメーションで骨の位置を動かさない骨 Skeleton
  126. #ue4fest とりあえずこれをやれば再生できる2 •SkeletonのRetargetManagerで設定 •キャラ固有モーションを作る時に必要(後で説明) •登録するモデルはメモリ削減のためマテリアル無し のモデルにする リターゲットソース キ ャ ラ モ デ ル へ の 参 照 が い っ ぱ い
  127. #ue4fest 足が浮く!埋まる! 「骨の構造に問題がある場合1」 Root COG (腰の移動値) これ、ダメ •腰の移動値を入れる骨とRootの間に 骨を追加してはいけない •ボーンスペースのTrans値を元に倍率 が計算されるので途中に骨があると 正しい倍率でリターゲットされない •ただし、Rootと同じ位置に追加する 分には大丈夫
  128. #ue4fest 足が浮く!埋まる! 「骨の構造に問題がある場合2」 極端な例 •「ひざ上」と「ひざ下」の比率が 違うと足を曲げた時に高さが変わ る。左の例は直立している時は同 じ長さだけど曲げるとズレる •よくあるのが「ハイヒール」 •すこしくらいならIKでごまかす
  129. #ue4fest 足が浮く!埋まる! キャラ固有モーションとは? •リターゲットしなくてもいいモーション •キャラ専用のリグで出力したモーションのこと この設定を間違えると足が浮いたり埋まったりする ここでどのキャラ固有なのかを指定 しないといけない リターゲットマネージャで登録した 名前が出てくる
  130. #ue4fest 足が浮く!埋まる! この設定、アセットごとに手動で設定しないといけない・・・ そんなんいややー!
  131. #ue4fest 自動化しました • アニメーションインポートプラグインを作成した • コンテンツブラウザの右クリックにアイコンを追加 • 特定のキャラのモーションを一括でインポート • 更新されているかはハッシュ値で比較 • インポートするフォルダ名からリターゲットソース の値を生成して設定 • Additive設定、Notify、MetaDataなどの設定は テンプレート(主人公)から自動でコピー • モンタージュやブレンドスペースの自動生成、 AnimBPのアセットの参照付け替えの自動化 プラグインの作り方:http://historia.co.jp/archives/367
  132. #ue4fest アセットのロード •ファイル名でStaticLoadする。キャラごとのアセット名は同じ 例: •ゲーム起動時に各キャラごとにアニメーションアセットのパス を生成 •パスの生成ルールは以下の順にファイルの存在チェックをして 優先度の高いものが使われる キャラ固有モーション 性別共通 共通 Pl001/Animation/co0000_Idle Pl200/Animation/co0000_Idle
  133. #ue4fest アニメーション使う時 •標準のPlayAnimationは直接使わなかった • 引数にアセット設定したらコードを再利用できない •Idを指定して再生するPlayAnimationを作った •こうしておくとキャラを新規追加し てもすぐにゲームでプレイできる •データがない場合は共通モーション (主人公のモーション)が再生され る
  134. #ue4fest 骨の階層を変更しようとすると面倒 対処法 1. 古いモデルを削除 2. 共通スケルトンを開き、TransrationRetargettingの設定をメモ(3 番の手順をするとずれてしまうので) 3. Asset→RemoveUnusedBonesFromSkeletonを実行し、古い骨を 削除 4. 新しい骨のモデルをインポート 5. メモしておいたTransrationRetargettingの設定を見ながらずれてい る部分を修正 6. リターゲットマネージャでリターゲットソースを再設定 7. 全モーション再インポート
  135. #ue4fest 共通だけど変えたい(´・ω・`) •ヤラレは共通モーション •武器を持っていると手が不 自然、小物がめり込んじゃ う •部分的に上書きしたい、 データドリブンに・・・ •DyanmicLayerBlendという ノード実装した 修正前 修正後
  136. #ue4fest 使用したデータ
  137. #ue4fest 2.ステート管理について BeginAction アクション起動時によばれる EndAction アクション終了時によばれる ActionTick アクションが起動中のみ毎フレよばれる LocalActionTick クライアントのみよばれる版 CheckShiftableAction 指定アクションへの遷移が可能かを定義 •Actionという単位でクラスを作ってそれを切り替えて管理 •ながらアクションが可能なようにMainとSubの2レイヤー 使えるようにした
  138. #ue4fest 2.ステート管理について ゲームシステム側のステート マシンは良いとして ↑これ、AnimBPのステートマシンを使うべきか、 使わざるべきか
  139. #ue4fest AnimBPステートマシンのメリット・デメリット ■メリット •通信量が抑えられる •ゲームシステム側のステートや移動量などすでに同期済みのステート を参照してアニメーションを切り替える場合 ■デメリット •キャラごとにカスタマイズできない •ゲームシステムのステートマシンと二重管理になる •通常行動でモンタージュが使いづらい
  140. #ue4fest •マジシャンズデッドでは使わ なかった •もっと大人数の通信対戦だっ たら使ったほうがいいかもし れない マジシャンズデッドではどうしたか
  141. #ue4fest ネットワーク同期はアニメーション単位 •アクション遷移はRPCで送って同期する •アクション個別の処理は基本クライアント のみLocalActionTickに書く •アニメーションの再生タイミングをRPCで 同期する
  142. #ue4fest エフェクトやSe、ヒット判定など同期は? •可能な限りAnimNotifyに仕込む •AnimNotifyとはアニメーション の特定フレームでイベントを発 生させるための機能です •→はとある格闘3段目のNotify
  143. #ue4fest アニメーションの再生タイミング さえ同期しとけばなんとかなる!
  144. #ue4fest 3.AnimGraph
  145. #ue4fest
  146. #ue4fest AnimGraph 親指 人差し指 中指 薬指 小指
  147. #ue4fest AnimGraph
  148. #ue4fest アニメーションが無い=歩き •アニメーションはSlotに流す •Slotが空だとSourceのブレンドスペース(歩き)が出る •攻撃中はエイミングポーズを上半身にブレンド
  149. #ue4fest 補助骨やキャラ固有処理はどこに書く? •Post Process AnimBPに書くと良い •UE4.14で実装された。もっと早く欲しかった・・・ •「SkeletalMeshに設定できる」第2のAnimBP •ラグドールなど物理の後に実行されるので 補助骨に最適
  150. #ue4fest まとめ AnimBPは Skeletonと結合しているので再利用性 が低くなりがち。でも大丈夫! Skeletonを1個にすれば乗り切れる!
  151. #ue4fest おしまい
  152. #ue4fest ご清聴ありがとうございました
  153. #ue4fest
Advertisement