20年オヤジのUnreal Engine 4 TIPS

皆さん、はじめまして!
セガ・インタラクティブ技術統括室の林田です。

1997年入社、20年越えのおっさんプログラマです。入社以来、おおむねアーケードゲームに携わってます。

いくつか私の代表作を紹介しておきましょう。Crazy Taxiシリーズ、頭文字D Arcade Stageシリーズ、WCCFシリーズなどなど。古いタイトルもありますので、あまりご存知ないかもしれませんね。ご興味があればWebやYoutubeなどで検索してみてください。その他、変わり種としては、初代ダーツライブのCPU戦、Answer×Answer Pocket (Objective-Cネイティブ!)、あとは古い時代の部内ライブラリなども担当したことがあります。

主な担当分野は、キャラクタアニメーション周り、あとは「火消し」と呼ばれる厄介な事件を解決する人、最近ではアンリアルエンジン4全般を担当しています。

今回の記事は、セガテックブログ初(!)の「アンリアルエンジン4(以下UE4)」についてです。初のUE4記事ゆえ力が入ってしまい、とても長くなってしまいました。お時間のある時にゆっくり読んでいただければと思います。

この記事は、UE4の(ちょっとマニアックな)TIPSを中心に書かせていただいています。なお、ちょっと紙面を余分に頂いて、我々がUE4タイトルをリリースする前にやっていた実験などの紹介などを、前半に書かせていただいています。「前置きはいいから、本題を!」という方は、途中を飛ばして「マクロは悪?」のあたりから読んでくださいませ。

もくじ

セガ製UE4タイトルは、お近くのゲームセンターで好評稼働中です。

見かけた際には、ぜひプレイしてみてくださいね!

セガUE4タイトル第1弾「SEGA World Drivers Championship」


『SEGA World Drivers Championship 2019』アドバタイズムービー

開発チームより

UnrealEngineの機能を存分に使って、SUPER GTの実車両や実在コース(実在コースは期間限定)を再現しています。
ぜひ、体感してみてください。

セガUE4タイトル第2弾「HOUSE OF THE DEAD ~SCARLET DAWN~」


HOUSE OF THE DEAD ~SCARLET DAWN~ JAEPO 2018 MOVIE

開発チームより

13年ぶりにアーケードゲームへ帰ってきました。
ゲームのグラフィックやプログラムは全てUE4エンジンで完結しています。
またアーケードゲームらしく、筐体の音や振動が非常に凝った演出となっていますので、お近くのゲームセンターで見かけたら、ぜひプレイしてみてください。

言い出しっぺが語るセガ×UE4

何を隠そう、私がセガのアーケードゲームにUE4を持ち込もうと騒ぎ始めた張本人、いわゆる「言い出しっぺ」です。そしてご多分に漏れず「言い出しっぺの法則」が発動しまして、ここ数年は社内UE4担当大臣として活動しています。

なんで自社ライブラリを持っている会社がゲームエンジンを?等々、会社の政治的・経済的・人事的な事情は脇に置いておいて(とは言え、おおむね多くの大手ゲームメーカーさんと同じ事情だと思います)、ここは「テック(技術)」ブログですから、UE4を使ってモノを作る話をしましょう。

タイトルを作る前は、こんな実験をしてました。

UE4を甘噛みしてみる実験(UE4.3のころ)

f:id:sgtech:20181125225944p:plain f:id:sgtech:20181125225942p:plain

四輪駆動のおもちゃが壁のあるコースを走るアレです。あのおもちゃと同様、前進しかできず、コリジョンで(壁に沿って)曲がるように作られています。原理的には非常に簡単ですので、興味のある方はぜひ真似をしてみてください。

作り方ヒント

  • f:id:yoshimasa_hayashida:20181019113423p:plain こういうポリゴンを使って、スプラインメッシュでコースを作っています。コリジョンは見た目よりもかなり高い壁を作りましょう。でないとクルマが簡単に吹き飛んでコースアウトします。
  • 車はアクセルボタンに応じた前進しかしません。あとは運を天に任せて、うまく曲がってくれるのを祈る感じです。場合によっては吹き飛んでしまいますが、それはそれで楽しいかと思います。何ならブレーキ操作をできるようにして、コーナーではうまく減速するゲームにしても面白いでしょう。
  • コースの各所にトリガーボリュームなどを置いて、「時間内に通過するとパワーアップ」などのギミックを入れても面白いでしょう。

 格好いい映像を作ってみる実験(UE4.5のころ)

上記の「四輪駆動のおもちゃ」はプログラマ主導でやっており、アーティストにはコース作成だけお願いしていましたが、今度の実験はアーティスト主導で行いました。この実験ではSubstance Designer/Painterも試しています。 

f:id:sgtech:20181125230654p:plain f:id:sgtech:20181125225931p:plain

さすが本職の人が作ると違いますね。HOUSE OF THE DEADを意識するというテーマを悪用して(?)、作ったメンバーの趣味が存分に盛り込まれています(笑)。

UE4の特徴である「物理ベースレンダリング」を活かそうと、光と影を意識した映像の実験となります。従来のセガのアーケードゲームとは多少趣が異なり、明暗のコントラストを強めに出しています。いわゆる「洋ゲー」に寄せた、といったところでしょうか。

一通りゲームを作ってみる実験(UE4.9のころ)

ここまでの実験である程度UE4が分かってきましたので、今度は一連のゲームの流れを作る実験をしました。何らかのタイトルプロジェクトを発足させる前に、踏める地雷はあらかじめ踏んでおこう、がテーマです。

パーティクルエフェクト担当のアーティストや、ユーザーインターフェース担当のアーティストも参加して、チェインクロニクルをアーケード向けにアレンジしたらどうなるか?を試しに作ってみたものです。

f:id:sgtech:20181125225927p:plain f:id:sgtech:20181125230016p:plain

本家チェインクロニクルの倍(10人!)のプレイヤーキャラクタ、倍どころじゃない数の敵、パーティクルエフェクトが派手に飛び交い、カメラもグルングルン回る。これを80型の大型タッチパネルモニタで両手を振り回して遊ぶ。アーケードゲーム化するんだったら、派手に!大味に!半ばパニックになっちゃうくらい忙しい!そんな風にしちゃいました。これは作るのも楽しかったですね。

この実験成果の報告会では、100名を超える社員が会議室に集まってしまい、大半は立ち見、エアコンが追いつかず会議室はどんどん暑くなるという事態に。おかげさまで社内へのUE4の認知度は高まり、UE4採用プロジェクトとしてSWDCとHODを発足させることが出来ました。

ご注意いただきたいのですが、本家チェインクロニクルがUE4に移植される予定も、アーケード版をつくる予定も全くありません。あくまで実験の題材として使用しただけですので、「次のチェインクロニクルはUE4だ!」なんて、間違った情報をうっかり拡散してしまわないようにお願いしますね!

さて、今回の記事は…

20年越えのオッサンプログラマが、その経験をBlueprintに活かすとどうなるか、そういう話をできればいいなと思っています。

UE4の紹介記事などもWebを検索すればたくさん見つかるようになりました。申し訳ありませんが、この記事には初心者向けの説明はあまりありません。それよりはもうちょっと深い部分、私視点でのUE4の「コーディング(code-ing)」ならぬ「ノーディング(node-ing)」事例などを紹介したいと思っています。

初心者の皆さんには、有名な書籍をご紹介。

初心者お断り!なんてバッサリ斬り捨ててしまうのも心が痛いので、書籍を数点ご紹介しますね。本を見つつ、Webで検索しつつ、おそらく最初は苦労されるかとは思いますが、それを乗り越えて楽しくなってきたら、ぜひこの記事に戻ってきてくださいませ!

では、書いてある通りにやれば、何か動くものが出来上がる、おそらくはUE4ユーザーの大半がお世話になっている良書から。

Unreal Engine 4で極めるゲーム開発:サンプルデータと動画で学ぶUE4ゲーム制作プロジェクト

Unreal Engine 4で極めるゲーム開発:サンプルデータと動画で学ぶUE4ゲーム制作プロジェクト

 

 同じく、「書いてある通りにやれば何かできる」もう一冊。

作れる!学べる!Unreal Engine 4 ゲーム開発入門

作れる!学べる!Unreal Engine 4 ゲーム開発入門

 

 こちらは残念ながら、おそらくUnityで使われてただろうキャラクタモデルが流用されており、Unlit(ライティングなし)前提ですので、UE4の美しいレンダリングには触れられていません。それでもキャラクタをアニメーションさせて動かす等々、おそらく多くの皆さんがやりたいと思っているだろう要素は、ちゃんと揃っていますのでご安心を。

もっとお手軽に試してみたい方には、書籍ではありませんが、こちらの動画はいかがでしょうか。


Unreal Engine 4 勉強会 『40分でBlock崩しを作る』(1)

これは「Unreal Engine 4で極める…」の著者、湊さんによる勉強会での公演の動画です。私も一番最初にこの動画をマネをすることで、UE4へのとっかかりを得ました。動画では画面の細かい文字が見えませんが、Blueprintのスクショを貼ってくれた方がいらっしゃいますので、こちら(↓)のページと合わせて見ると良いでしょう。

www.jonki.net

なお、この動画は慣れた方がサクサク組んでいらっしゃいますが、初心者にはテンポが速すぎて追いつけません(当時の私もそうでした)。一時停止や巻き戻しを繰り返して追いかける感じになりますので、決して、40分では完成しません。悪しからずご了承ください。2~3日かけてゆっくりやるくらいの心づもりで。

UE4はアップデートの周期がとても短く(この記事の執筆時点でUE4.20.3。記事のチェックをしている間にUE4.21が出てしまいました)、気を抜くとあっという間に情報が古くなってしまいます。上記3つの書籍・動画は古いバージョンのものですので、お手持ちのUE4バージョンとは違い、もしかしたらメニューの位置やコマンドの名前などが変わってしまっているかもしれません。新旧のバージョン間の機能の違いを、Web検索などを駆使してなんとか見つけ出すのもUE4の勉強の一環だと思って、頑張ってみてください。

Web上では、UE4は難しい…という声をチラホラ見かけます。

確かにそうかもしれません。私も最初の2か月くらいは、UE4が嫌いでした。
それを乗り越えて、ざっくりでもUE4が分かってきたころから、逆にサクサクものが作れていく感覚を覚え始めます。今では「テキストエディタを開いてプログラミング言語を入力する」こと自体に抵抗を覚えるくらいのUE4信者になってしまいました。特にBlueprintとMaterialは手放せません。C++/C#の時代は終わったなんて言っちゃっています。

皆さん、最初は我慢です!(これ、プロからの助言としてはどうかと思いますが…)

UE4に限らず、初めて使うツールって、体に馴染むまでは難しい顔してやるもんでしょ? ましてや、UE4はAAAタイトルすら作れちゃうくらいの豪華ツールです。大量の機能や設定の中から、今自分が欲しい機能を見出せるようになるには時間をかけて慣れるしかありません。

今回つかう題材は、UE4ぷちコン応募作品です。

株式会社ヒストリアさん主催の「UE4ぷちコン」はご存知でしょうか。毎回テーマが出され、それに沿ったゲームや映像作品をUE4で作って応募する、ちょっとしたゲームコンテストです。「UE4の勉強の成果」を発表する、勉強会の延長線上にあるもので、誰でも参加できます。皆さんも参加してみてはいかがでしょうか。

一方で、意外と本気勢も多く(私もその一人ですね)、「ガチコン」と言われてしまうこともあるようです。ヒストリアの佐々木社長はこの言葉を嫌がっているようですが、幸か不幸か、初心者作品からプロ作品まで非常に幅広いレベル帯の作品が集まるコンテストになっており、自分の現在のレベルと、次に目指すべきレベルが見えやすい、とても良いイベントです。

それはともかく、今回の記事は、私が第9回ぷちコンに応募したゲームを題材にお話しようと思っています。

第9回ぷちコン応募作品「Gravity One」


【UE4ぷちコン#9応募作品】GRAVITY ONE

テーマは「ループ」。なので、丸い地球上(マップがループしている)でのシューティングゲームを作ってみました。ありがたいことに、「カナマイ賞」を受賞することができ、アンリアルフェスWEST2018でプレイアブル展示していただきました。

社内でも、毎日昼休みにスコアアタックをしてくれるドハマリプレイヤーが出現。最終的にノーミスクリアを達成! 記念にご本人の強い要望に応えて、このゲームのexeを進呈しました。

第10回ぷちコン応募作品「MAGITYPE」

つい先日行われました、第10回ぷちコンにも応募させていただいています。


【UE4ぷちコン#10応募作品】MAGITYPE

テーマは「ぷち」。ぷちコンの「ぷち」です。
安易に思いつく「プチプチ」(梱包材のアレです)は断固避ける!と意気込んだものの、制作期間の6割くらいの間、ずっと迷走してしまい、結局は未完成のままの応募になってしまいました。テーマ「ぷち」の回収方法として私が選んだのは、過去10回の「ぷち」コンのテーマを全部使う!明らかに盛りすぎですね。間に合うわけもありません。

審査結果発表会では軽くご紹介いただきましたが(動画2:15:00くらいから)、もちろん落選です。プロとして恥ずかしい限りです。

そして、いまだに鋭意作成中…(どうなることやら)

この「MAGITYPE」からも、ご紹介したい事例がいくつもあるのですが、長くなってしまいそうなので、また次の機会に。例えば「MAGITYPE」が完成した後などに記事にできればと思います。

(困ったことに、2018年内にすら完成させられる自信はありませんが…)

プロなのに応募してずるい!

いやいや! 応募要項には「日本在住のUE4ユーザーなら誰でもOK!」と書いてあります。

…いえ。確かにズルいとは思っています。ですので、自分なりにハンデを設けて作っています。

  • 「絵も音もプログラムも、全素材を自分一人で作る!」

面白そうでしょ? やること多くて死ねますけど。

21年もゲームプログラマをやっていますと、アーティストやサウンドデザイナーとのやり取りなどで、それなりにツールの使い方や用語などは覚えるものです。なので、箱を作ってテクスチャを貼れる程度には使い方を知っています。まあ、その程度の技量で全素材づくりに挑むのですから、十分ハンデかと。

おかげさまで、2回のぷちコン参加で、SDキャラクタ作成・テクスチャ作成・アニメーション作成なども自分でできるようになりました(クオリティはともかく)。ほら、ちゃんと勉強になっているから、ズルくない!

参考までに、プログラムは組めるけど絵素材や音素材がなくて困っている皆さんや、インディーズを目指している皆さんに、私が使っているツールをご紹介しておきますね。(ちょっと世間の流行りからはズレていますけど…)

MODO indie(月々1500円ほど)

3Dモデリングツールの中では新しく、古い時代のしがらみなどが少ない分かりやすいツールです。MODO JAPAN GROUPのページにはチュートリアル動画やTIPS動画がたくさんあり、学習のしやすさもオススメしたい理由の一つです。

store.steampowered.com

CorelDRAW Graphics Suite(買い切り6万円ほど)

私は学生のころから論文などの図の作成に使っていました。未だにアップデートを繰り返して使い続けています。いわゆるフォトショップやイラストレーターに相当するツールがセットになっています。特に CorelDRAW(イラストレーター相当)は、私や多くのアーティストでない方々のように、フリーハンドで思い通りに線が描けない人にはありがたいツールです。筆で描くのではなく、方眼紙に定規やコンパスで図を描くイメージですね。私はベジエで描いてから、ビットマップに変換する流れでテクスチャを作成しています。

www.coreldraw.com

Logic Pro(買い切り2.5万円ほど)

いわゆるDTMソフト、音楽編集ソフトです。私の使っているのは古いバージョンの方、Logic Pro 9です。当時は5.5万円ほどしていたのが、今では1.7万円ですね!驚愕です。なお、私が音楽の世界に足を踏み入れたのは、ボカロ(なぜかミクさんではなくルカさん)の影響です。ありがちですね。

www.apple.com

C-Deck(540円×3種)

トランプ大のカードにコード進行が書かれた作曲ツールです。Aメロ、Bメロ、サビカードをランダムに選ぶだけでコード進行が完成です!私はこれがないと作曲できません。古いツールのなので、今ではAmazonなどでも欠品してますね…。再販してほしいものです。

blog.shimamura.co.jp

マクロは悪? いえ、善です。(Blueprintに限る)

前置きが長くなってしまいました。
さて、ここからは具体的なUE4プログラミングやTIPSの話を書いていきましょう。

以下、Blueprintのスクリーンショットが多く登場します。紙面の都合上、どうしても画像が小さくなってしまいますが、クリックすると大きく表示されますので、その機能をご活用ください。

また、ブラウザを複数立ち上げて、片方では文章、片方では画像の拡大を表示する、などの小技を使えば、より見やすくなるでしょう。

定数はどうしてますか?

最初に固定値を決めたっきり、以後は絶対変更したくない変数、つまり定数のことですが、皆さんはBlueprintではどのようにしていますか? 残念ながら、Blueprintには定数という概念がありません。

多くの方が、例えば変数名を大文字とアンダースコア(_)の組み合わせにしてみたり、

f:id:sgtech:20181125230013p:plain

接頭辞や接尾辞を付けるなど、命名規則を工夫して対処しているかと思います。

f:id:sgtech:20181125230011p:plain

C++ならconst修飾子がありましたが、

const int MaxPositionHistory = 256;

Blueprintではそうはいきません。

ここでマクロの出番です。
特にC言語の時代を知っている人は、マクロは危険という認識から、UE4でも避けてしまっているのではないでしょうか。

#define MAX_POSITION_HISTORY (256)

こんな風に書いちゃった日には、確実に先輩にドヤされます。なぜなら、C/C++言語のマクロとは、その数値が整数型なのか実数型なのか、ましてやそれが数値であるかどうかすら、コンパイラは全く気にせず、単なる文字列の置き換えで対応してしまうからです。

ところが、ご存知の通り、UE4のマクロはきっちり型を意識してくれます。ですので、

f:id:sgtech:20181125230008p:plain

こういうマクロを作ると、これは間違いなくInteger型の256となってくれます。
そうすると、

f:id:sgtech:20181125230005p:plain

ミソは、詳細(Details)パネルの「Compact Node Title」の欄にノード名を書くことです。

f:id:sgtech:20181125230053p:plain

これを書くことで、「いかにも定数です」みたいな見た目になってくれます。

f:id:sgtech:20181125230050p:plain

ゲーム用定数マクロライブラリを用意する。

上記の例はアクタの中で作っていましたが、ゲーム全体で使う定数はどうしましょうか。答えは簡単、マクロライブラリを作れば解決します。私はUE4で何か作る際には必ず「Game Constants Macro Library」といった名前のマクロライブラリを作り、ゲーム全体で使う種々の定数を入れています。

これで、このマクロライブラリを編集するだけで、ゲーム中の様々な状態を変更することができるようになりますね。例えば、バランス調整用の定数マクロライブラリなどがあっても良いかもしれません。(ゲームエンジンの時代に定数でバランス調整って、時代遅れな気もしますが…)

なお、定数を変更したらコンパイルしなくてはなりません。ここはご注意ください。

ノードグラフをより見やすく、便利にするための定数マクロ

それでは、ゲーム専用に限らず、Blueprintそのものの見通しをよりよくするために、こういうマクロを作ってみてはいかがでしょうか?

f:id:sgtech:20181125230047p:plain

作り方は先ほどの Max Position History と同様です。Boolean型のFalseを返すマクロを作り、Compact Node Title に「False」と書くだけ。

f:id:sgtech:20181125230630p:plain

同様の方法でTrue マクロも用意しておきましょう。

これらは、作成者の意図を明示するだけでなく、ノードグラフをサクサク組むための助けにもなってくれます。「Compact Node Title」に書かれた文字列は、右クリックで出てくる検索ウィンドウに引っかかるようになってくれますので、例えば「True」や「False」と入力するだけで、今作った Trueマクロや Falseマクロがサクっと引っぱり出せるようになります。

f:id:sgtech:20181125230043p:plain

これらもマクロライブラリを作って、便利そうなものはどんどん入れておきましょう。参考までに、私のマクロライブラリに入っている便利定数をご紹介します。UE4/Blueprintライフが向上すること請け合いです。

f:id:sgtech:20181125230701p:plain

よく使う整数として「Integer 0」や「Integer 1」。このほかにも「Integer -1」などを用意してます。これを使うと、Make Literal Int を検索して、(あの小さい枠に)0を入力して、の手間がまるっと解消されます。

f:id:sgtech:20181125230037p:plain

同じく「Float 0, 1, -1」。ちなみに上記は軸との内積の正負で、回転角度のプラスマイナスを決めるような、比較的よくありそうなノードグラフですね。

f:id:sgtech:20181125230144p:plain

あの巨大な「Make Transform」ノードが非常にコンパクトになる「Transform Identity」ノード。ちなみにIdentityとは「単位行列」の意味。高校数学でしたっけ?内容は、Location=(0,0,0), Rotation=(0,0,0), Scale=(1,1,1) です。これも右クリックのノード検索メニューで「Identity」と入力するだけで出てきます。

下側のSpawn Emitter at Locationに繋がっているのは、意外と面倒な(0, 0, 0)とか(1, 1, 1)を一発で書くためのものです。

マクロ内ローカル変数を活用する。

 下のGIFアニメはぷちコン応募作品「Gravity One」に登場するザコ敵です。「プレドニゾローン」という、とても覚えられない名前がついてます。さて、このプレドニゾローン、キノコ状の「フタ(Flap)」が一定時間ごとに上がったり下がったりします。これをBlueprintで書いてみるとどうなるでしょうか。

f:id:sgtech:20181125230128g:plain

普通のコーディング例、もとい「ノーディング」例

Event BeginPlayとEvent Tick

f:id:sgtech:20181125230124p:plain

  • Event BeginPlay: 使っているメンバ変数に初期値をセットしています。
  • Event Tick: 後述のTickEvent UpdateFlap(カスタムイベント)を呼び出しています。ザコ敵とは言え、弾を撃つなど、もっとたくさんの処理がぶら下がるはずですが、上の図はあくまでサンプルだととらえてください。

TickEvent UpdateFlap

f:id:sgtech:20181125230120p:plain

  • Event Tickから呼び出され、「フタ(Flap)」の回転や上下動を行うカスタムイベントです。
  • カスタムイベントTickEvent Open/Close Flap を呼び出しています。このカスタムイベントは、フタの高さ(Float FlapHeight)を決めています。
  • FlapYaw変数の値を算出しています。現在のYaw角度+DeltaSeconds × RotationSpeedで、次の角度を求めています。
  • Set Relative Location And Rotation で、フタモデルSM_Flap (Static Mesh Component)の相対位置と相対角度をセットしています。

TickEvent Open/Close Flap

f:id:sgtech:20181125230116p:plain

  • TickEvent UpdateFlapから呼び出され、フタ(Flap)の上下動を行います。
  • Sequence - Then 0側:
    ・経過時間(Float ElapsedSeconds)を算出しています。
    ・経過時間÷開け閉めの秒数(Open/Close Duration)で開け閉めの割合(Alpha)を求ています。
    ・フタの高さを求めるマクロ(Make Flap Height Macro)(後述)に、開け閉めの割合(Alpha)と現在の開け閉め状態(Boolean CloseFlag)を渡しています。
    ・算出された新しい高さを、Float変数 FlapHeightに格納します。
  • Sequence - Then 1側: 経過時間が、開け閉めの秒数(Open/Close Duration)+待ち秒数(Wait Duration)を越えたら、経過時間をゼロクリアし、開け閉め状態のフラグ(CloseFlag)を反転します。
  • Open/Close Duration、Wait Duration、Elapsed Seconds の使い方がちょっとだけトリッキーなので注意してください。
    ・Elapsed Secondsの変化する範囲は 0~(Open/CloseDuration+WaitDuration)ですが、Make Flap Height Macro に渡す Alphaの値は WaitDurationを考慮に入れていないため、1を超えてしまいます。
    ・Make Flap Height Macro 内で Alphaの値を0~1にクランプしています。これで、Wait Duration秒数だけ開いたまま/閉じたまましばらく待つ、という状態を作ってます。

Make Flap Height Macro

f:id:sgtech:20181125230226p:plain

  • 入力された開け閉め率(Float Alpha)を0~1の範囲にクランプしています。
  • 入力された開け閉め状態のフラグ(Boolean Close)に応じて、OpenHeightからCloseHeightまでのをEaseするのか、CloseHeightからOpenHeightまでをEaseするのかを切り替えています。
  • Easeで求められた高さをNewHeightとして出力します。

多少トリッキーな書き方をしているのは認めますが、考え方は至って普通です。

  • 経過時間を計算する。
  • その経過時間から、フタの高さを求める。
  • 一定時間経過したら、開け/閉めを切り替える。

さて、ここで話題に挙げたいのは、この「フタの開け閉め」で使われている4つのメンバ変数です。

f:id:sgtech:20181125230223p:plain

  • Boolean CloseFlag: このフラグがTrueの時は閉め、Falseの時は開け、の動作を行う。状態切り替えのためのフラグ。
  • Float ElapsedSeconds: フタを開け始めてから/あるいは閉め始めてからの経過時間(秒)。
  • Float FlapHeight: フタの高さ(Z値)
  • Float FlapYaw: フタの回転角度(Yaw値)

 

さて、この、至って普通のノーディング、20年オヤジは何が気に食わないのでしょうか。

これらの変数は、単にフタを開け閉めするだけのための用意されました。しかし、フタの開け閉めなんて、このActorにとっては影響度/重要度はかなり低いです。私としては、重要度の低い変数(や関数)は、できる限り重要度の高いものとは分けて置いておきたいのです。本音を言うと、メンバ変数にすらしたくない。さもないと、クラスに機能が増えていくにつれ、メンバ変数の欄はどんどん肥大化し、重要度の高い変数と低い変数が同レベルでゴチャっと並んでしまうのです。

実はこの問題、マクロ内ローカル変数を使うことで解消できます。

マクロ内ローカル変数で重要度の低いメンバ変数を減らした例

(Event BeginPlayやEvent Tickは、おおむね変更はなく、想像がつくと思いますので割愛します)

TickEvent UpdateFlap (Modified)

f:id:sgtech:20181125230220p:plain

まずは簡単にできるところから。

フタの回転角度として使っていたメンバ変数FlapYawをなくしてしまいました。その代わりにUpdate Yaw Macroというマクロを作りました。これがミソです。

Update Yaw Macroの中身はこうです。

f:id:sgtech:20181125230217p:plain

Local Floatノードが「マクロ内ローカル変数」です。

  • 普通に「+」ノードなどに挿して、Floatとして使えます。
  • いわゆるSETノードに相当するののが「Assign」ノードです。
  • 上の図では「マクロ内ローカル変数に、YawAdderを足して、マクロ内ローカル変数にAssign(セット)する」「マクロ内ローカル変数をNewYawとして出力する」が行われています。

マクロ内ローカル変数の制限などについて。

  • 変数名がつけられませんので、複数のマクロ内ローカル変数を使うときは混乱しがちです。
  • 使う場合は、Local Floatから必ずラインを伸ばす必要があります。上の図のように、ひたすらLocal Floatノードから、相手のノードに直接つなげる必要があります。したがって、マクロ内ローカル変数をたくさん使うと、非常にたくさんのラインが飛び交うスパゲッティコードになりがちです。

このマクロ内ローカル変数、「Event Graph内に限り、常に値は保持される」という特徴があります。例えば、入力イベントに1つカウントアップするマクロを繋げると、ボタンを押すたびに1, 2, 3... と一つずつ増えてくれます。このアクタが破棄されるまで、この値がクリアされることはありません。(もちろん、自分でクリアした場合は除きます)

f:id:sgtech:20181125230212p:plain

ボタンを押すたび1増やす例

f:id:sgtech:20181125230325p:plain

Count Upマクロの実装

ただし、イベントグラフ内ではなく、関数内でマクロ内ローカル変数を使った場合、関数呼び出しのたびに値がクリアされますので注意してください。例えば、関数内で DoOnce マクロを使って、思ったように動かなかった経験のある方はたくさんいらっしゃると思います。これもマクロ内ローカル変数のこの性質が原因です。(どちらかというと、イベントグラフが特殊で、関数が普通の挙動をしているのですが…それはさておき)

興味のある方は、UE4標準の種々のマクロの実装を見てみてください。ダブルクリックするだけで見られます。皆さんが良く使うであろう ForLoop や ForEachLoop もマクロ内ローカル変数を使って実装されていますよ。

TickEvent Open/Close Flap (Modified)

さて、次は TickEvent Open/Close Flap関数がどう変わったか見てみましょう。

f:id:sgtech:20181125230322p:plain

こちらは比較的トリッキーです。戸惑われた方もいらっしゃるかもしれません。マクロが2か所あるのは良いとして、恐るべきことに(?)1つのグラフにカスタムイベントが3つ繋がっています。

それでは個々に見ていきましょう。まずは、Elapsed Seconds Macroから。経過時間を格納していたメンバ変数Elapsed Secondsをこのマクロで置き換えています。

f:id:sgtech:20181125230318p:plain

ここまでに紹介してきたマクロとほぼ同じような形ですが、InputsノードにあるResetピンで経過時間をゼロクリアできるようにしてあります。カスタムイベントTickEvent Open/Close Flap (Modified)のグラフをもう一度見てみてください。このResetピンには、カスタムイベント Reset ElapsedSeconds が繋がっており、さらにそのReset ElapsedSecondsイベントは、Sequence - Then 1の、時間経過後のOpen/Close切り替え時に呼び出されています。ここで、ElapsedTimeにゼロをセットするのと同等の処理を行っているわけです。

次に Make Flap Height Macro (Modified) マクロについて。これは「普通版」の同名マクロを変更して、メンバ変数CloseFlagを置き換えました。

f:id:sgtech:20181125230314p:plain

変更前のMake Flap Height Macroと見比べていただくと分かると思いますが、

  • CloseFlagの代わりにマクロ内ローカル変数を用意。
  • Toggle Open/Close ピンを新設して、CloseFlagの役割をするBoolean型のマクロ内ローカル変数のTrue/Falseを切り替え。
  • Toggle Open/Closeピンには、カスタムイベントToggle Open/Closeを繋げ、時間経過でのOpen/Close切り替えのタイミングでこのカスタムイベントを呼び出し。

という仕組みになっています。

いかがでしょうか。これでActorクラスにとって重要度の低い3つの変数 CloseFlag、ElapsedSeconds、FlapYawがメンバ変数から消えて、まさに必要な部分だけに登場する適材適所なグラフになりました。
(その代償として、初心者お断りなトリッキーなグラフになっていますが…)

次はさらにマニアックな技です。ご注意を!

さて、重要度の低い4つの変数のうち3つを「適材適所」な位置に移すことが出来ました。こうなると、最後の1つFlapHeightもメンバ変数から外してしまいたくなります。

あらかじめ言っておきます。ここから先はマニアックな使い方になります(ここまでも十分マニアックかもしれませんが)。ですので、他人がノードグラフを見ると、頭の上にクエスチョンマークを浮かべてしまうかもしれません。あるいは先輩に「やりすぎだ!可読性を上げろ!」と怒られてしまうかもしれません。

f:id:sgtech:20181125230310p:plain

  • TickEvent UpdateFlap (Maniac)
    ・TickEvent UpdateFlapのマニアック版です。
    ・ここまでに登場した同名イベントと同様、算出された高さと回転角度をフタ(Flap)モデルにセットしています。
  • TickEvent Open/Close Flap (Maniac)
    ・TickEvent Open/Close Flapのマニアック版です。
    ・ここまでに登場した同名イベントと同様、経過時間を計算し、そこからフタ(Flap)の高さを算出しています。
  • Flap LotationマクロとFlap Rotationマクロ
    ・Set Relative Location And Rotation 関数のNew Location引数とNew Rotation引数をバラすのが面倒になったので、マクロを作って見た目をシンプルにしています。
    ・Flap Location マクロ
     f:id:sgtech:20181125230429p:plain
    ・Flap Rotationマクロ
     f:id:sgtech:20181125230426p:plain

さて、このマニアック版でのミソは、カスタムイベントSet Flap Height (Maniac)と、Set Flap Height Macroです。

Set Flap Height Macro

f:id:sgtech:20181125230422p:plain

  • Inputsノードに指定されたマクロの引数In Flap Heightを、Float型のマクロ内ローカル変数に格納しています。
  • Outputsノードから、その格納された値をOut Flap Heightとして出力しています。

一見、全く何の意味もないプログラムのようにも思えますが、このマクロは「Event Graph内に限り、マクロ内ローカル変数の値は保持され続ける」特性を利用して、変数のGETとSETの両方の機能を持たせたものです。

  • SET機能: カスタムイベントSet Flap Height (Maniac)が呼び出されると、その引数の値をマクロ内ローカル変数にSETする。
    ・つまり、カスタムイベント、TickEvent Open/Close Flap (Maniac)でフタ(Flap)の高さが決まった際に、FlapHeight変数にその高さをSETする代わりにカスタムイベントSet Flap Height (Maniac)を呼び出します。
    ・SET(Assign)された値は、再びSET(Assign)されるまで、変更されることはありません。
  • GET機能: Out Flap Height を通じて、マクロ内ローカル変数に格納された値をGETする。
    ・マクロ内ローカル変数に格納された値は、Event Graph内であれば、いつでもGETすることができます。

このマクロを用いて、TickEvent UpdateFlap (Maniac)や TickEvent Open/Close Flap (Maniac)イベントは、以下のメカニズムで動いています:

  • TickEvent UpdateFlap (Maniac)で、Set Relative Location And Rotationが呼び出される際、Set Flap Height Macroの出力Out Flap Height経由で、マクロ内ローカル変数に格納された値(現時点のフタ(Flap)の高さ)をGETしています。
  • TickEvent Open/Close Flap (Maniac)で、Make Flap Height Macro (Maniac)で算出されたフタ(Flap)の高さを、Set Flap Height (Maniac)イベントを使って、マクロ内ローカル変数にSETしています。

さすがに無理矢理やった感は否めませんが、Actorのメンバ変数からはフタ(Flap)の上下動に関する4つの変数をメンバ変数欄から消すことができ、Event Graph内の必要なところでのみGETあるいはSETされる「適材適所」な形に整理することができました。

マクロ内ローカル変数を活用する際の注意点

  • デバッグが難しい: ウォッチができないので、Print Stringなどのログ出力を使う必要があります。
  • スパゲッティになりがち: マクロ内変数が増えるたびに、おびただしい数のラインが増えてしまい、可読性が非常に下がります。

簡潔に言うと、気を付けないとバグの温床になりやすい、ということです。そういう意味では、UE4やプログラミングにある程度慣れた人以外は、多用しない方が良いかもしれません。まずは、小さなサンプルを作って試し、正しく動くことを確認出来たら本使用に移すなど、守備的な方法で運用するように注意してください。特にチームで作業している場合は、チーム全員でマクロ内ローカル変数をどう使うかの意思統一してから使うべきでしょう。

弾幕で分かるBlueprintの限界

さて、次はBlueprintの最適化とプロファイリングの話をしましょう。

ぷちコン応募作品「Gravity One」は弾幕シューティングを目指しました。その意気込みの割には密度が薄かったのは反省点ですが… やはり弾が多いと処理落ちしてしまうのです。

Blueprintは重いと知りつつも、Blueprint信者としてC++に逃げることは許されません。結局、弾一個一個をアクタで作ってしまいました。結果、本当に重くなってしまい、ボス戦などでは60FPSをキープできていません。というか、40FPSくらいです。ホント、プロとしてお恥ずかしい限りです。

f:id:sgtech:20181125230408p:plain

この弾幕の最適化、今までずっと放置していたのですが、今回のブログのネタとしても面白そうだと思ったのでやってみました。Blueprint信者としての信念を曲げてのC++化もやっています。ここではそのあたりのお話をさせていただこうと思います。

当初から重くなるのは覚悟してました。

もともと弾幕を出すつもりでしたので、作り始めた当初から重くなるのは想定していました。ですので、弾のActorはできる限りシンプルに組んだつもりです。

まずは、Tickの仕事を最小限にするように気を付けました。

f:id:sgtech:20181125230359p:plain

  • Sequence - Then 0: 移動計算は地球表面に沿って直進するだけ(Ballisitic Object.Update)。その結果をSet Actor Location And Rotationに渡している。
  • Sequence - Then 1: Dynamic Material Instance を使って、時間に応じて色を変化させる。
  • Sequence - Then 2: 一定時間で自滅させる。

コンポーネントの構成も非常にシンプルです。

f:id:sgtech:20181125230512p:plain

  • Sphere Collision: ルートコンポーネントとして球コリジョンを使っています。
  • Bullet: その子コンポーネントとして、Material Billboard Component を使っています。つまりメッシュですらありません。

コリジョンプロファイルも限定的にしました。

f:id:sgtech:20181125230509p:plain

  • プレイヤーオブジェクトに対してのみ「Overlap」
  • その他のオブジェクトに対してはすべて「Ignore」
  • 「Block」は一切使っていません。

セッションフロントエンドでCPU負荷をチェックしてみる。

セッションフロントエンド、使ったことのない方は、これを機にぜひ使ってみてください。使い方は、UE4公式にあります。ちゃんとわかりやすく書かれているのでご安心を。

では、ボス戦をDevelopmentパッケージで調べてみた結果を見てみましょう。

f:id:sgtech:20181125230505p:plain

画像をクリックすると拡大して見られますが、それでも見づらいと思いますので要点をまとめます。

  • 敵の弾Actor (BP_EnemyBullet01)がダントツで重い。14.404 ms。案の定、弾幕がボトルネックになっていた。

そのうち顕著なのは、

  • Set Actor Location And Rotation 7.167 ms/コール数 814.3
  • BP_BallisticObject.Update 2.582 ms/コール数 814.3

となっています。

ちなみに60FPSですと、1フレームは16.667 msです。
つまり、弾幕だけでCPUリソースの14.404 / 16.667(9割弱!)使っていることになります。

最初からシンプルになるように組んだことが功を奏しています。なぜなら、ボトルネックのトップとしてUE4の標準関数(Set Actor Location And Rotation)が挙がっており、自作の関数たちは次点以下になっているからです。自作の関数BP_BallisticObject.Updateが次点ですので、ここはもちろん考察しておくべきですね。

まずは、自作関数を見てみましょうか。

では、ボトルネック次点となった自作関数BP_BallisiticObject.Updateから。

f:id:sgtech:20181125230459p:plain

正直なところ、この関数もとてもシンプルで、これを最適化しろと言われると困ってしまいます。やっていることは、1フレーム前の「弾を地球中心から見たベクトル」を、今回の移動量分だけ地球の中心で回転しているだけです。

この関数については、最適化方針が見出せなかったので見送ります。これ以上軽くするには「とんち」(試行錯誤の労力、あるいは天才的な閃き)が必要そうです。後述しますが、結局は、こんなシンプルな関数でも大量に呼び出されるとボトルネックとなってしまうということですね。なんせ、ボス戦では700~1000個の弾が動いているわけですから。

では、Set Actor Location And Rotation をどうにかしましょうか。

念のため言っておきますが、UE4標準関数のSet Actor Location and RotationのC++コードにテコを入れるという話ではありませんよ。ここで問題視したいのは、コール回数の多さです。ざっくり調べてみたところ700~1000回の呼び出しがありました。ですので、今回の最適化の方針は

  • Set Actor Location And Rotation を呼ばなくていい時は呼ばない

ということにしてみます。

それはそうと、Set Actor Location And Rotation をはじめ、アクタのトランスフォームをセットする関数(以下、総称して Set Actor Transform系と呼びます)が重いということを知らない人が意外と多いようです。

f:id:sgtech:20181125230455p:plain

せっかくセッションフロントエンドを開いていますので、Set Actor Location And Rotation のやっていることをざっくり確認してみましょう。

f:id:sgtech:20181125230559p:plain

見づらいでしょうから、要約します。なお、エンジンのC++コードを開いて詳しく調べたわけではなく、関数名から想像した話でしかありませんので、ご注意を。

GeomSweepMultiple 2.480 ms/コール数 814.3

関数名から、コリジョンのSweep形状を作っていると想像できます。Set Actor Transform系の「Sweep」パラメータが関連するのでしょう。

f:id:sgtech:20181125230556p:plain

ということは、Sweepしない方が軽いのでしょうが、さすがにSweep処理なしでシューティングゲームを作るのは至難の業ですね。

UpdateComponentToWorld 2.037 ms/コール数 814.3

関数名から、そのアクタに付随するコンポーネントのトランスフォームをワールド系に変換していると想像できます。つまりは、コンポーネントが多ければ多いほど重くなるのでしょう。

Set Actor Location And Rotationのその他の処理

  • Component PostUpdateNavData: NavMesh系の処理だと想像できます。NavMeshが不要なら切りましょう。
  • UpdateOverlaps Time, MoveComponent FastOverlap: どちらもコリジョンのOverlap系の処理だと想像できます。

これらをまとめると、下記のようになるでしょうか。

  • Sweepが不要なら、積極的にOFFにする。
  • コンポーネントの数を必要最小限にする。
  • NavMeshが不要なら、積極的にOFFにする。

また、Set Actor Transform系が重いということから、UE4の基本として:

  • そもそも、Set Actor Transform系の呼び出しは、Tick1回の流れで1回だけにとどめるべき。

についても留意するようにしましょう。

カリング処理を作ってみる。

f:id:sgtech:20181125230551p:plain

上の画像は、地球を非表示にした状態でのボス戦です。見ての通り、実は地球の裏側でも弾幕が動いていたのです。どうしようもなく無駄ですね。このような見えないところにあるオブジェクトの処理を省くことを、カリング処理といいます。

カリング処理については、Gravity Oneを実装していた当初から、気にしつつも放置してきた部分です。と言いますか、プロとしてカリング処理をしていないこと自体お恥ずかしい。それくらい基本中の基本です。では、当時の私はなぜカリング処理を実装しなかったのか。もちろん1番の理由は、やることが多すぎてそれどころじゃなかったからですが、実際のところ他にも躊躇する理由があります。

  • 重いと言われているBlueprintでカリング処理を組んだ場合、逆にそのカリング処理が重くてボトルネックになってしまう可能性がある。

Blueprintでは関数コールは重い処理の一つです(関数名で検索してから呼び出す仕組みとの話です)。ノード1個1個が関数に相当しますから、ノードの数が増えると比例して重くなる、ということです。したがって、カリング処理もできる限りシンプルに組む必要がありますが、カリング処理の多くは算術演算が比較的多くなってしまいがちです。ご存知の通りBlueprintでは「+」や「-」すら一つのノードになっています。これも、もちろん関数呼び出しです。つまり算術演算は関数コールが増えやすいものの一つです(なお、Math Expressionを使って軽減することはできます)。この算術演算周りの負荷が高くなってしまった場合、せっかく作った最適化処理(カリング処理)は逆効果となってしまいます。ここを懸念していました。

Blueprintでの最適化処理は、(今の私のUE4技能レベルですと)「とりあえず作ってみて、効果を確認する」の試行錯誤を繰り返すことが必要だと思います。労力がかかる上に、うまく行くかどうかが不明。困ったものです。そういう意味では、Blueprintでの最適化に悩まずに、とっととC++へ移行した方が、費用対効果は高いかもしれません。

今、このブログの執筆時点では、時間に追われているわけではありませんし、面白そうだし!ということで、やってみました。

内積1発で済ますカリング処理。

上記に書いた通り、Blueprintで組んだカリング処理が重くなっては意味がありません。ある意味、C++で組まれたUE4標準関数Set Actor Location And Rotationに勝てるような、できる限りシンプルなカリング処理を選ぶ必要があります。そこで今回は「内積1発でざっくり判定」する方法を選びました。

もともと、プレイヤー機や敵の弾をはじめ、すべてのアクタのUpベクトルが地球表面の法線ベクトル(球の中心から球面を垂直に突き抜けるベクトル)に一致するように作ってあります。このUpベクトル同士の内積を取れば、プレイヤー機と敵の弾の「球面に対する」位置関係が分かるはずです。内積の値が1に近ければ、球面上でプレイヤー機に近い位置にいて、-1に近ければ、球面上では反対側にいるはずです。

結果、弾のアクタのTickはこうなりました。

f:id:sgtech:20181125230547p:plain



  • クラスメンバ変数Location (OptTest)とRotation (OptTest)を用意。修正前ではGet Actor Locationから取得し、Set Actor Location And Rotation でセットしていたところを、いったんこの変数に保存している。これは、Set Actor Location And Rotation を呼ばなくても、Tickのたびに更新される位置と回転を保持しておくため。
  • 修正前ではSet Actor Location And Rotationを呼び出していた場所で、カスタムイベント「TickEvent Cull If Outsight」を呼び出している。このカスタムイベントについては後述する。
  • その他の個所については、変更なし。

カスタムイベント TickEvent Cull If Outsight

f:id:sgtech:20181125230625p:plain

  • TickEvent Cull If Outsight: プレイヤー機と敵の弾のUpベクトル同士の内積の大小を判定しているところ。Math Expressionの 0.7071は cos(45度)の値。つまりプレイヤー機のUpベクトルとの角度差が45度以内のものを可視と判定している。
  • SubEvent Cull If Outsight > Sequence - Then 0: 可視圏内/可視圏外へ切り替わった時の処理。SweepのOFFと、コリジョンのON/OFF、アクタの表示/非表示を切り替えている。可視圏内に入った直後はSweepをOFFにしておかないと、過去の可視圏内だった位置から可視圏内に戻った現在位置まで、長いSweepが作られてしまい、意図せぬコリジョンが発生してしまう。
  • SubEvent Cull If Outsight > Sequence - Then 1: 可視であれば Set Actor Location And Rotation を呼び出した後、SweepフラグをTrueにしている。

さて、「内積1発で済ます」と言った割には大きなノードグラフになってしまいました。これがプログラミングの怖いところですね。果たしてこの修正でパフォーマンスは改善したのでしょうか。

セッションフロントエンド再び。

f:id:sgtech:20181125230544p:plain

  • 敵の弾Actorの負荷は 2.991 ms改善(14.404 msから11.413 msへ)
  • Set Actor Location And Rotation のコール数が半減(814.3から429.0へ)。今回作ったカリング処理で、半数の弾の Set Actor Location And Rotation が呼ばれなくなったため。結果、負荷が半減(7.167 msから3.566 msへ)。
  • BP_BallisticObject.Update は現状維持(変更を加えていないため)

おおよそ3 msの軽減という、良い結果が得られました。Blueprintでも負荷の低いカリング処理が組めたようです。3 msというと、単純計算で弾があと234.5個出せます。これはかなり良い結果と言えます。成果が得られずに色々な手法を試行錯誤する覚悟をしていましたが、一回で結果が出てホッとしています。

現実のゲーム開発では0.5 msも稼げれば相当頑張ったと言えます。各プログラマがおのおの自分の担当分野で頑張って少しずつ稼ぎ、合計で3 ms稼ぐ、といったところです。そういう意味では、今回の3 msという成果は、逆に怒られる領域かもしれませんね。「こんな基本的なところを今までなぜ放置してた!」と。(はい。申し訳ありません…)

C++化も試してみる。

さて、せっかくですからC++化も試してみましょう。C++化と言っても「Nativize」の方です。ところで「Nativize」とは日本人には非常に読みにくい綴りです。Web辞書で調べてみたところ「ネイティバイズ」と発音するようです。このNativize機能はUE4による「自動C++化」です。非常にありがたい機能が実装されたものです。

プロジェクトセッティングを見てみると、Nativizeには3つのモードがあります。Project Settings >Project > PackagingにあるBlueprint > Blueprint Nativization Method の項目があります。

f:id:sgtech:20181125230639p:plain

  • Disabled: Nativizeなし。デフォルト。
  • Inclusive: プロジェクトのBlueprintをまるっと一式Nativizeする。
  • Exclusive: 指定されたBlueprintのみNativizeする。(ただし関連するBlueprintも一緒にNativizeされる)

残念ながら、Nativize機能はうまく行く場合とうまく行かない場合があるようです。本シューティングゲームGravity Oneも、Inclusive(まるっと全部)のNativizeはエラーが出てしまい、うまく行きませんでした。今後のアップデートに期待です。

一方、今回の「敵の弾」に対してのみNativizeするように指定した、Exclusiveモードではうまく行きました。今回はこちらについてお話します。

ExclusiveなNativizeのしかた

まずは、NativizeしたいBlueprintを開き、上のボタンバーから「Class Settings」をクリックします。そうすると詳細パネルにクラス設定一覧が出ますので、その中の「Packaging > Nativize」にチェックマークを入れます。

f:id:sgtech:20181125230636p:plain

これをNativizeしたいすべてのBlueprintに対して行います。なお、チェックマークを入れたBlueprintだけでなく、それと参照関係にある他の(チェックマークを入れていない)BlueprintもNativizeの対象となるようです。それがいわゆるReference Viewerでみられる参照関係と同じなのか、他に法則があるのか、などは調べていないので分かりません。悪しからずご了承を。

次に、プロジェクトセッティングを開き、Project > Packagingから、Blueprints > Blueprint Nativization Methodを「Exclusive」にします。(意外とこの設定を忘れがち)

f:id:sgtech:20181125230634p:plain

あとは、パッケージングするだけです。ちゃんとNativizedされたかどうかを確認するには、Output Logで「NativizedAssets.cpp」を検索すると良いでしょう。また、NativizedAssets.cppの付近には、NativizeされたBlueprint名に妙な数字と.cppがつけられて並んでいますので、何がC++化されたかを知ることもできます。

今回は、カリング処理なし/ありの両方についてNativizeしてみました。それらのプロファイリング結果を見てみましょう。

Nativizeされた弾幕はどれくらい軽いか?

結果を以下に並べてみます。()内の数字は、最適化前の状態のNativizeなし/カリングなしの状態に対して、何 ms高速化できたかを表しています。

  • Nativeなし/カリングなし 14.404 ms(0.000 ms)
  • Nativeなし/カリングあり 11.413 ms(2.991 ms高速化!)
  • Nativeあり/カリングなし 7.618 ms(6.786 ms高速化!)
  • Nativeあり/カリングあり 7.266 ms(7.138 ms高速化!)

見ての通り、小躍りしたくなるような結果を得られました。これを見ると手動でC++を組むのがばかばかしくなってきますね! 問題はNativizeが失敗することが多々あることですが、今後のUE4アップデートに期待することにしましょう。

弾幕で分かるBlueprintの限界

ここまでの話をまとめます。文字ばっかりになりますが、ご容赦くださいね。

Blueprintをできるだけ軽く組むために。

Blueprintは非常にサクサク組めて、イテレーションサイクル(試行錯誤の繰り返し)も速いので、UE4でのゲーム開発では積極的に取り入れるべきものだと思います。一方で、Blueprintは所詮スクリプトに過ぎないという一面もありますので、CPUパフォーマンスに問題が出やすいのも事実です。大事なことは、Blueprint/Nativize/手動C++の境界をどこに置くかで、これを見極めることができると、サクサク作れて高パフォーマンス、という夢のような環境を手に入れることも不可能ではないでしょう。

その見極めの基準の一例として、Blueprintで注意するべき項目を並べてみようと思います。これはあくまで私個人の見解で、セガのUE4エンジニアの総意ではありませんので、その辺はご注意ください。

  • アクタの数やTickの数を必要最低限に絞る: この数は純粋にCPU負荷に影響します。今回の弾幕のようにアクタ数が多いと、明確に分かりやすく処理落ちし始めます。まずは、アクタの数を必要最低限に絞ることです。また、Set Actor Tick Enabledなどを使って、不要なTickは切ってしまいましょう。
  • Set Actor Transform系はTick1回につき1回まで: 前述したとおり、一見トランスフォームをセットするだけのように見えて、その中ではコリジョンのSweep処理や、コンポーネントの座標変換など多くの処理が行われています。位置や回転などのトランスフォーム値は変数で計算しておき、確定した段階でSet Actor Transform系を呼び出すようにしましょう。また、不要なSweepは行わないこと、コンポーネントの数を絞ることも大事です。
  • ループの数を減らす: 今回の記事では取り上げていませんが、Blueprintのループ処理も重い処理の一つです。試しに、256回回るForLoopを2重にして(つまり256x256=65536回ループ)実行してみてください。劇的に重いことが分かるかと思います。これは、パッケージ化すると改善はされますが、劇的に軽くなるわけではありません。また、ループはエディタでの実行とパッケージでの実行との速度差が大きく、開発中にCPU負荷を見積もるのが難しいので、ループを多用している場合は、パッケージでの動作チェックを頻繁にすべきでしょう。
  • できる限りノードの数を減らす: Blueprintの関数呼び出し、イベント呼び出しは、比較的重い処理のようです。できる限りシンプルなノードグラフを組んで、関数呼び出しそのものを減らす工夫をしましょう。また、UE4標準で用意されている関数は、たいていは内部がC++化されています。似た処理を複数のBlueprintノードで自作するよりは、UE4標準関数を積極的に使いましょう。また、UE4アップデートのたびに便利関数がこっそり増えていたりします。UE4リリースノートや右クリックの検索ウィンドウなどを活用して、新しいノードや機能をマメにチェックしましょう。

何を基準にNativize/手動C++化に踏み切るか。

個人的には、上記4項目がそこそこ出来ているならば、最適化処理をBlueprintで組んで試行錯誤するより、Nativizeを試すべきだと思っています。そういう意味では、上記4項目がBlueprintの限界点だと言えます。

今回例に挙げたカリング処理は幸いにも成果を得られましたが、一方で、Blueprintで最適化を模索するのは、Blueprintそのものの重さが災いして、うまく行かない可能性も高いと思っています。その試行錯誤にかけた手間暇に対して、得られる効果が見合ったものかどうか、いわゆるコストパフォーマンスは、私のUE4技能レベルではまだまだ謎の領域にあります。

ですので、Blueprintが一定のレベルまで組めているなら、最適化の模索より先にNativizeを試すほうが建設的かと思います。前述したとおり、得られる効果は絶大です。Nativizeでエラーが出てしまうようなら、そこで初めて、Blueprintでの最適化を模索するか、手動でC++を組むかを悩むべきでしょう。

ここで、Blueprintでの最適化と、手動でのC++化が、同レベルで天秤に掛かっていることを不思議に思う方もいらっしゃるでしょう。一見、手動C++化で決まりだと思えます。しかし、私が手動によるC++化を避けている理由は、関連するゲームプログラム周りの設計を再構成する必要がでてしまいやすい点にあります。例えば、ゲームバランスに直結するようなBlueprintを安易にC++化してしまうと、以後ゲームバランスを変更するたびに Visual Studio でのビルドが必要になり、作業スピードが落ちてしまいます。また、アーティストやレベルデザイナーが頻繁に触っているBlueprintをC++化するわけにもいきません。そのためには、基底クラスをC++で作って、そのBlueprintの親にする等、何を表(Blueprint)に出して、何を裏(C++)に隠すかを設計しなおさなくてはならないのです。一方のNativizeはパッケージングにのみ影響する機能ですから、その辺の心配はいりません。

手動C++化については、もっと気楽な方法もあります。Blueprintでゲーム全体を組むと決めてしまい、C++はそのためのツールを提供するためのものと割り切ってしまうことです。例えば、基本機能を充実させた、そのゲーム専用の基底クラスをC++で作っておいて、Blueprint側はその基底クラスを派生して使うようにする、他には便利関数や便利クラスなどの小さいが高速なモジュールをC++で用意しておくなどです。

まあ、これらはBlueprint信者の妄信かもしれません。参考にしていただきつつも、皆さんは皆さん流のBlueprint/C++使い分け術を見出していただければと思います。

おわりに

 夢中になって書いてしまった結果、非常に長くなってしまいました。ここまで読んでくださった皆さん、本当にありがとうございます! 楽しんでいただけましたでしょうか?

とは言え、これでも書こうと思っていたトピックの4分の1だったりします。現時点でもあと6つくらいトピックがありますし、今後もUE4を使う限りどんどん増えていくでしょう。また、社内の他のUE4エンジニアたちも、あれこれたくさんトピックを持っているようです。今回紹介できなかったトピックも、また機会を作って紹介できればと思っています。

ですので、今回の記事をお楽しみいただけた方、ぜひご反響をくださいませ! 今後もUE4のトピックをどんどん増やしていきたいと思います。

インディーズのススメ

ゲームエンジンの時代が到来して久しいですね。それに伴い、そのゲームエンジンで活かしてもらおうと、3Dモデリング環境や、画像・映像制作環境など、ゲームの素材を作る環境もどんどん安価に・身近になってきています。冒頭でもいくつかツールを紹介しましたが、今やゲーム制作環境の大部分が一般に降りてきています。何ならフリーのツールだけでも全部作れてしまいます。やる気さえあれば、誰でもゲームを作れる時代が到来しました。

今回題材に使いましたぷちコン応募作品「Gravity One」も、未完ながら「MAGITYPE」も、概ね全部の素材を私一人で作っています(もちろん、ものすごく大変でしたけど)。一昔前なら、チームを組まなくては作れない規模のゲームも、いまや個人や少人数グループの頑張りで作れてしまいます。

明らかに時代は変わってきています。ゲームエンジンが台頭する前は「特定の分野一つに強い職人」を集め、チームを組んで、リーダーが全体を統括しながら作る時代でした。それゆえに、企業が強い分野でもありました。一方、昨今では、高度な/専門的な知識はあらかじめゲームエンジンに内包されており、ゲーム開発者は「その使い方と効能」を理解してさえいれば良くなりました。その結果、ゲーム開発者は、特定の分野一つを専門にして深く理解/応用する労力から解放され、複数の分野に渡って広く知る余裕が出来てきました。

今後は、「複数の分野を知っていて、それらを上手く組み合わせてコンテンツを作れる人」同士がチームを組んで、その相乗効果でより面白いものを作る時代になるのでしょう。ゲーム開発者はより「面白さ」に専念できるようになりました。

皆さんも、小規模で良いので、「一つのパッケージを自分一人で作り上げる」を試してみてはいかがでしょうか。他人の評価を得ることは何にもまして勉強になりますし、その成果を何らかの形で発表すると、なお良いでしょう。ゲーム制作の全部の流れを何となくでも知っておく(体に通しておく)と、非常に視野が広がり、例えば、プログラマがアーティストの作業を知ると、以後、お互いの作業領域に重なりができることで、お互いにカバーしあえる体制が出来上がります。これは非常に良い信頼関係となります。

ゲームエンジンの台頭によって、ゲーム開発者の価値が変わりつつあります。今はまだ「UE4を上手く使える」「Unityを上手く使える」という技能面だけで、それなりのステータスを得られますが、将来は、ゲームエンジンを上手に使えることよりも、「どんなテイストのゲームが作れるか」「どんな触り心地のゲームが作れるか」といった「クリエイティブ力」が、今まで以上に、ゲーム開発者の価値となる時代が来るでしょう。例えば、いわゆる「絵師さん」。そのテイストや画風が人々に受け入れられ、その絵師さんの価値となるように、あなたの作ったゲームの「テイスト」や「触り心地」が人々に受け入れられ、あなたの価値となる、そういう時代になるのでしょう。

セガ・インタラクティブではUE4エンジニアを募集しています。

長いうえに説教臭い話でしたね。すみません。私も年を取ったもんです。

それはさておき。

我ら「セガ・インタラクティブ」は、アーケードゲームをはじめ、スマホ、テーマパーク、ショッピングモール、はたまたeスポーツなどなど、様々なマーケットにエンタメを投入する、セガの中でも一風変わったオモシロカンパニーであります。弊社では、UE4エンジニアがまだまだ足りません。まさに、この長い記事を最後まで読んでくださったイケてるUE4遣い(とその候補)の皆さん! 弊社にご興味を持っていただけると嬉しいです。

採用情報などはこちらに記載されています。是非ご確認ください。

採用情報|株式会社セガ・インタラクティブ - 【SEGA Interactive Co., Ltd.】

 

また、UE4インターンも「画策」しています。「開催」や「予定」と書かず「画策」と書いたのは、まだいつ開催できるかが不明だからですが、弊社のUE4エンジニアと、イケてるUE4遣い(とその候補)の皆さんとで、一緒にゲーム開発を体験できれば!と思っています。開催された折にはぜひご参加くださいませ。

弊社では、もちろんUnityタイトルも出しています。スマホに限らず、ゲームセンターにもUnityタイトルを出していますので、イケてるUnity遣い(とその候補)の皆さんも是非、セガ・インタラクティブへ! そして、おそらく最も万能な、イケてるC++遣い(とその候補)の皆さんも是非、セガ・インタラクティブへ!

私たちと一緒にオモシロ体験を作っていきませんか?

 

©SEGA

新卒からのTAが内製ツールに動画撮影機能をつけてみた話

初めまして。

セガゲームス開発サポート部テクニカルアーティストの清水と申します。
新卒からテクニカルアーティスト(以後TA)業務に積極的に関わらせてもらい、今年で社会人歴TA歴共に3年目になります。

今回は、弊社で使われてる内製ツールHNDViewerにコマンドライン実行を組み込み、アセットのモーションGIF画像を自動生成できるようにした時の対応について紹介させていただきます。

概要

独自の内製ビューアに動画撮影機能を実装し、「モーションプレビュー一覧を半自動的に作成する環境を構築する」
という目的のもと、以下のようなコマンドをJenkinsで自動定期実行することにより、内製ビューアがGif画像を自動で生成できるようにしてみました。

HNDViewer.exe -cmd -exec=capturegif -out=D:\foruda\output -open=D:\directory\Narita_Ann_mojimoji.hn2v -width=600 -height=450

f:id:sgtech:20181023232429g:plain
モーションのGif画像 (C)SEGA

今回紹介する事例で取り組んだ内容は、3つの内容から成り立っています。
・内製3DCGモデルビューアHNDViewerにモデルのモーションに関するGIF画像を生成する機能を追加した。
・HNDViewerにコマンドライン実行機能を追加して、モデルのモーションに関するGIF画像を生成する機能をコマンドライン実行できるようにした。
・実装したコマンドラインをJenkinsから実行することで、モデルのモーションに関するGIF画像の生成を自動化した。

まず、今回紹介するアプリケーションについて、触れておきましょう。

f:id:sgtech:20181023232512p:plain
概要

HNDViewerとは?

弊社には、3D CGツールのデータをエクスポートして格納するための中間構造を扱うHNDというシステムがあります。
HNDViewerとは、このHNDを格納した「HNDファイル」のビューアツールです。

格納されている3DCGデータの表示・再生はもちろん、各ポリゴンやノードのパラメータを一覧することもできます。

f:id:sgtech:20181023232418p:plain
HNDViewer

Jenkinsとは?

Jenkinsとは、ソフトウェアの実行等の一連の作業を自動化できる自動実行ツールです。

jenkins.io

高い汎用性を持った自動実行ツールで、事前に設定した条件を満たすたびに指定したコマンドを自動で実行してくれます。

自動実行に指定できるのは基本的にbat処理などのコマンドライン実行可能な処理になります。

ここからは少し実装の話に入っていきます。

GIF画像の生成

今回はImageMagickを使用してgif画像を作成する方法を採用しました。

www.imagemagick.org

ImageMagickは、幅広い画像ファイルフォーマットに対応している、画像を操作したり表示したりするためのソフトウェアです。 コマンドラインツールを含んでおり、バッチ処理での画像の変換・編集などに必要な機能が揃っています。

ImageMagickを使用して指定した連番画像からGif画像を生成することができます。

HNDViewerには下記の3つの機能はすでに搭載されています。
・3DCGモデルを表示する
・モデルのモーションを再生する
・モデルを表示している画面のスクリーンショットを作成する
従ってGif画像を作成するために追加する必要のある機能は下記の2つです。
・モデルのモーションの連番画像を作成する機能
・ImageMagickに連番画像を受け渡してGIF画像を作成してもらう機能

まず、読み込んだモデルを1フレームずつ動かして表示している画面をキャプチャし、画像として一時フォルダへ保存します。 これをモーションの最終フレームまで行い、モデルのモーションの連番画像を作成します。

f:id:sgtech:20181023232423p:plain
連番画像の作成

モデルのモーションの連番画像の生成が完了したら、ImageMagickを利用してGIF画像を生成します。

キャプチャした連番画像をImageMagickのコマンドラインツールであるconvert.exeの引数に渡してGIF画像を作成します。

 convert.exe -delay 3.3 -loop 0 キャプチャした画像_*.png キャプチャした画像.gif  

これでGIF画像の生成は完了です。

GIF画像の生成処理が終了したことを確認したら、一時フォルダに保存してあるGIF画像の生成に使用した連番画像はすべて削除します。

これでモデルのモーションに関するGIF画像を作成する機能ができました。

コマンドライン実行の追加

モデルのモーションに関するGIF画像を作成する機能を実装したHNDViewerは、GUIツールでコマンドラインから処理を実行する機能は持たないため、次にHNDViewerにコマンドライン実行機能の追加をしていきます。

コマンドライン実行時の引数の入力方法について

入力する引数については以下のようなルールを採用しました。
・引数はキーとなる文字列とパラメータを「=」で接続したものを一つの引数として入力する。
・キーとなる文字列の頭には「/」もしくは「-」を付ける。
このような引数をプログラム側でパースしてパラメータを読み込みます。

つまり、以下の2種類のうち、いずれかの引数を入力するルールとします。

application.exe -cmd -exec=コマンド名 -out=出力ディレクトリ -open=出力ファイル -width=画像の横幅 -height=画像の縦幅  

または

application.exe /cmd /exec=コマンド名 /out=出力ディレクトリ /open=出力ファイル /width=画像の横幅 /height=画像の縦幅  

そして、次のようにプログラム側で引数を=でパースし、辞書にします。

Dictionary<string, string> ParseArgs(string[] args)  
{  
    Dictionary<string, string> ParsedArgsDictionary = new Dictionary<string, string>();  
    char[] splitters = { '=' };  
    foreach (string line in args)  
    {  
        string s = line;  
        if (s.StartsWith("/") || s.StartsWith("-"))  
        {  
            s = s.Remove(0, 1);  
        }  
        args = s.Split(splitters);  
        if (args.Length > 1)  
        {  
            ParsedArgsDictionary.Add(args[0], args[1]);  
        }  
        else  
        {  
            ParsedArgsDictionary.Add(args[0], "");  
        }  
    }  
    return ParsedArgsDictionary;  
}  

この引数の入力方法は以下のような利点があります。

・コマンドを使用する際にどのパラメーターにどの値を入力しようとしているのかユーザーに分かりやすい

例:通常のスペース区切りの場合

HNDViewer.exe capturegif D:\foruda\models D:\directory\model 640 320

capturegifはコマンド名であることは推測できます。

また、2つあるパスは入力先と出力先を表していると推測できます。

が、どちらが入力でどちらが出力かは読み取ることはできません。

残り2つの数値については何を表すのかは推測することすら困難です。

しかし、このルールを採用した場合

HNDViewer.exe -cmd -exec=capturegif -out=D:\foruda\models -open=D:\directory\model -width=640 -height=320

-exec=capturegifによって実行したい処理がcapturegifであることがわかる。

-outと-openで指定されていることによって入力と出力が一目でわかる。

-widthと-heightによってそれぞれの数値が幅と高さを表していることがわかる。

・アプリケーション側からのユーザーへ対しての通知内容を分かりやすくできる。

コマンドラインに渡す引数の順番を間違えるなどといったミスを事前に防ぐことができる。 各パラメータとパラメータが示すキーが対になっているため、アプリケーション側からどのパラメータに問題があったのかをユーザーに通知できる。

・アプリケーションに関連付けられたファイルを開く処理を明確に分けることができる。

第1引数に「-cmd」のようなコマンドライン実行であることを表すキー文字列が存在することによって、プログラム側は今回の実行がコマンドライン実行であるか否かを明確に判定することができます。

既存ツールへのコマンドライン実行の追加

コマンドライン実行時の処理の流れ

f:id:sgtech:20181023232408p:plain
コマンドライン実行の流れ

コマンドラインの確認

まず、アプリケーションのmain関数内でツール本来の処理に入る前に、 実行時の引数を確認する処理を追加します。

本来の処理に入る前に引数の内容を確認して、第一引数が「-cmd」または「/cmd」であった場合 コマンドラインモードで起動できるようにします。

この「コマンドラインモードで起動するか否か」の判定は、引数の有無で判断してしまうと、関連付けられたファイルを開くことができなくなってしまいますので、必ず引数の内容を確かめるようにします。
これは、アプリケーションが関連付けられたファイルから起動される際に、そのファイルのフルパスが引数1に入るためです。
アプリケーションに関連付けられたファイルがダブルクリックなどで開かれる場合、一般的に起動するアプリケーションには関連付けられたファイルのパスが第1引数に渡されます。
このパスの情報をもとにアプリケーションはファイルを開いた状態で起動することができます。
そのため、コマンドライン実行か否かの判定は引数の有無だけで判断しないようにします。

また、第一引数が「-?」または「/?」であった場合も
コマンドラインモードに遷移するようにして最終的にユーザー対してヘルプが表示されるようにします。

 main(){  
        var args = Environment.GetCommandLineArgs();  
        bool consoleMode=false;  
        //第1引数を確認
        if(args[1].Equals("-cmd") || args[1].Equals("/cmd")){  
            //-cmdまたは/cmdの場合はコマンドライン実行用の処理に遷移するようにする。
            consoleMode=true;
        }
        if(args[1].Equals("-?") || args[1].Equals("/?")){  
            //-?または/?の場合もコマンドライン実行用の処理に遷移するようにする。
            //その後ヘルプを表示するようにする。
            consoleMode=true;
        }
        if(consoleMode){
            //コマンドライン実行用の処理へ遷移 
            Application.Run(new MainForm(consoleMode));  
        } 
        else{
            //通常起動用の処理へ遷移 
            Application.Run(new MainForm()); 
        }
    }

実行コマンドの確認

コマンドライン実行であることが確定した後に、実行しようとしているコマンドがアプリケーションに登録されたコマンドであるかを確認します。 コマンド名が指定されていない場合やアプリケーションに登録されていないコマンド名の場合は、ヘルプを表示して終了させます。

 //CommandListは実行できるコマンドのリスト

    //引数    
    Dictionary<string, string> argsDictionary = ParseArgs(args);
    //引数に実行するコマンド名が含まれているか否か
    if (argsDictionary.ContainsKey("exec")) {
    //実行しようとするコマンドがあるか否か
        if (CommandList.Contains(argsDictionary["exec"])) {
            //コマンドが存在するならば実行する
            ExecuteCommand(argsDictionary);
        }
        else {
            //コマンドが無い場合はヘルプを表示する。
            ShowHelp();
        }
    } else {
        //execが無いということはコマンドが指定されていないということなのでヘルプを表示する。
        ShowHelp();
    }

引数の確認

実行するコマンドが確定した後に実行に必要な引数が全てそろっているか、引数に入力されている値は有効かを確認します。 引数が足りていない場合や引数の内容に問題がある場合は、その旨エラーを出力し、最後にヘルプを表示して終了させます。

以下のコードは私が実装した「capturegif」コマンドの引数確認の例です。

 public Bool CheckCaptureGifImageArgs(Dictionary<string, string> argsDictionary)
    {
        //入力ファイルを確認する。
        if (!argsDictionary.ContainsKey("open")) {
            //引数にopneが存在しない場合は、openが無いことをユーザーに表示してヘルプを表示
            Console.WriteLine("引数[open]がありません。");
            ShowCaptureGifImageHelp();
            return false;
        }
        //入力ファイルが存在するかを確認する。
        string modelpath = argsDictionary.ContainsKey("open");
        if(!File.Exists(modelpath)){
            //opneで指定されたファイルが存在しない場合は、その旨をユーザーに表示してヘルプを表示
            Console.WriteLine("指定されたファイルmodelpathが存在しません。");
            ShowCaptureGifImageHelp();
            return false;
        }

        //出力フォルダを確認する。
        if (!argsDictionary.ContainsKey("out")) {
            //引数にoutが存在しない場合は、outが無いことをユーザーに表示してヘルプを表示
            Console.WriteLine("引数[out]がありません");
            ShowCaptureGifImageHelp();
            return false;
        }
        //出力フォルダが存在するかを確認する。
        string outputDirectory = argsDictionary.ContainsKey("out");
        if(!Directory.Exists(outputDirectory)){
            //outで指定されたフォルダが存在しない場合は、その旨をユーザーに表示してヘルプを表示
            Console.WriteLine("指定されたフォルダoutputDirectoryが存在しません。");
            ShowCaptureGifImageHelp();
            return false;
        }

        //生成するgif画像の大きさを確認する。
        if (argsDictionary.ContainsKey("width") && argsDictionary.ContainsKey("height")) {
            int w = 0;
            int h = 0;
            //widthとheightが数値に変換できるかを確認する。
            if (int.TryParse(argsDictionary["width"], out w) && int.TryParse(argsDictionary["height"], out h)) {
                SetGifImageSize(w, h);
            }
            else{
                //数値に変換できない場合は、その旨をユーザーに表示してヘルプを表示
                Console.WriteLine("widthとheightが数値に変換できませんでした。");
                ShowCaptureGifImageHelp();
                return false;               
            }
        }
        else{
            //引数にwidthとheightが存在しない場合は、その旨をユーザーに表示してヘルプを表示
            Console.WriteLine("引数[width]、[height]がありません。");
            ShowCaptureGifImageHelp();
            return false;
        }

        return true;
    }

処理の実行・アプリケーションの終了

ここまでの手順で、実行するコマンドが決まり、引数に問題ないことが確認できたので、処理を実行します。 処理が終了したら、アプリケーションを終了します。

これでGUIツールだったHNDViewerにコマンドライン実行機能を追加することができました。

既存の機能に対応するコマンド名と処理に必要な引数を決めておき、
設定したコマンド名が実行されたら、対応する既存の機能を実行するように処理を実装することで、コマンドラインからツールの任意の機能を実行できるようになります。

一例として、モデルのモーションに関するGIF画像の生成機能について、コマンド名と引数は以下のように設定しました。

コマンド名 : capturegif
引数

Key 内容
out 出力ディレクトリ
open モデルファイルのパス
width 画像の横幅
height 画像の高さ

複数の作業をバッチ処理にまとめることもできるようになりました。

jenkinsを用いた処理の自動実行

  ここまでで、コマンドライン実行でモデルのモーションに関するGIF画像を作成することができました。
この処理をjenkinsから実行してもらうことで、自動でモデルのモーションに関するGIF画像を作成できるようにします。

jenkinsを立ち上げて新規のジョブを作成し、
Windowsバッチコマンドの実行に、実装したモデルのモーションに関するGIF画像を作成するコマンドを設定します。
自動実行するタイミングは好きなタイミングを指定します。

f:id:sgtech:20181023232413p:plain
jenkinsのジョブが実行するコマンドを設定する。

jenkinsの導入についてはCEDEC2017で講演された以下のセッションの資料がわかりやすくてオススメです。

cedil.cesa.or.jp

これで自動でモデルのモーションに関するGIF画像を作成することができるようになりました。

最後に

いかがでしたでしょうか。

改めて振り返ってみると実装した各処理の内容自体は、特別優れた技術が使われているわけでもなく、普通な実装だなぁと自分でも感じる部分があります。
しかし、その普通な実装の積み重ねで、「アセットのアニメーションGIF画像の自動生成」という目的を達成することができました。

この処理の自動化を実現したことによって、 手作業を必要とせずに、常に最新のモデルのモーションに関するGIF画像を生成できるようになりました。
さらに生成されたGIF画像を用いて、手軽にモデルのモーションを確認できるようになり、作業の効率化に貢献できました。
社内での反響も上々です。

テクニカルアーティストとして実際に業務を経験するまでは、 作業の効率化とは最先端の高度な技術によって実現される「未だかつてない便利」なものだというイメージを持っていたのですが、 実際の業務経験を通して、作業の効率化というのは、案外小さな普通の技術でできている「ちょっとした便利」の組み合わせで成り立っているんだなぁと感じました。 これからもこうした作業の効率化にどんどん取り組んでいき、クリエイターがより快適にゲーム制作に注力できる環境の実現を目指して、頑張っていきたいと思います。

快適なゲーム制作環境の実現や快適な環境でのゲーム制作に興味がある方は、ぜひセガゲームスの採用情報にアクセス!

自己紹介(補足) 

新卒からTAという比較的珍しいキャリアパスを広めるべく過去2回CEDECで登壇などもいたしました。

若手テクニカルアーティストの業務効率改善への貢献、育成について話すラウンドテーブル http://cedec.cesa.or.jp/2017/session/VA/s58da6294d3416/

若手テクニカルアーティストの育成とその役割について話すラウンドテーブル https://2018.cedec.cesa.or.jp/session/detail/s5aafcb42e41b7

参加してくださった方はありがとうございます。
上記セッションについて興味を持たれた方には以下の記事がオススメです。

新卒からテクニカルアーティスト(TA)を育成するために必要なこと>>TAの素養ってなんだろう?
https://entry.cgworld.jp/column/post/201710-cedec-ta.html

TAを増やす改善策は「余裕をもつこと」~若手テクニカルアーティストが大いに語ったラウンドテーブル~CEDEC 2018レポート(3)
https://cgworld.jp/feature/201809-cedec-03tart.html

記事に取り上げてくださった

株式会社ボーンデジタル 尾形美幸様

株式会社ボーンデジタル 小村仁美様

にはこの場を借りて感謝申し上げます。

What Do We Do as a QA Engineer?: Welcome to the Testing World for Game Development

Hello.
I'm Naoki Sakaue. I work as a QA engineer in "Ryu Ga Gotoku Studio" of SEGA Games. I have been creating the video games of "Ryu ga Gotoku/Yakuza" series about 10 years.
In the following article, I will explain the role of a QA engineer and playback the game development history of "Ryu Ga Gotoku Studio".

What Do We Do to Test the Games?

Before we go on to the main topic, let me explain what a QA in the game development is. QA stands for Quality Assurance. When we use a word "QA" in the game development, it usually means the work itself but also the departments or the project teams, depending on the organization. The basic purpose of QA in the game development is to find bugs and make sure if the games are working correctly in required quality.

Then, what do we do when we use a word "Test" in the game development? In most cases, it means to play the games manually to find bugs and fix them. (Unit testing and smoke testing which are well-known in the software development are also held in the game development, and I will explain them later in this article.)

The games under development are checked by people called a "QA Tester" to see if there is no bugs left in the games, the products are well followed by the specification documents, the games meet the product standard, and the games are come up fun as the final products. Their works cover a wide range, such as a simple testing of crashing a wall to find collision bugs, finding failures triggered by a complex procedure or specific timing, and a physical testing of plugging or unplugging cables.

It is likely that people think of game testing as just a simple process of finding bugs, but it is only a step to QA and not a goal. The main purpose of game QA is to assure that the games are working correctly in required quality.

So, this process is very important that the games cannot be made into the final products without it!

Works of a QA Engineer

Recently, as the game development is getting bigger and bigger in size, it’s becoming more and more difficult to test and develop the games manually. To solve such problems by engineering technology, a new profession called a "QA Engineer" (like me) was born. What is required for a QA engineer might differ by organization. At our office "Ryu Ga Gotoku Studio", the QA engineers make efforts to automate the environment of the game development and QA and to increase its productivity every day.

At our studio, to improve the productivity of the game developing environment, we automate build and convert of game assets, and improve efficiency for the workflow of issue tracker (Trac/Redmine/JIRA etc.). In some offices, people called a "Build Engineer" do these jobs. But at our studio, the QA engineers usually take these roles, and sometimes ask for help from other engineers of our team or different departments, depending on the situation.

In this article, I will mainly explain the game testing on my work and can give you only a brief explanation of the automation technology for the game developing environment. So, if you are interested in the automation technology and want to know further information, please check out the following link of Japan Symposium on Software Testing in Tokyo 2016 (JaSST'16 Tokyo).

What Do We Do to Debug Faster for "Ryu ga Gotoku/Yakuza" Series?: High-Speed Workflow to Fix Enormous Bugs (JaSST'16 Tokyo) (Japanese) 

(2009-) Automated Playtesting

From here, I will move on to the next topic "Automated Testing", which is one of the main works of a QA engineer. I will explain how we came up with a new profession “QA Engineer” at “Ryu Ga Gotoku Studio” through a history of “Ryu ga Gotoku/Yakuza” series.

We have been releasing "Ryu ga Gotoku/Yakuza" series every single year in Japan, and the latest title which was released this year is the 14th. To release the mass scale games in such a high speed, at “Ryu Ga Gotoku Studio”, each one of engineers and a team as a whole always have been thinking what we can do to automate the game developing environment and to enhance its productivity. This spirit gave a birth to automated playtesting!

When we had started developing games for PS3 generation, we had developed our original automated playtesting system “AutoTest” and started operating it. This is a system which enabled PC and development machines to run through automatically throughout the midnight, so that they can detect errors even after the engineers left the office.

In the following figure (Figure 1), "AutoTest" gets the latest build and starts to play the game automatically, and Player AI (like bot) can emulate pushing buttons and play the game automatically.

 

Figure 1: The Architecture of "AutoTest" System

f:id:sgtech:20181015000004p:plain


At the beginning, we tried to make the player in the game move randomly. We made them crash into a wall to find collision bugs.  And then, we gradually expanded the area of automated testing, and now that we can clear the main story of the games with the replay data on the basis of playing the games in manual testing! Therefore "AutoTest" can expand the area of automated testing.

We kept brushing up the functions of "AutoTest" even further. In the game of “Fist of the North Star: Lost Paradise”, "AutoTest" cleared the main story all by itself. For “Fist of the North Star: Lost Paradise”, we made additional functions to automated testing which can cope with widely varying situation, and now that it enables us to find various types of bugs. For example, "AutoTest" can select the bot AI that mashes the decide-button during dialogue scenes, and changes to the battle’s bot AI when it attacks enemies (Figure 2). It can select bot AI that meets the circumstance of the game.

 

Figure 2: "AutoTest" Demo (Fist of the North Star: Lost Paradise)

f:id:sgtech:20181015000246p:plain

Furthermore, an effective cooperation system is built up between manual testing and automated testing, so that "AutoTest" can take charge of testing numerous combination steps that can be hardly handled in manual tests.

You may think that the more the automated playtesting finds various patterns of bugs efficiently, the better works we accomplish as a QA engineer. But it is preferable that AI technology concentrates on removing only easily-find-bugs out, while we take our time to find more complex bugs, because we always want to focus on improving quality of our games and create the best and the most fun games ever before. The automated playtesting does support and help the manual testing, but not all the process of game testing can be easily replaced by the automated testing.

(2013-) The Birth of a QA Engineer and the Acceleration of Automated Testing

We have been improving and adding new functions to the automated environment for the game development and QA every time we release "Ryu ga Gotoku/Yakuza" series at our studio “Ryu Ga Gotoku Studio”. But on the one hand, it contributes to speed up the game development and improve the game quality, on the other hand, maintaining the automated environment increased the burden on developers. Therefore, I stepped forward and started to take in charge of the QA engineering since the development of "Ryu ga gotoku Ishin!" which was released in 2014 in Japan.

It was a wise decision to assign an exclusive QA engineer in a developing team that it carried out a great evolution to QA engineering technology at unbelievable speed on a daily basis. We reorganized the original developing environment and started integrating the systems in order to manage and maintain them easier. We also expanded the functions of “AutoTest”, and moreover we implemented the new functions for log analysis which I will explain in the next paragraph. QA engineering technology of “Ryu Ga Gotoku Studio” is still continuing evolving and it accelerates its speed even today.

(2015-) Analysis of Testing Result

At our studio, we assigned an exclusive engineer and we can now handle and manage the automated testing much easier. But there, we faced another new problem. Other than "AutoTest", we use Jenkins for automated testing. (Of course we use it as a continuous integration tool.) But it can only tell us either the result of the test is a success or a failure. We wanted the results in much more detail. so we started to analyze the logs of testing since "Ryu ga Gotoku KIWAMI" (Released in 2016 in Japan/The English version is "Yakuza Kiwami") and "Ryu ga Gotoku 6: Inochi no Uta" (Released in 2016 in Japan/The English version is "Yakuza 6: The Song of Life").

The following graphs (Figure 3 and 4) show the visualization of heap maps which are created by collecting usage of VRAM (Video RAM/Graphics Memory) (Figure 3) and collision errors in "AutoTest" (Figure 4).

 

Figure 3: Heat Map for Usage of VRAM (Fist of the North Star: Lost Paradise)

The heat map below visualizes the usage of VRAM in the city of "Eden".
Red is high usage, and X is NG (over 100% usage). 

f:id:sgtech:20181015000236p:plain
Figure 4: Collision Error Map in Very Huge "Wasteland" (Fist of the North Star: Lost Paradise)

f:id:sgtech:20181015000020p:plain

 

As a result of making the “AutoTest” play the games, defects other than easily-found-bugs, such as warnings, were found, just like when we play the games by ourselves. And also it can check the game performance for us. By collecting the logs and visualizing them, we can now save a lot of time and fix bugs much faster with high accuracy.

Moreover, we analyzed logs of manual playtests and could get feedback of game level design. It enabled us to create more fun games. The following graphs (Figure 5 and 6) are examples of feedback of game level design to analyze logs of manual tests (Figure 5) and "AutoTest" (Figure 6).

 

Figure 5: The Game Over Points of Manual Playtesting (Yakuza 6: The Song of Life)

We visualized points where player’s HP is zero in manual tests. We could make use of it for game level design.

f:id:sgtech:20181015000240p:plain

Figure 6: Item Drop Odds of Automated Playtesting (Fist of the North Star: Lost Paradise)

We measured odds of items that the enemies dropped in automated playtests. We confirmed the item odds are correct and the enemies can drop the rare items for game level design.

f:id:sgtech:20181015000243p:plain

If you want to know about our automated playtesting and playlog analysis in more detail, please take a look at the following link of Japan Symposium on Software Testing in Tokyo 2018 (JaSST'18 Tokyo)

Automated Playtesting and Playlog Analysis to Create More Fun Games for "Ryu ga Gotoku/Yakuza" Series (JaSST'18 Tokyo) (Japanese)

(2018-) Thought of Test Pyramid and QA Engineering in the Future

No matter how efficiently we became to analyze the result of automated testing, we can never stop improving the QA environment. Nowadays, AI technology is a big trend everywhere around, and the efficiency of the automation technology and the log analysis in the game development which have been based on our experience are expected to make much more progress with an effect of AI technology.

In Computer Entertainment Developers Conference 2018 (CEDEC 2018) in Japan, I joined a session "On the Future of QA and AI: How to Implement AI into Game Development Correctly" as a panelist. In the article below, I will follow up on the test pyramid which I had explained in CEDEC 2018.

The test pyramid is often used to show the execution of automation efficiency. In system software or web development, the test pyramid is desired to be like the figure below (Figure 7).

 

Figure 7: Test Pyramid of System and Web Development

f:id:sgtech:20181015000016p:plain

UI Testing The product testing. It is high cost and difficult to automate.
Integration Testing Testing if the combination of individual functions and modules work correctly.
Unit Testing Testing of individual functions and modules. It is the lowest-cost testing in this test pyramid.

 

By increasing the ratio of lower-cost unit testing and automating it, it is possible to cut cost and improve efficiency. Then what about the test pyramid in the game development? In most cases, it is likely to be a pyramid below (Figure 8).

 

Figure 8: Test Pyramid of Game Development (Real)

f:id:sgtech:20181015000012p:plain

Manual Playtesting Testing to be played by hand.
Smoke Testing

Simple testing to check if the games launch and the individual modules work correctly. The shorter the time, the better testing. (about a few minutes)

Engine and Library Testing

Testing if samples of the engine and the library work correctly when they are developed in the company.
Assets Testing

Individual testing if the game assets (the models, the textures and the motions etc.) work correctly.

 

As you can see from the figure above (Figure 8), the pyramid is upside down and very unbalanced. The ratio of the manual testing at the last stage of the game development is very high, which means it is inefficient and high costs. In the game development, these testing relies on human resources that it is difficult to increase personnels in a short period of time, especially under such a current circumstance of labor shortage.

And because of its data-driven architecture in the game development, it always seems to be very buggy by data(assets). Sometimes the number of these bugs is even greater than that of programming bugs.

So, we incorporated unit testing before final testing. You may think “Why do we need unit testing in the game development?”, but once you know that it can detect errors and check consistency of individual assets before the final tests, you may easily imagine how extra works and retake-costs we can eliminate by having unit testing.

We have been trying to make further efforts to fix the inverted triangle to a well-balanced triangle. For example, except for “AutoTest” and log analysis which I have already explained, we strengthen detecting errors in assets-converting and increasing smoke testing.

 

Figure 9: Test Pyramid of Game Development (Ideal)

f:id:sgtech:20181015000009p:plain

With the ideal pyramid above (Figure 9), you may wonder why we had started to automate playtesting which is highest-cost testing first.

There are two reasons for it. Because the results of unit testing in the games can be observed only in the graphics output, it is difficult to determine if the result is a success or a failure. And the other reason is that the members of the development teams accept errors of automated testing as errors we must fix.

The second reason is especially important. In a testing process, once an error is found, the error must be fixed right away. But if the errors which automated testing found are not trusted by the developers, they would have a question such as “Do we really encounter the same errors in the product?”, and that these bugs would be possibly ignored and thus left over in the games. In this case, we will end up in just wasting time and labor. We should build the test environment exactly like the product which surely ensures the reliability of automated testing. It is important to raise the organization culture that every time the automated testing finds errors, we must fix them immediately.

At “Ryu Ga Gotoku Studio”, every team member recognizes the need of the “Automated Playtesting” and trusts the system, thus we are able to keep increasing the ratio of low-cost automated testing. If you are willing to try the automated testing, my advice for you is to build automated playtests which enable a player in the game move randomly by mashing buttons, and then gradually share them with your teammates.

Conclusion

As you can see from this article, QA engineering is very essential technology in the game development now, and it is desired and expected to evolve greater in the future.

Talking about my career, I first started working as a game programmer, and then experienced game development and QA as a developer. That’s why I can easily tell what is exactly desired for QA and what should be automated in the game development. In addition, I can suggest the concrete solutions for automation of the game development and seek for better productivity. In this sense, I believe that I’m making the most of my career. If you are interested in QA, a QA engineer would be a good choice for whom already have experienced game creating as a programmer.

We have been trying to make a comfortable environment also for developers. If you are interested in our jobs, please knock the door and contact us any time. We are always waiting for you here at SEGA.

SEGA Careers (Japan)

 

Reference

* The game screenshots in this article were taken under development. It is different from the products.

 ©SEGA

ゲーム音楽って面白いんです!

はじめまして、セガゲームスでサウンドクリエイターをしております小林と申します。
1998年に入社し、主に「ファンタシースター」シリーズでサウンドの制作に携わっています。
今回はゲーム音楽の面白さ!をできるだけ伝えられればと思っています。

 

【目次】

 

                                                                                                                                                                                           

最初に作った音楽は?



最初の頃に作曲として参加した作品は「ぐるぐる温泉」というパーティーゲームのBGMでした。ぐるぐる温泉というゲームはたくさんのミニゲームがあり、それに好きなBGMを鳴らして遊ぶというもので、自分も何曲か作りました。
(フュージョン的なBGMや、ボサノバ風なものも作りました)

 

ここで、このゲームにおけるBGMのテーマや役割について考えてみましょう。

 

  • ゲームの内容に沿ったもの、というよりは「なるべく色々なジャンルの音楽を!」というテーマ
  • どの曲でも好きなゲームで聴けることにより、様々な組み合わせでゲームを楽しめる、という役割

 

などでしょうか。ここでのまとめは

 

遊ぶたびに、任意の曲を好きなようにBGMとして使うことができる

 

ということになるのかと思います。リアルタイムでプログラムを実行し、内容を反映できるゲームならではの利点だと思います。

 

                                                                                                                                                                                           


本格的に関わった「ファンタシースターオンライン」


 

私の中でもエポックメイキングなプロジェクトだったのがこの「ファンタシースターオンライン(PSO)」です。PSOはオンラインのアクションゲームで、当時のコンシューマーゲームとしては新しいことをしていたと思います。
そこで、サウンドでもなにか新しいことをできないかと思っていました。

 

まず、なるべく簡単にゲームの仕様をまとめてみると、下記のように考えられます。

 

  • 壁や扉に区切られた部屋が組み合わさってマップができています。
  • マップを移動するとエネミーが出てくるので攻撃し、倒します。

 

ここで、BGMがどう関わるか考えてみましょう。

 

  1. マップをスタートするとBGMが鳴る
  2. 敵が出てくると別のBGMが鳴る
  3. 敵を倒すと元のBGMに戻る

 

普通のBGMアサインの仕方であれば、上記の場合2曲で足りると思います。それぞれの状況で2曲を鳴らせば良いだけで、現在でも多くのゲームで使用されている手法です。
ただ、それだと普通で面白くないと思っていたのと、当時のサウンドディレクターからも「2曲が「自然に」変わるような方法はないだろうか?」というアイデアがありました。

 

そこで考えたのが下記の方法です。

 

  • 楽曲A、楽曲Bをいくつかの「パート」に区切り、パートの中も2~4小節単位で区切れるようにする(フレーズとしておきます)
  • パートごとに、「楽曲A→楽曲B」「楽曲B→楽曲A」へのファンファーレ的なものを作っておく
  • 楽曲A、楽曲Bを、フレーズ単位で細切れにして、それを連続的に再生する
  • 敵が出る、倒し終わるなど、場面の変化時に、「フレーズの終わるタイミング」で「ファンファーレ」を鳴らし、次の楽曲に連結する

 

いきなり複雑になってきました。今度は図解にしてみましょう。

 

 

f:id:sgtech:20180924193629p:plain

 

 

f:id:sgtech:20180924193631p:plain



 

 

こうしてみると更に違いがわかると思います。
そしてPSO方式の場合、技術的にも通常には無いものが必要になってきました。

 

  • それぞれのフレーズを、決められた順番・時間通りに再生する仕組み
  • 状況の変化に応じて、必要なフレーズを連結し、それぞれの楽曲へ変化させる仕組み

 

また、楽曲の変化タイミングについても考えてみるとより表現を豊かにできます。

 

  • 敵が出現する、倒し終わることで楽曲が変化する
  • 敵がいるマップから避難すると楽曲が変化する、等

 

上記はすべて特殊な内容だったため、一から仕組みを作る必要がありました。当時プログラマー向けに書いていたBGM挙動についての 仕様書の一部が下記になります。

 

f:id:sgtech:20180924193633p:plain
 

f:id:sgtech:20180924193635p:plain


 

これをステージごとに、全部手作業で設定してもらっていました。当時は苦労をかけてしまいましたが、開発チームがBGMシステム案に理解を示してくれたおかげで実現できました。やはり実現のためにはプログラマーの力が必要で、ゲームにおけるプログラマーは非常に重要な役目を担っています(本当にありがとうございます!)

 

ここで、PSOにおけるBGMのテーマや役割について考えてみましょう。

 

  • ゲームの内容&世界観に沿った楽曲を!というテーマ
  • ゲームの状況に応じて、必要な音楽を動的に再生・変化させて、場面を演出する役割

 

というものになるかと思います。「ぐるぐる温泉」のときは指定された内容の楽曲を提供するのみでしたが、ここでは

 

  • 「必要な音楽を動的に再生・変化させて、場面を演出する」役割になるように「設計」し
  • そのための仕組み、方法についても「設計

 

しています。このように、ゲーム音楽を作るサウンドクリエイターのひとつの特徴と言えるのが、この

 

設計プランニング)」

なのです。そして、このプランニングによってゲーム音楽はもっと面白くできるのです!

f:id:sgtech:20180924193627p:plain

 

また、プランニングのための作曲テクニックも、その実現のためには重要です。

 

例えばPSOの場合は、「楽曲A」「楽曲B」が「自然」に切り替わり、連続性を持たせるように設計していますが、そのためには楽曲そのものにもひと工夫必要です。

 

  • 楽曲A、楽曲Bは、違って聴こえつつも、近しい関係であるようにする
    → 平行調、同主調などで作曲を行う
  • 戦闘中(楽曲B)は緊張感を増すように、楽曲Aよりもテンポを早くする
    → PSOのときは、再生する1フレーズの長さが各ステージで固定されていたため、基本的に楽曲Bは楽曲Aの2倍のテンポで作っていました。(2倍であれば、同じフレーズの長さで小節数が2倍になるだけで、合わせやすい)
  • 楽曲A←→楽曲Bがスムーズに移動できるように、ファンファーレを工夫する
    → その先の楽曲に繋がれるように作曲を行う(ファンファーレと呼んでいますが、AB楽曲それぞれのイントロ&エンディング部分を作っている感じです)

 

このように、 個々のゲームがそれぞれ持っている目的に対して、

 

  • どのような音楽を作るのか
  • それがどのようにゲームに関わっていくのか
  • 関わることによって、どのような結果をもたらすのか

 

などのことを考えて、楽曲そのものや、その鳴らし方を含めて考え、作っていくのがサウンドクリエイターなのかと思います。面白いのが、上記の順番は場合によって変化もして「こういう風に関わっていくからこういう曲を作りたい」という考え方もアリです。(PSOはこの考え方だと思いました)

 

また、元からのBGM仕様(プランナーが制作する)もあります。「この場面でこの音楽がほしい」といったものから、「ここでこう変化させたい」など、一段と細かい要望もあり、それらをより具体的な形にしていくのもサウンドクリエイターの仕事です。

 

もちろん、すべてのプロジェクトでこのようなことはできないかもしれませんし、あるいは必要ないかもしれません。ただ、それぞれのゲームで表現できる可能性というものはいくらでも考えられると思います。そこが面白いと思います!

 

                                                                                                                                                                                           


インタラクティブミュージック・・?



「インタラクティブミュージック」という言葉がございます。大雑把な説明をすると「ゲームプレイに応じて変化するミュージック」というべきでしょうか。そういう意味では、例えばメガドラ版ソニックでも、水中にいるソニックが息苦しくなってくると曲が変わる(そして空気を補充できると曲が戻る)というギミックがありますが、これもインタラクティブミュージックだと思います。


またPSOでは、切り替わった先の楽曲が、変化のタイミングによって任意の場所に変化する、という意味では毎回楽曲の内容が変化していくというところでインタラクティブミュージックと呼べるかもしれません(PSOの場合は「シームレス」とも呼ばれています)。


そして現代のインタラクティブミュージックは、更に(それどころかめちゃくちゃ)高度に作られています。更にADX2Wwiseなど、「ゲームサウンドのための」システムも提供されていて、素晴らしい作品が作られています。
そしてここからは、現在進行中の「PSO2」についてお話しましょう!

 

                                                                                                                                                                                           


「SYMPATHY」システムを使用した「PSO2」



「SYMPATHY」システムとは何でしょう?それはPSO2における「インタラクティブミュージック」「プロシージャルミュージック」システムの総称です。

 

これからの内容は、過去2回にわたって行われたCEDEC講演の内容も含まれています。

 

www.4gamer.net

www.famitsu.com


PSO2開発当初、PSOで行ったBGMシステムについて社内でも評価があり、それをより拡張した形で表現できないか、と提案があったため、私が基礎を設計し、プログラマーの方にシステムやツールを作ってもらいました。

 

まずは、PSOでやっていた

 

  • それぞれのフレーズを、決められた順番・時間通りに再生する仕組み
  • 状況の変化に応じて、必要なフレーズを連結し、それぞれの楽曲へ変化させる仕組み

 

をツール化し、サウンドクリエイターが直接制作できるようにする環境作りです。
これは「Sympathy MusicEditor」というツールで可能になりました。
更に、PSOでは制限されていたフレーズの長さについても、楽曲A、Bで独自にできるどころか、フレーズ単位で変更が可能になったため、変拍子の楽曲も制作可能になりました。
また、従来の内容に加え、新たに様々な仕組みも追加しています(現在も追加中です!)
(SYMPATHYシステムの根幹は、CRI*1のADX2を元にしています)

 

ここで、新しく「プロシージャルミュージック」という言葉が出てきました。「プロシージャル」とは、決められたものではなく、その場の条件によって作られる内容が変わる、といった意味で、音楽でプロシージャルを行う=「楽曲の自動生成」を目指したものになります。


PSO2のプロシージャルミュージックの概念としては下記になります。

 

  • 「パート」>「楽章」>「フレーズ」という単位を用意する
    → PSOで使用した、細切れにした楽曲(クリップ)は「フレーズ」に入ります
  • 「パート」に3種類の役割(「メロ」「サビ前」「サビ」)を持たせ、それぞれを毎回自動的に再構成させる。
  • また、各役割のパートは多めに作っておき、そこから毎回選ばれることによって内容に変化を持たせる。
    (例1)
     メロパート1・メロパート2・サビ前パート・サビ1・サビ2
    (例2)
     メロパート1・メロパート3・サビ3
     (更に、「楽章」「フレーズ」単位でもシャッフル可能)

 

上記の仕組みにより、毎回内容が変化するBGMの制作が可能になりました。

 

また、連続的に楽曲を変化させるための手助けとして「ライン」という仕組みも追加しました。パート・楽章・フレーズが横軸の動きであるならば、ラインは「縦軸」の動きと言えます。
この機能により、例えば

 

  1. 毎回同じパートを再生していてもメロディを変化させたり、
  2. 状況に応じてプログラムから直接指定して再生することもできます。

 

1の場合は、あるメロディ楽器にアドリブ演奏をさせたい時に、1小節ごとに作曲したフレーズを切り分けてアサインさせ、毎回違ったアドリブ演奏をさせる、ということをしていました。
2の場合は、ボス戦でボスのHPが下がったときに、曲の位置は変えないで曲調を変化させる(全体を半音上げたり)ときに使ったりしています。

というように、より多くのことができるようになりました。

 

                                                                                                                                                                                           


目的を持った音楽を!



「目的を持った音楽」とは何でしょう?実は、私が重要視しているものの一つになります。
例えば、PSO2ではボス戦でHPが減少するとBGMが変化したり、更に強力なボスの場合は、最後にテーマ曲が鳴ったりします。
上記のように曲が変化すると

 

  • あともうちょっとでボスが倒せるぞ!
  • ボスの攻撃が厳しくなるから気をつけないと!
  • (テーマ曲が鳴って)イヤッッホォォォオオォオウ!

 

という感じ(になるであろうことを祈る)に、プレイをする人はより気分が盛り上がりつつ、ボスの「状況」も知ることができます。この、「『状況』を知らせる」ことが私は大事なことだと思っています。というのはゲームは「状況」の連続であり、更に状況を有利に進めることが目的であるため、そこに音楽の表現が加わることによって、より大きな感動を与えられたり・音楽に役割を持たせることができるのではないか、と思っているからです。

ただ上記もいわば当たり前の話で、当然のごとく多くのゲームで表現されています。また状況に合わせたサウンドの表現で、究極的に完成されているのが「映画」や「ミュージカル」ではないかと自分は思っていますが、ゲームもその表現を追っている印象を感じています。ただそれを突き詰めるほど、芸術のレベルまで高められた技術、楽曲が必要になります。実際にそれを実現できているプロジェクトも少なくありませんが、だからこそ自分は表現力を高める努力もしつつ「ゲームだからできる表現」もできないかと思っています。
ここからは、PSO2のサウンド表現について過去の事例をご紹介しましょう。

 

                                                                                                                                                                                           


PSO2のサウンド表現



※過去のCEDECで講演された内容が含まれています

1.惑星ハルコタンのフィールドBGM

 

PSO2はジャンプもできるアクションゲームでしたが、この新しい惑星のフィールドでは建物の「屋根」に乗ることができ、より立体的なアクションが可能になりました。これは自分の中でもかなり衝撃的だったので、これに音楽をぜひ絡ませたいと思いました。そこで考えたのが下記です。

 

  • 「地上にいる状態」、「屋根に登っている状態」で「楽曲A・B」の合計4種類の楽曲を用意する
  • 「地上」「屋根」はラインで分けておき、プログラムの指示で状況に応じて変化させる
  • 既存の機能(敵登場時の変化)も作動する。

 

この場合は、プログラムのほうは状況に応じてラインを指示するという対応のみでしたが、楽曲の方では程よい連続性・変化を楽しめるように、下記のような作曲を行いました。

 

  • 楽曲B(戦闘状態BGM)で
    → 地上時はパーカッション・オーケストラ風なアレンジ
    → 屋根上時は、ドラム・ギターと言ったロック風なアレンジ
    に制作した
  • 楽曲Bのメロディ部分については、同じ内容で「フルート」「ギター」の音色で用意し、独自のラインを用意してその都度ランダムに音色が変わるようにした
    (メロディ部分・伴奏部分・リズム部分は独自のラインを持っています)

 

 ©SEGA

 

また、この曲でポイントだと思っているのは

 

  • 「プレイヤーの(縦の)位置状況」を「楽曲」で知らせている
  • メロディがそのままで、プレイヤーのアクションによって楽曲のアレンジを変化させられる

 

というところだと思います。

 

 


2.ブリュー・リンガーダの「リング」を含めたBGM

 

「ブリュー・リンガーダ」というボスがいるのですが、大きなリングを2つ持っており、これを飛ばしても攻撃してきます。リングはプレイヤーの後ろに回ることもあり、常に見えているわけではなく、注意が必要です。

 

ここでも、この印象的な敵の攻撃にサウンドを絡めたいと思いました。そこで考えたのが下記のようなものです。

 

  • リングから鳴る持続的なSEについて、弦楽器(ストリングス)のフレーズをアサインしてもらう。このフレーズはその場で鳴っているBGM(ブリュー・リンガーダ用BGM)のどの時間軸で鳴っても問題ないような音で作っておく
  • SYMPATHYシステムには、「フレーズの再生タイミングに合わせて特定のSEを再生する」という機能があり、これを利用して、リングの持続SEが再生されるタイミングを楽曲に合わせる

 

上記のような設計によって、

 

  • リングの位置を音で知ることができる
  • リングの攻撃があると、楽曲にストリングスのフレーズが追加され、それが位置の変化によって縦横に変化する

 

という、楽曲にもプラスの変化があり、プレイヤーにも状況を伝えられる、という効果を狙っています。

 

 ©SEGA

 

また、リングが2つなので、ストリングスのフレーズも「ハモる」ようにできています(フレーズ内容も複数用意し毎回ランダム)
更に、この仕組みは「ブリュー・リンガーダ戦BGM」でしか使えないのですが、実はブリュー・リンガーダ自身は他の場所・任意のBGMが鳴っているところでも出現することがあり、そこで気を利かせたプログラマーが「リンガーダ専用BGM以外のシチュエーションでは普通のSE(純粋な効果音)が鳴るようにもしておきますね」と対応してくれて、感謝の涙を流した覚えがあります(泣。

 

 

 

3.「クーナ」登場に合わせて、カラオケ状態のBGMにボーカルがタイミング良く入る

「混沌に惑う白き都」というクエストで、PSO2のアイドル「クーナ」が途中から一緒に参加して戦ってくれるようになるのですが、制作当初から、BGMはクーナの歌(終わりなき物語など)にしたい、という要望がプランナー側から出ていました。
その上で、クーナが一緒に戦っているときとそうでないときで、音楽でも状況を伝えられないか、と考え下記のようにしてみました。

 

・基本のBGMはカラオケにして、クーナが登場しているときだけボーカルが入るようにする

 

仕組みとしては、

 

  • カラオケで1つのライン
  • ボーカルで1つのライン

 

を用意して、ボーカルのラインは、プログラム側でクーナが出ているときだけ鳴るように指示してもらいました。

 

ただ、上記で仕組みとしては完成ですが、歌のメロディというのは、必ずしも小節の切れ目で終わっていない場合があります。そこで、サウンドデータの方でそれを吸収してみました。

 

f:id:sgtech:20180924193659j:plain

 

 

この画像は、実際のMusicEditorの画像の一部ですが、「Beat(拍)」という箇所の値が、色々な数字になっていると思います。元の楽曲自体は4分の4拍子ですので、Beat: 11=2小節と3拍など、一見中途半端に見えます。

実は、そうなっているのはメロディのフレーズに合わせてフレーズを区分けしているためです。画像で、一番上に並んでいるブロックがカラオケが入っているラインなのですが、データは中途半端なタイミングで区切られているものの、隙間なく連結されて再生されるので違和感はありません。

一方、その下の2行で交互にデータが入っている部分がボーカルになります。(本当は1行にしても問題は無いのですが、見てわかりやすいように2行に分けています)

 

SYMPATHYシステムの利点として、独立した波形データを連結して再生できるということがあります。このボーカルデータは、実は長いボーカルデータを切って並べているのではなく、予めフレーズごとに切り分けたボーカルデータに、後からミキシングを施しています。

 

どういうことでしょう?ボーカル曲といえば、例えば声にエコーが入ったりしていると思います(カラオケでも歌うときにエコーを入れることがあると思います)。仮に、ひと続きになったボーカルを切った場合、エコーはずっとかかっていますので、あるフレーズを切り出したときに、直前のフレーズのエコーがかぶってしまいます。

 

今回の場合は、エコーをかける前のボーカルを切り分けて、個々のボーカルごとにエコーをかけ、それをSYMPATHY上で連結しています。

この利点としては、ボーカルの入り方、終わり方がとても自然にできるということで、なおかつ連続して聴いている分には普通の歌と変わりありません。 

 

f:id:sgtech:20180924193656p:plain


 SYMPATHYシステムは見かけ上4本のストリームデータを同時再生できるようになっていますが、実は上記の仕様を満たすために裏では2倍の、8本のストリームを同時再生しています。

 

この、フレーズに「余韻(エコー)」をつけるというのは非常に効果が高く、この「余韻」によって、フレーズ同士の連結をスムーズにするだけでなく、任意のフレーズ同士を自然に連結することも可能にしています。

その他のサウンドシステムはストリームデータを扱うものが主ですが、手間はかかるものの、このシステムによる自由度の高さはSYMPATHYシステムならではだと思います。

 

                                                                                                                                                                                           


「感動体験」を!



上記以外でも、PSO2では色々なことにチャレンジしていて、それは今も続いています。ゲームにしかできない音楽表現、それは場面に合ったものであったり、何らかの目的を持ったものかもしれません。それがクリエイターのアイデアを元に、さらに色々なクリエイターの協力を得て一つの形になったとき、「感動体験」を呼べるものができるのだと思います。
そしてセガグループのミッションこそ「感動体験を創造し続ける」になります。自分はこのテーマが大好きです。そして、ゲームだからこそできる「感動体験」をこれからも創造し続けられるよう、頑張りたいです。
小林なりの「ゲーム音楽は面白い!」だったかもしれませんが、少しでもその楽しさが伝わったでしょうか・・?ゲームだからできる音楽をセガで作ってみたい!という方はぜひ、セガゲームスの採用情報へアクセスを!

 

 

 

*1:CRI・ミドルウェア:は、日本のミドルウェアの研究開発・販売を行う企業で、主流となっているのは動画、音声データの効率圧縮ツールおよびその展開ソフト(ライブラリ)です。

QAエンジニアってどんな仕事?~ゲーム開発におけるテストの世界~

はじめまして。 

セガゲームス「龍が如くスタジオ」専属QAエンジニアの阪上と申します。 

今回は、QAエンジニアという職種の紹介とゲーム開発におけるテストの話を、「龍が如くスタジオ」での開発の歴史を振り返りながらご紹介したいと思います。

目次

ゲームのテストって何をするの? 

本題に入る前に、QAエンジニアのQAとは何なのかを説明しておこうと思います。QAは 「Quality Assurance」の略で、日本語では品質保証という意味です。ゲーム開発においては、ゲームが正しく動作しているか、バグがないか、ゲームが製品クオリティに達しているかなどを検証する仕事・部門・チームのことを指します。

QAがわかったところで、ではゲーム開発でテストとは何をするのかというと、ゲームを実際にプレイして、バグを見つけて修正することを指すことが多いです。(システム開発等で行われている単体テストやスモークテストなどもありますが、こちらは後半で説明します。) 

発売前のゲームをプレイして、バグがないか、仕様書通り動作するか、製品としての基準を満たしているか、ゲームとして面白いかどうかを検査する仕事を、テスターやデバッガーと呼ばれる職種の人が担当します。 壁にぶつかって抜けないかをテストする単純なものから、複雑な手順やシビアなタイミングで起こる不具合を見つけたり、物理的にケーブルを抜き差しするテストなど、その仕事は多岐に渡ります。 

ゲームのテストというと、バグを見つけるだけの仕事と思われがちですが、バグを見つけることは過程であって、最終的にゲームが正しく動作していることを確認した上で、品質や面白さを保証することが最終的な目的です。 

つまり、この工程がないと、ゲームは完成しないというくらい重要なものになります。 

QAエンジニアの仕事内容 

近年のゲーム開発は、大規模化の一途をたどっているため、先ほど説明しましたテストや開発そのものをすべて手動で行うことが困難になりつつあります。このような状況をエンジニアリングのアプローチから改善するために生まれたのが、私のようなQAエンジニアという職種です。組織によって具体的な業務内容には違いがあると思いますが、「龍が如くスタジオ」では、開発環境やQAの自動化・効率化を行うことを日々の仕事としています。

開発環境については、ビルドやデータコンバートの自動化、Redmine等のチケット管理システムのワークフローの効率化などを行っています。これらを仕事とする人を、より細分化してビルドエンジニアと呼ぶ場合もありますが、「龍が如くスタジオ」では、QAエンジニアである私が兼任したり、各ツールの担当者や他部署の協力を得るなどして、これらの自動化を行ってます。 

今回はテストの話が中心ですので、開発環境の自動化については簡単な説明にとどめていますが、詳しく知りたい方は、ソフトウェアテストシンポジウム 2016 東京(JaSST'16 Tokyo)の講演資料をご覧ください。 

「龍が如く」の高速デバッグ術~そびえ立つバグの山を踏破するための弾丸ワークフロー~(JaSST'16 Tokyo) 

(2009年~) 自動プレイテスト

ここからは、QAエンジニアの主な仕事の一つであるテストの自動化について、「龍が如く」シリーズの開発の歴史とともにご紹介したいと思います。

「龍が如くスタジオ」は、大規模なゲームを高速でリリースするために、個々やチーム全体で開発環境を積極的に自動化・効率化していこうとする組織風土がありました。このような環境だからこそ生まれたといえるものの一つが、自動プレイテストです。

PS3世代のタイトルを開発するようになったころから、オートテストという独自の自動プレイテストを開発し、運用を始めました。 開発メンバーが帰ったあとの開発環境(PCや開発機)を利用して、深夜に自動的にゲームをプレイして、エラーを検知するシステムです。  

下図のような仕組みで、最新ビルドのゲームを取得した上で自動的にゲームを起動して、QA専用のプレイヤーAI(ボットのようなもの)がゲームパッドの疑似入力を行い、実際にゲームを自動でプレイします。

 

オートテストの仕組み

f:id:sgtech:20180827092145p:plain

 ※図中の「エラー送信」は、「龍が如くスタジオ」独自のクラッシュレポート機能です。

 

ランダムにプレイヤーを移動させ、壁にぶつかり続けてコリジョン抜けを探すところから始めて、現在は、事前に用意したパス(操作手順をコマンド化したもの)に従ってゲームのメインシナリオをクリアすることもできるようになり、より広範囲のテストをオートテストで行えるようになりました。

オートテストの機能はその後も進化を続け、「龍が如くスタジオ」制作の「北斗が如く」(2018年発売)では、下図のようにメインシナリオをクリアするテストを行っていましたが、会話中は○ボタンで会話を進め、敵とバトルになった場合はバトル用のボットAIに切り替えて戦うなど、ゲーム内の状況に合わせたきめ細かい自動テスト機能を追加し、様々なバグを検出することができるようになっています。

 

オートテストの動作例(北斗が如く)

f:id:sgtech:20180827092140p:plain

 

また、上記に加えて、組み合わせが多すぎて手動でテストしきれないものをオートテストが専任で行うなど、手動テストとの協力体制ができつつあります。 

このように、自動プレイテストの取り組みは、近年のAIの台頭によって、AIに取って代わられる仕事と見られることがありますが、オートテストはあくまで手動テストの補助を目的としています。簡単に見つかるバグはできるだけAIにまかせて、手動テストでは、より複雑な条件のバグを探したり、ゲームの品質や面白さの向上に注力してほしいという思いで、日々オートテストの改良を続けています。 

(2013年~) QAエンジニアの誕生と加速するテスト環境の自動化

このように、「龍が如スタジオ」では、シリーズの開発を重ねるごとに、開発とQA環境の自動化が進んできたわけですが、開発のスピードアップやゲームの品質向上に貢献する反面、自動化した仕組みの維持が開発チームの負担となってきたため、「龍が如く 維新!」(2014年発売)の開発から、私が専属でQAエンジニアリングを担当することになりました。

専属のQAエンジニアを開発チームに置くことで、今までの自動化環境を維持しやすいように整理した上で一元管理したり、前述のオートテストの機能拡張や後述するログ分析などの新機能を実装することができるようになり、このころから、「龍が如くスタジオ」のQAエンジニアリング技術が劇的な進化を始めます。

(2015年~) テストの結果分析

テストを自動化して、QAエンジニアを専任化しましたが、それで終わりではありません。自動化のツールとしてよく使われているJenkinsでは、テスト結果の成功・失敗がわかりますが、自動テストの結果をもっと詳しく知りたいという要望が寄せられるようになりました。そこで、「龍が如く 極」(2016年発売)での試験運用を経て、ドラゴンエンジンでの開発となった「龍が如く6 命の詩。」(2016年発売)より導入したのがログ分析機能です。 

下図は、オートテスト実行中のゲーム内のVRAM(Video RAM、グラフィックスメモリ)の使用量を収集し、ヒートマップで見える化したものになります。

 

VRAMヒートマップ(北斗が如く)

エデンという街のVRAM使用率を、ヒートマップで見える化したもの。

赤くなっているところが使用率が高く、Xが100%を超えているので修正必須な地点。

f:id:sgtech:20180827092149j:plain

 

コリジョン抜けマップ(北斗が如く)

荒野という広大なマップのコリジョン抜けを見える化したもの。

f:id:sgtech:20180827092151j:plain

 

ゲームを自動でプレイしているわけですから、明確なエラー(例外やASSERT)以外の警告レベルの不具合も、通常のゲームプレイと同様に発生しますし、パフォーマンス計測も可能です。 これらをログとして収集し見える化することで、問題箇所を探す手間が省けるので、修正を正確かつ迅速に行えるようになりました。 

さらに、手動テストのプレイログも分析して、ゲームバランスの調整に使ったりと、まさにゲームの品質(面白さ)の向上にも活用できるようになりました。 以下は、手動テストやオートテストのログを分析して、ゲームバランスの調整に活用した事例です。

 

プレイヤーがゲームオーバーになった場所(龍が如く6 命の詩。)

手動テストでプレイヤーのHPが0(ゲームオーバー)になった地点を可視化して、ゲームバランスの調整に活用。

f:id:sgtech:20180827092136p:plain

 

アイテムドロップ率(北斗が如く)

敵が落とすアイテムのドロップ率を計測し、仕様通りの確率でアイテムを排出しているか、レアアイテムが本当に排出されているかをオートテストを使って計測。

f:id:sgtech:20180827092220p:plain

 

今回ご紹介したオートテストとログ分析は、ソフトウェアテストシンポジウム 2018 東京(JaSST '18 Tokyo) で講演させていただいたときの資料でより詳しく説明していますので、 ご興味がある方はご覧ください。(オープンソースを組み合わせて構築しているので、気軽に試すことができます。) 

無料で始める!「龍が如く」を面白くするための高速デバッグログ分析と自動化(JaSST'18 Tokyo)

(2018年~) テストピラミッドの考察とQAエンジニアリングの未来

自動化して結果を分析できるようになっても、QA環境を快適にする取り組みには終わりがありません。 現在は、どの業界でもAI活用がトレンドですが、今まで行ってきた自動化やログ分析を基礎として、AIを活用したさらなる自動化・効率化が期待されています。 

先週開催されたCEDEC 2018では、「次世代QAとAI 〜ゲーム開発におけるAI活用に正しく向き合うために〜」というセッションに、QAの今後の進化、AIの活用の未来というテーマで、パネリストとして参加させていただきました。今回は、CEDEC 2018で紹介したテストピラミッドについて、フォローアップしたいと思います。  

テストピラミッドとは、テストを自動化・効率化する上で、その考え方のベースによく使われています。一般的なシステムやWeb系の開発では、以下のようなテストピラミッドになることを理想としています。 

 

一般的なテストピラミッド

f:id:sgtech:20180827092217p:plain

UIテスト 最終的な製品に近いテストのことで、高コストで自動化するのが難しいテスト。
結合テスト 機能ごとに実装したものを結合して、問題がないか動作確認等を行うもの。
単体テスト ユニットテストとも呼ばれる機能ごとのテスト。一番低コスト。

 

より低コストな単体テストを増やして、自動化することで、コストを抑えつつ効率化することができるようになります。 では、ゲーム開発のテストピラミッドはどうなるかというと、 現状は以下のような状況にある場合が多いのではないでしょうか。

 

ゲーム開発のテストピラミッド(現実)

f:id:sgtech:20180827092214p:plain

手動プレイテスト 人が実際にゲームをプレイするテスト。
スモークテスト

ゲームの起動や各モードが正しい動作しているかを簡易的に調べるテスト。最新ビルドをリリースする時に最低限の動作を保証するためのテストなので、なるべく短い方がいい。(1~5分程度)

エンジン・ライブラリテスト

ライブラリやエンジンを社内開発している場合は、サンプル等が正常に動作しているかをテストする。
データテスト

モデル・テクスチャ・レベルデザインなどのデータファイルが正しくゲーム内で動作するかを個別にテスト。ゲーム内で動的に描画テストを行ったり、コンバートの時に静的チェックを行う。

 

上図では、最終的な製品に近い状態での手動テストの割合が高く、高コストなので、ピラミッドのバランスが非常に悪くなっています。 高コスト体質な上に人に依存するテストなので、昨今の人手不足によりスケールアップが困難になる恐れがあります。 

また、ゲーム開発では、データドリブンな仕組みを採用している場合が多いため、データのバグが非常に多い構造になっています。(場合によってはプログラムのバグよりも多いことがあります。) 

単体テストと言われると、ピンとこないかもしれませんが、一つ一つのデータの不具合や整合性のテストを、 最終的な製品のテストの前に検出できれば、手戻りコストを含めてどれだけの手間が減るかは想像に難くないと思います。  

「龍が如くスタジオ」では、今回ご紹介したオートテストとログ分析以外にも、データコンバート時のエラー検出の強化やスモークテストを増やすなどの改良を加えて、逆ピラミッドから以下のような正しいピラミッドになるように、日々改善を行っています。 

 

ゲーム開発のテストピラミッド(理想)

f:id:sgtech:20180827092211p:plain

 

ここまで読み進めていただいた方なら、もしかしたら理想のピラミッド図を見て、疑問に思われるかもしれません。 なぜ一番高コストであるプレイテストを自動化することから始めたのか? 

これは、「ゲームという特性上、単体テストでの結果が画像出力しかない場合が多く、画像の差分は閾値(しきいち)が安定しないので成否の判定が難しいこと」、「自動テストのエラーをエラーとして開発メンバーに受け入れてもらうこと」の二つの理由があります。

特に後者が重要で、エラーが出たらそれを修正してもらう必要がありますが、自動テストのエラーに対する信頼性が低いと、「このエラーは製品でも起きるの?」と言われて修正されないまま放置されてしまい、テスト自体の意味もなくなってしまいます。 まずは自動テストを通常のゲームに限りなく近い状態で実行することで信頼してもらい、そして自動テストのエラーは即時修正するというチーム文化を作ることが重要です。 

「龍が如くスタジオ」では、自動プレイテストをチームに受け入れてもらった上で、現在進行形でより低コストな自動テストを増やしているところです。 自動テストを一から導入することをお考えの方は、ランダムにプレイヤーが動く自動プレイテストを作ってみて、チームのメンバーにみてもらうところから始めてみてはいかがでしょうか。 

 

まとめ

このように、QAエンジニアリングは、ゲーム開発とQAにとってとても重要な技術で、 今後さらなる技術向上と成長が望まれている分野であることが、おわかりいただけたのではないかと思います。 

私は元々ゲームプログラマからキャリアをスタートしましたが、ゲームの開発やQAを開発者の立場で経験したことで、 何を自動化すればいいのか、どういったことが望まれているのかが具体的に分かるので、その経験は非常に役立っています。 そういった意味で、QAエンジニアは、ゲームプログラマやテスターの方にとって入りやすい職種だと思います。

また、QAエンジニアが開発現場にいることで、開発する側にとっても快適な環境を目指して日々改善しておりますので、ご興味がありましたら、セガで一緒に働いてみませんか? 

採用情報 | セガ企業情報サイト 

 

参考資料 

※この記事は、JaSST'18 TokyoとCEDEC 2018、セガの社内勉強会であるSDC(SEGA Developer's Conference)の講演内容をベースに作成しました。 

※本記事で使用しているゲーム画像は、すべて開発中のもので製品とは異なります。

英語版はこちら

 ©SEGA

Powered by はてなブログ