ロボット好き集まれ!こいつ、動くぞ。星と翼のパラドクス開発事例【UNREAL FEST EAST 2018】

12.1K Views

October 18, 18

スライド概要

講演動画:https://www.youtube.com/watch?v=bKhH2NU99Gw

2018年10月14日に行われた「UNREAL FEST EAST 2018」における株式会社バイキング様の講演で使用されたスライドです。

●公式サイト
https://unrealengine.jp/unrealfest/
===
大型可能筐体を用いたハイスピードロボット対戦アクションゲーム「星と翼のパラドクス」の制作事例としてキャラクタープログラム、カメラ、筐体制御、ネットワーク周りについてお話したいと思います。本作品で行っている8vs8の計16体のプレイヤーと多数のモブキャラや弾をマルチプレイで実現したノウハウについてもご紹介させていただきます。

profile-image

Unreal Engineを開発・提供しているエピック ゲームズ ジャパンによる公式アカウントです。 勉強会や配信などで行った講演資料を公開しています。 公式サイトはこちら https://www.unrealengine.com/ja/

シェア

埋め込む »CMSなどでJSが使えない場合

関連スライド

各ページのテキスト
1.

ロボット好き集まれ! こいつ、動くぞ 星と翼のパラドクス開発事例 株式会社バイキング 橘川 優樹 奥井 健

2.

登壇者紹介

3.

登壇者紹介 橘川 優樹 プログラマー 「星と翼のパラドクス」ではキャラクターアクション、 演出用カメラ、操作周り等を担当。 奥井 健 癒し系プログラマー ゲーム業界歴13年 「星と翼のパラドクス」ではカメラや椅子の制御を担当。 趣味はボードゲーム

4.

バイキングってどんな会社?

5.

バイキングってどんな会社? • アーケード(業務用)ゲームをよく作ってます。 • 多人数対戦アクションが得意です。 © 2012 SQUARE ENIX CO., LTD. All Rights Reserved.

6.

本日のお話 • • • • • 「星と翼のパラドクス」のご紹介 コックピット型可動筐体 UE4を用いたキャラクター制作 カメラについて 武器・弾の作り方

7.

「星と翼のパラドクス」ご紹介

8.

「星と翼のパラドクス」ご紹介

9.

作品のコンセプト  ハイスピードロボット対戦 アクション  2レバー、2ペダルの 専用筐体でロボットを自在に操作  1チーム8人、計16人のプレイヤーによる オンライン対戦 多数の雑魚AIが試合に参戦

10.

プロジェクト概要 ・開発期間 約30ヶ月(試作込) ・UE4のバージョン : 4.9.1 ~ 4.16.3

11.

コックピット型可動筐体

12.

筐体スペック 耳元にスピーカー ゲームと連動して 色が変わるLED 帰還ボタン タッチパネル ロマンがてんこ盛り! この中に2本の アクチュエーター フットペダル 操作レバー

13.

タッチパネルの機能 • 出撃前にキャラクターと ハイタッチ! • 武器を選択したり • マップで味方に指示を 出したり

14.

動いている筐体の動画

15.

筐体でのプログラミング • 椅子の調整時は一日中こんな感じで 作業しています • 筐体からリモートデスクトップで 作業用PCにアクセス • プログラムをビルドしDLLのみを 筐体に転送して実行

16.

揺れの制御 • • • • 左右はカメラのZロールに連動 前後はキャラの高度変化に連動(浮遊感を演出) いろんなアクションで1ショットの揺れにカーブを使う ダメージなどによる振動 それっぽい揺れに仕上げる のにとても苦労しました

17.

前に進むときは前に 右に進むときは右に 傾ける 超高速移動のとき だけ逆

18.

UE4を用いたキャラクター制作

19.

UE4を用いたキャラクター制作 本作の開発ではブループリントでは極力処理を書かずC++で作成 処理速度が速い デバッグしやすい マージしやすい BPで作成してから後でC++へ移行するのはコストがかかる etc … C++を使用している理由の詳細はUnreal Fest2017で講演した 「バイキング流UE4活用術 ~BPとお別れするまでの18ヶ月~」を参照してください。 YouTubeに動画があります。

20.

UE4を用いたキャラクター制作 • UE4には組み込みでキャラクタークラスが用意されている • キャラクタークラスにはMovementComponentという人型キャラクター を動かすためのコンポーネントが組み込まれている • 標準機能だけで足りるのであればそのまま使えば良い • 足りないのであればカスタマイズするか完全に自作する必要がある

21.

UE4のキャラクターアーキテクチャ AActor APawn ACharacter ・UE4のレベルに配置できる基本クラス ・プレイヤーのコントローラーやAIによって制御可能 ・人型のキャラクターを作成するための機能が集約されている (スケルタルメッシュ、モーション、コリジョン等) ・キャラクターの移動を制御する「UCharacterMovementComponent」を持っている

22.

UE4のキャラクターアーキテクチャ UActorComponent ・他のアクターに持たせることができるコンポーネントの基本クラス 省略 UPawnMovementComponent ・APawnの動きを制御するコンポーネント UCharacterMovementComponent ・ACharacterの動きを制御するコンポーネント ・歩きだけでなくダッシュやジャンプ等、人型キャラクターを想定した機能が実装され ている

23.

UE4におけるキャラクター制作の選択肢 1.ACharacterを継承してタイトル用の キャラクタークラスを作成 2.APawnを継承してACharacterに相当する クラスを独自で作成 <メリット> APawn <メリット> APawn UE4のキャラクターシステムの恩恵 を受けられる ACharacter <デメリット> カスタマイズしようと思ったとき に元のシステムを熟知していない と問題が起きやすい AMyCharacter AMyCharacter 自由度が高い <デメリット> 実装コストが高い ※ACharacterで用意されている物を自前 で実装する必要がある ※UCharacterMovementに相当する物も自 前で実装する必要がある

24.

本作が目指すキャラクター挙動 • ハイスピードロボットなので、ダッシュをした時は初速が速くそこから 少し減速した状態でダッシュを継続したい • ダッシュ中、曲がるときや逆方向に移動する時に速度を落としたくない →例えば逆方向に移動する場合、速度を落とさず弧を描くように移動

25.

本作が目指す挙動 ダッシュ中に右へ移動入力を行い、左へ移動入力を行うと速度を落とさず弧を描いて旋回 前から後ろへ移動入力を行った場合も同様

26.

UE4標準機能によるキャラクター挙動 • 現状のUE4のキャラクターの速度変化は基本的に加速 • 入力方向を元に加速度をVelocityへ加算していく • 設定された最大速度でClampする

27.

UE4標準機能によるキャラクター挙動 • 基本的に加速しかない 減速は移動入力を止めた時や障害物へ当たったときしかできない • 移動入力を入れたままの減速ができない ダッシュの初速が速く、その後に減速するような動きができない • ダッシュ中、90度を超える方向へ移動すると速度が落ちてしまう ※90度以内でも見た目では分かりづらいが速度が落ちる 本作の目指す挙動とは異なる カスタマイズするか完全に自作する必要がある

28.

UE4標準の挙動 右へ移動入力を行い、左へ移動入力を行うと速度を落としてから再加速する

29.

本作の開発開始時、プロジェクト内にはUE4経験者がいなかった そのため、キャラクターを完全に自作するのではなく UE4組み込みのキャラクター機能を利用しつつカスタマイズする方針に ACharacter AMyCharacter UCharacterMovementComponet

30.

MovementComponentの差し替え UCharacterMovementComponet UMyCharacterMovementComponet UCharacterMovementComponentを継承して カスタム用ムーブメントクラスを作成 ACharacter UCharacterMovementComponet AMyCharacter ムーブメントコンポーネントはACharacterクラスが保持 しているコンポーネントなので、それをカスタマイズし たコンポーネントで差し替えたい

31.

MovementComponentの差し替え • キャラクタークラスのコンストラクタにFObjectInitializerを 受け取るようにする • FObjectInitializerのSetDefaultSubobjectClassで カスタマイズしたムーブメントクラスを指定 AMyCharacter::AMyCharacter(const FObjectInitializer& ObjectInitializer) : • Super(ObjectInitializer.SetDefaultSubobjectClass<UMyCharacterMovementComponent>(ACharacter::CharacterMovementComponentName))

32.

キャラクター挙動のカスタマイズ方針 • 移動処理(座標更新)はムーブメントに集約する • ムーブメント内のメンバ変数はpublicになっている物があるが 他のクラスからは更新しない 例えばVelocityがpublicになっているが、 ムーブメント以外から更新すると キャラクターが想定外の挙動をした場合の原因特定に時間がかかる 実際、開発中にVelocityがムーブメント以外の様々な箇所で変更するコードがかかれていた。 プロジェクトの規模がある程度の大きくなった段階で問題が顕著に。

33.

キャラクター挙動のカスタマイズ ムーブメント内の主な修正はCalcVelocity関数に入れた

34.

キャラクター挙動のカスタマイズ UCharacterMovementComponent::CalcVelocity • CalcVelocityは摩擦の影響を適用して速度と加速度を更新する関数 void UCharacterMovementComponent::CalcVelocity(float DeltaTime, float Friction, bool bFluid, float BrakingDeceleration) { ※省略 // Apply acceleration const float NewMaxSpeed = (IsExceedingMaxSpeed(MaxSpeed)) ? Velocity.Size() : MaxSpeed; Velocity += Acceleration * DeltaTime; Velocity += RequestedAcceleration * DeltaTime; Velocity = Velocity.GetClampedToMaxSize(NewMaxSpeed); if (bUseRVOAvoidance) { CalcAvoidanceVelocity(DeltaTime); } } 毎フレーム、Velocityへ加速度を加算し て最大速度でClampする関数です

35.

キャラクター挙動のカスタマイズ UCharacterMovementComponent::CalcVelocity オーバーライド UMyCharacterMovementComponent::CalcVelocity • この関数をオーバーライドして独自の挙動に書き換える • 本作では親クラスのCalcVelocityの中身をそのまま子クラスの CalcVelocityへコピーして書き換えるという手段を取った ※エンジン更新でCalcVelocityに修正が入った場合、注意が必要

36.

キャラクター挙動のカスタマイズ ダッシュ中、曲がる時や逆方向へ行く場合に 速度を落とさず弧を描いて曲がるようにする いくつか旋回のタイプを用意 アクションによって旋回タイプを切り替え ・ワールドのZ軸を基準に旋回 ・プレイヤーカメラ基準に旋回 ・弧を描かずに旋回 → 地上ダッシュ時 → 空中ダッシュ時 → 地上歩き時

37.

<地上ダッシュ時> ワールドのZ軸を基準に旋回

38.

<空中ダッシュ時> プレイヤーカメラ基準に旋回

39.

<地上歩き時> 弧を描かずに旋回

40.

キャラクター挙動のカスタマイズ switch (TurnVelocityType) { case ETurnVelocityType::MoveCameraDirection: 旋回タイプに応じて UpdateMoveCameraDirection(DeltaTime, RequestedAcceleration); break; Velocityを加工 case ETurnVelocityType::TurnWorldAxisZ: UpdateTurnWorldAxisZVelocity(DeltaTime); break; default: { const float NewMaxSpeed = (IsExceedingMaxSpeed(MaxSpeed)) ? Velocity.Size() : MaxSpeed; Velocity += Acceleration * DeltaTime; Velocity += RequestedAcceleration * DeltaTime; UE4標準の処理 Velocity = Velocity.GetClampedToMaxSize(NewMaxSpeed); } break; }

41.

多彩なアクションを実装

42.

キャラクター制作のまとめ • UE4標準のキャラクターシステムは機能が豊富 すぐにキャラクターを動かせるので開発期間が短縮できる • カスタマイズが容易なので、本作のような 人間の動きと異なる物も開発可能

43.

キャラクター制作のまとめ 非常に便利ではありましたが

44.

キャラクター制作のまとめ ディレクターの細かい要求に対応するのが難しかった もっとロボットっぽい動きにしてよ! 僕の考える最高のロボットの動きに!! 石田ディレクター 元々の機能が豊富がゆえ、本作には不要な処理も多かった。 アクションの細かい動きに拘ると、元々の処理が障壁になることも。

45.

キャラクター制作のまとめ • それでも初めてのUE4開発において UE4のキャラクターシステムを利用したのは正解だったと 思います。 • 再びUE4でアクションゲームを作る機会があれば より自由な実装を目指してACharacterと UCharacterMovementに相当する物を独自に実装しようと 思います。

46.

カメラについて

47.

カメラ振動 • アクションゲームでは至るところでカメラ振動を行います 攻撃を受けたときや死んだとき 着地したとき 強力なレーザービームを撃ったとき • そんなカメラ振動についてのお話です

48.

カメラ振動 • UE4には組み込みで「CameraShake」ブループリントというカメラ振 動用の機能が用意されている • 本作では、よりゲームに合わせた自由な振動を行いたかったため振動の 機能を自作することにした • UE4では「UCameraModifier」というクラスを拡張することで、最終的 なカメラの計算結果を調整する機能を自作することができる

49.

カメラ振動 • UCameraModifierのModifyCameraをオーバーライド • 引数のInOutPOV(LocationとRotation)の値を設定することで カメラの最終的な結果を調整することができる bool UCPP_CameraShaker::ModifyCamera(float DeltaTime, struct FMinimalViewInfo& InOutPOV) { Super::ModifyCamera( DeltaTime, InOutPOV ); ※省略 InOutPOV.Location += InOutPOV.Rotation.RotateVector(Offset); InOutPOV.Rotation += OffsetRot; return false; }

50.

カメラ振動 • 振動データの設定はUE4の「VectorCurve」を利用

51.

通常カメラ 何故、FPS視点ではなくTPS視点? コクピット型の筐体に乗って遊ぶロボットゲームならFPS視点にすべきでしょ?

52.

通常カメラ • 開発当初、FPS視点による検証を行ったが ・「高速で飛び回るロボットアクション」 ・「大型ディスプレイ」 ・「可動筐体」 という酔いやすい要素にFPS視点を加えると更に酔いを誘発する

53.

通常カメラ ロボットの速度やカメラ速度を調整することで酔い対策は可能だが • ロボットとカメラの速度を落とす • ロボットとカメラの速度変化を等速にする • カメラを上下に回転させないようにする(左右回転のみ) etc …

54.

通常カメラ これはロボットシミュレーターではなく 「ハイスピードロボットアクションである」 FPS視点にすることでロボット操作の臨場感を出すことも重要 しかし、FPS視点を重要視することによって 本来実現したいアクションスピードに影響が出てはいけない

55.

通常カメラ 理由は色々ありましたが

56.

通常カメラ 結局はディレクターの趣味です 僕、3D酔いしやすいから。 僕が酔わないゲームにしないとダメ。 TPS視点でいこう。 石田ディレクター 「ハイスピードロボットアクション」というコンセプトは守りつつ 「多くの人に遊んでもらいたい」という事を選びました。 自分の機体を見せたいという理由もあった(自機の見た目をカスタマイズする要素もあるため)

57.

ゲームのスピードは落とさずに 酔いやすい人でも遊べるゲームに仕上がりました 椅子の振動も設定で止められるので酔いやすい人でも安心して遊べます!

58.

武器・弾の作り方

59.

なぜ武器の話をしようと思ったか 対戦アクションゲームにおいて ゲームを面白くできるかどうかは 武器の魅力にかかっている。 そして、作るのがとても大変。

60.

データ構造 • AttackParam(エクセル) • ProjectileParam(エクセル) • WeaponParam(エクセル) エクセル→Csv→DataTable

61.

AttackParam • 属性(ビーム系、実弾系など) • ダメージ量 • やられタイプ • ダウン値削り量 • ぶっ飛び量 • ヒットストップ時間 などパラメータ34個!

62.

ProjectileParam • 攻撃ID • 初速 • 最高速 • 重力 • ホーミング性能 などパラメータ90個!

63.

WeaponParam • 発射する弾ID • ロックオン距離 • アニメーションタイプ • 連射間隔 • リロード時間 などパラメータ120個!

64.

パラメータ多すぎない? 石田ディレクター

65.

すいません。 多すぎました。

66.

エフェクトやモデルデータの設定は? • 安易にDataTableに定義してはいけない! • DataTableをロードすると全武器のアセットがロードされてしまう • AssetIDを使えば参照を切れるが、 1つずつ対応しているとロードが面倒 • 武器単位でBlueprintを作ってアセットをそこに設定

67.

武器Blueprint 武器モデル、マズルエフェクト、薬莢、SEなど

68.

弾も種類分Blueprintがある • こちらは弾BP 同じくエフェクトなどの アセットデータを設定 • それ以外にプランナーに公開したくないパラメ ータなどが入っている • プランナー:エクセル • デザイナー&プログラマ:Blueprint • パラメータ例: 弾の消え方、拠点バリア貫通設定など

69.

弾クラスの継承図 ACPP_ProjectileBase ACPP_PrjExplosionBase ACPP_PrjStandardBase ACPP_PrjMachineGunBullet01 BP_PrjMachineGunBullet01 (マシンガン) … ACPP_PrjFireBombCoop01 … … BP_ PrjFireBombCoop01 (火炎爆弾) 処理はCPPに書いてBPはパラメータを設定するだけ BPもCPPも大量にある・・・

70.

BPはパス(文字列)で参照 • エクセルにBPのパスを指定して文字列でBPアセット を取得する • 文字列で取るのはそれなりに遅いのでキャッシュして おくのがおすすめ

71.

リリース後の武器調整はとても大事 • どうしても生まれてしまうバランスブレイカーに対してすば やく対処する必要がある • 通常のアップデートだと更新の反映に時間がかかってしまう そこで DataTableの動的書き換え

72.

DataTable書き換えの流れ 1. ファイルサーバから該当csvファイルをダウンロード 2. (1)をメモリへ読み込む 3. FTableRowBaseを継承した構造体からUScriptStructを取得 UScriptStruct* ScriptStruct = FTableRowBase::StaticStruct(); 4. データテーブルを作成(自前クラス) DataTable* DataTable = UDynamicDataTable::Get().CreateDataTable(UObject* object, UScriptStruct* scriptStruct, const FString& dataTableName, const FString& csvString); 5. (3)の構造体テーブルへAddしていく

73.

DataTableのランタイム生成 • DataTableはお手軽で使いやすいが、 実行中に書き換えることはできない • エンジンを修正してできるようにした • 具体的にはソースの「WITH_EDITOR」を外すだけ • DataTableCSV.cpp(.h) • DataTable.cpp(.h)

74.

ヒット感、当てたときの気持ちよさ1 • 自分の弾は味方や敵よりも見た目をちょっと大きくする • ヒットエフェクト • 遠くても小さくなりすぎないようにスケールをかける • 通信ラグで位置やタイミングがズレないように(後で説明) • 置いてくエフェクトと、キャラにくっつけるエフェクト2種類ある 置いてく くっつける

75.

ヒット感、当てたときの気持ちよさ2 • 敵を画面の中心にとらえて撃つとクリティカル表示 相手を中心にとらえて トリガーを引くと、 ホーミング力が強い 弾が発射され、 それが当たると 「CRITICAL」

76.

マルチプレイで問題が • 弾を見て避けるという遊びをさせるためには 弾がゆっくり飛んでいかないといけない。 • しかも8vs8で雑魚AIが沢山。弾も大量に発生 • すべての弾の位置同期していたら通信帯域が足りない!

77.

非同期弾 • マシンガン、ビームライフルなど大量に生成するものは 位置同期しないことにした • トリガーのOnとOffだけを送信し、サーバーとクライアントは それぞれローカルの敵の位置をめがけて飛ぶ • そうすることで起きる新たな問題。位置やタイミングのズレ

78.

通信ラグで位置やタイミングにズレ • ヒット判定はサーバーのみで行うためタイミングや 位置がズレる • サーバーからの通知でヒットエフェクトを出す場合はヒット 位置をワールド座標ではなくキャラ相対座標で送る • 弾の消えるタイミングがズレるのでコリジョンを 少し後ろに付けている

79.

同期弾 • それでも気になる弾は同期弾にする • 爆発等フィールドに設置されるもの、サイズが大きいものは 非同期にすると座標のズレが目立つので同期弾にしている • 同期弾はサーバーで生成、クライアントにレプリケートされ るのでクライアントでは生成する部分をスキップする

80.

攻撃を当てられた感 • 見た目だけで当てられた感を出すのは難しかった • UIで画面端に赤い枠を表示すると情報量が多すぎたり 閉塞感が出て良くなかったのでかなり薄くしている • SE大事 • ダメージを受けた方向から衝撃がくるように 椅子の振動でダメージを表現

81.

まとめ

82.

魅力的な武器、弾を作るためのポイント • 調整しやすい環境を作る • 納得感を出すために通信を考慮した作りにする • バリエーションを沢山用意するための労力を惜しまない

83.

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

84.

スタッフ募集!! 業務拡大につき全職種積極採用中! エントリーは弊社HPまで http://byking.jp/recruit/ 本日配布のチラシも見てね!