イベント
[CEDEC+KYUSHU]すべてはイテレーション向上のために。「ヘブンバーンズレッドにおける開発環境整備のとりくみ」聴講レポート
講演には,WFSでテクニカルディレクターを務める西田綾佑氏,「ヘブンバーンズレッド」(iOS / Android / PC。以下,ヘブバン)のメインプログラマーの奥村典史氏がスピーカーとして登壇。同作の開発事例をとおして,ゲーム内コンテンツ制作や開発サイクル向上ための環境整備,セーブデータシステムの構築に関する取り組みや考えを説明した。
「ヘブンバーンズレッド」のスクリプト開発環境
ヘブバンは,2022年2月にリリースされたドラマチックRPG。宇宙から来た謎の敵「キャンサー」によって危機的状況に陥っている日本を舞台に,選ばれた少女たちが決戦兵器「セラフ」を用いて戦う物語が描かれる。過酷な現実と運命に立ち向かう少女たちが織りなすさまざまなエピソードは,ときに笑い,ときに感動を呼ぶことで多くのプレイヤーたちから支持されている。
人気を支えるものの一つとして重要なのが,定期的に配信されるコンテンツの数々だ。
近年のゲームコンテンツはリッチ化が進み,またマルチプラットフォームも当たり前となった。そういった環境で毎月のように新たな要素を,それも高品質のものを更新しなければならない。
モバイルゲームを取り巻く現状についてそのように説明した奥村氏は,「限られた時間の中で高品質なコンテンツを提供するには,まず環境の構築が必要」と話し,ヘブバンのストーリー体験のベースとなる「スクリプト開発環境」について解説を始めた。
まずは,ヘブバンの制作環境について。現在はLuaをベースに制作されているが,元々はノードベースで開発していたという。
では,なぜそれをLuaに置き換えたのか。ヘブバンは,ストーリー体験を特徴としたゲームのため,シナリオのテキスト量が膨大となる。それらのコンテンツを量産するには,Luaのようなテキストベースの開発環境のほうが適していたというわけである。また,プランナーのほうで仕様策定から実装までを進め,エンジニアに渡してシステム化するという流れもできるため,プロトタイプの開発がやりやすいという理由もあったとのこと。
β版の開発時にLuaへの置き換えを行ったが,当初プランナーはスクリプト言語による開発が未経験だったこともあり,そこは“やや恐い部分”だったそうだ。
そこで奥村氏は,そのままLuaを使うのではなく,触れなくていい部分はラップする,多岐にわたる命令をネームスペース化して系統別にグループに分け,入力支援機能で候補が出やすくするといった,習熟度が低い人でも作業しやすいよう環境を整備したとのこと。
次に奥村氏は,ヘブバンを構成する3つの構成要素を紹介し,それぞれの要素で工夫したポイントを解説した。
まずはアドベンチャー(ADV)パートについて。アドベンチャーパートは基本的に立ち絵と背景,メッセージウインドウによって構成されており,メッセージを表示する[Adv.talk]は,そこで記載されたメッセージの内容を表示し,それを表示する秒数を[Wait]で指示するという命令になっている。極端な話,この命令を並べていくだけでアドベンチャーパートの進行が可能だという。
具体的には,書く必要があるところと不要なところを分けて擬似的なヘッダを作り,そのヘッダが指定したファイルだけ,上記の書き方を可能にするという改良を施した。実際,書きたいコンテンツのほとんどは逐次処理で,キャラクターを順番に発話させて指定時間待機し,プレイヤーのタップを待って次へ行くという形になっている。もちろん別の部分では通常のLuaの書き方を必要とする場合もあるので,あくまで該当のヘッダが付いていたら切り替わるという仕組みだ。
一般的に開発時によく使用されるゲームのスクリプトだと,初めてスクリプトに触れる人に理解してもらうまでに時間がかかり,また「Luaは難しい」「恐い」と苦手意識を持つ可能性もある。それを緩和・払拭するために,こういった直感的で分かりやすいものするため,書き方自体の改良を進めていったそうだ。
スクリプトの手順に慣れてきたら,オブジェクトの生成に加えて,徐々に演出や表現を増やしていく。これによって,ツールとしての改良だけでなく,作る側の“意識の改良”も進んだそうだ。こうしてアドベンチャーパートでは,可能な限り記述を減らすことで,演出への注力や量産に適した開発環境を整備していったとのこと。
続いてはフィールドパートについて。フィールドパートは,基本的にキャラクターが移動してフィールド上のキャラクターに話しかけるという動作になるが,その際のイベントの“発火”を簡単にしたそうだ。
フィールド上のオブジェクト(またはキャラクター)に近づく,またはタッチすることで,後は先のアドベンチャーパートと同じような逐次処理が行われる。つまり,そこに展開させたい内容を用意しておけば,すぐに“ゲームっぽさ”を出せるという。
とはいえ,すべてが楽ではない。ヘブバンといえば,イベントの多くは主に学園内で展開する。訪れる時間によって,発生するイベントが変化するのも特徴だ。つまり,一つのフィールド上に,異なる発生条件を持つイベントのランチャーが設定されているわけで,それの管理はかなり大変だ。
その大変さの一例としてWFSが開発した「アナザーエデン 時空を超える猫」(iOS / Android / PC)の通称「血塗られたバルオキー」と呼ばれるコードが紹介された。バルオキーとは同作品の最初の村で,何度も訪れては数多くのイベントが発生するため,もはや文字の判別もできないほと大量で難解なコードとなっているのが分かる。
これを回避するためには,適切な単位で分割する方法が必要だったが,奥村氏らはそれを模索する中で「時間とそれによる物語の変化」に着目し,「時間とそれによる物語の変化の“単位”」にスクリプトを分割することにした。
分割されたスクリプトは,ランチャー命令(オブジェクトに近づく,またはタッチするとイベントが発動する仕組み)は,あとから設定されたイベントで上書きされる形となった。
例えば下画像のように,スクリプトが分割されている場合は,汎用会話と交流の両方に大島三野里のランチャー命令があるが,後に書かれたイベントに上書きされるため,大島三野里の挙動は「立ち止まってタッチできるようになっている」となる。
このように,“いつもの時間”を書いたスクリプトの上に“その日だけの時間”を上書きすることで,1つの切り取った時間(時間別のイベントの発生)を作成。ランチャーイベントを複数のスクリプトに分割できる環境を用意することで,効率的に共通化しつつ限定された条件での“密度の高い時間”を描くことができたわけだ。
バトルパートはUnityとC#による堅実な作りにも見えるが,「バトル中でも柔らかくシナリオ演出を行う必要がある」とし,その“柔らかさと硬さ”を手に入れるために,割り込み処理による,Luaで制作した自由度の高いシナリオ演出を導入する仕組みが作られた。
Luaスクリプトは,常にバトルシステムを監視しており,イベントが挿入されると一時停止してスクリプトによる演出を行い,演出終了後にまたバトルシステムへ戻す形になっている。ムービー/タイムラインにおいても,基本的な関係性はバトルシステムと同様だ。バトルシステムでは,スクリプト以外の演出のパワーを十分に活用することで緊迫感のある体験が味わえるようになっているとのことだ。
奥村氏は,スクリプトを書く以外の不要な手間を減らすことで,結果的にスクリプトの量自体も減らし,より良い開発環境を作っていくことができたと,“メタ的なスクリプト利用”という+αの利点があったことも付け加えた。
その1つとして,奥村氏は通常のLuaの利用では難しいことや扱えないようなことを実現するための方法として「Luaスクリプトの先読み」を紹介した。これは独自に制作したパーサーによる,必要な要素を限定的にLuaに読み込ませることによって,Luaの構文解析をせず高速にLuaをパースするというものだ。具体的にどのようなことをやっているか,「入校時パース」を例に説明された。
入校時パースは,その名のとおり入校時にLuaをパースし,データを作ることによって不要なリストやデータを再生産をしなくてもよい環境を整備できる。例えば一括ダウンロード用のリスト制作の場合,ソースコードの中から使用するリソースを読み取ってリスト化するため,漏れや間違いのないリストが作成できるわけだ。
また,台本用のボイス管理ラベルの埋め込みも,入校時パースによって実現できると奥村氏は言う。フルボイスのゲームであるヘブバンは,すべての命令にどのボイスを流すのかを設定する必要があり,それを手作業で入力するためには膨大な時間が必要となる。
しかしこの機能では,一度パースして読み込んだ命令の管理ラベルを引数に追加し,Luaに書き戻せるのだという。
さらに,ランタイム実行時にLuaをメタ的に読み込んだり改変することによって,難しい記法を避けてシンプルにLuaを記述できる環境を作っているとのこと。BGMやセリフ,表情などの“間”を大事にしている本作では,アセットのロード時間でその間が変化するようなことがあると問題だ。それを避けるため,実行直前にLuaを一度パースし,使用されているリソースのロードが完了後,Luaを実行する。ポイントとしては,最初にすべてのリソースをロードするような命令が不要となり,自動的に読み取っているところだと奥村氏は話した。
ほかにも,既読スキップ処理の場合は実行時パースを利用しており,発言をすべて取得後,既読フラグを立てる命令で一度ラップするかのように書き換えている。差し込んだ命令が実行されると既読フラグが立つが,すでに読まれた発言の場合,既読フラグが立っていない命令に当たるまで実行を早送りするといった処理が行われるわけだ。
このように事前にパースをしつつ,ときには動的に書き換えることで,通常のスクリプトでは実現不可能な処理の実装に成功していると解説した奥村氏は,次のテーマを担当する西田氏へとバトン手渡した。
セーブシステムの構築
西田氏はまず,近年のモバイルゲームのプレイ環境について語った。ゲームをプレイするハードであるスマホの高性能化,ネットワークの高速化,それに伴うゲームのリッチ化についても言及。開発側としても,コンシューマゲームの制作に近いような印象になってきているという。
WFSが目指すゲームは,上記の表に記載されている通り。その中のセーブデータについて西田氏は,「サーバーとローカル,それぞれのいいところを併せ持ったハイブリッドなセーブシステムが必要」だと話した。
その根幹にはバックグラウンドでのセーブ同期の考え方があり,それはクライアントでの自由なデータ変更を許容し,それをバックグラウンドでサーバーに送信する形だ。これは,通信中によるゲームの停止などがなく,またローカルにセーブデータがあるため通信環境が悪くてもある程度プレイできるという,プレイヤー目線で考えると嬉しいポイントが多い。もちろん開発者側としても,プレイヤーがストレスなく遊べる環境を作ることが,大きな目標の1つでもある。
さらに詳しく,クライアントからのセーブデータ送信について解説された。
これは,ホーム画面への移動や装備の変更といった任意のタイミングで,データの差分を取り出して送信するというもので,通信環境が悪い場合はその差分をローカルに溜め込み,通信環境が良くなったときに送信する形を取っている。そのままでは容易にチート行為が可能となるので,サーバー側では送信データが妥当かどうかを判断するバリデーション機構を作り,細かくデータを検証している。
サーバー優先のデータ変更にも対応しており,ユーザーからの問い合わせによってデータの確認や操作を行うことができるよう,柔軟な対応が可能なシステム構築を行っているという。クライアントで自由にデータを変更しつつ,サーバー側では送られてきたデータを検証し,反映する。そうしたセキュリティも担保する折衷案のシステムが,ハイブリッドなセーブシステムの概要となっている。
ヘブバンでは,ハイブリッドなセーブシステムがどのように活用されているのか。奥村氏の解説でもあったように,ヘブバンは大きく分けてアドベンチャーパート,フィールドパート,バトルパートの3つに分類される。各画像の主なデータは,以下の画像のとおりだ。
西田氏は,例として表示したテーブルの画像を,ランタイムの中にあるローカルデータベース(これらのテーブルに対して,クライアントは自由に変更を行い,レコードも随時追加可能な環境)と仮定。ADVパートで新たなフラグが追加されたり,フィールドパートでフラグの内容が変更されたりといったことがローカルで行われた場合,その変更がセーブのタイミングで検知され,その差分がサーバーに送られると解説した。セーブのタイミングとは,サービス側がデータを管理するうえでも都合がいいタイミングというわけだ。
続いて西田氏は,データ変更時の差分の取り方について解説した。
差分とは,データ変更されたテーブルのレコードすべててのことで,メモリ上に変更されたフラグ(dirty flag)が立つことで,それらをシリアライズし,サーバー通信キューに載せてバックグラウンドで送信していく。通信キューは不揮発性で,ゲームを再起動してもその通信キューは復元される。そのため,確実にデータ変更がサーバーに送信されるということだ。
次は,サーバーとクライアントのデータスキーマの共有について。ヘブバンではデータスキーマの共有にFlatbuffersを利用しており,これをシリアライザーとしてではなくDSL(Domain-Specific Language)として使用しているとのこと。
Flatbuffersでテーブル構成を定義し,flatcでスキーマをパース。それをそのまま独自のジェネレーターに通すことでC#のボイラープレートコードを吐き出すといったことが行われているという。これにより,サーバーとクライアントで共通のスキーマから得られた各種ボイラープレートコードが得られるとのこと。なお,なぜFlatbuffersを使用しているのかについては,カスタムAttrbuteが便利であること,スキーマの記述が簡単で見やすいなどの理由があるそうだ。
西田氏は,「クライアントコードの実装者は,ローカルDBにflushしている感覚に近い」とし,その裏ではサーバーへの送信をセキュアで行っているということも付け加えつつ,別途ソースコードを表示しながらシンプルなコードで済む便利さをあらためて語った。
クライアントエンジニアとサーバーエンジニアの関わりについても解説された。クライアントエンジニアは,ある実装の仕様が決定すると,その仕様にそってデータスキーマをFlatbuffersで書き,そこからソースコードを生成し実装まで進められるようになっている。また,バックグラウンドのデータ同期をオフにすることで,オフラインのままサーバーなしで開発が進められるという。
サーバー向けにもソースコードは生成されているため,オートセーブをオンにすると,サーバーが自動的にデータを読み込む。結果的に,サーバーエンジニアはあまり関与していないように見えるが,「クライアントだけで作業が進むのはイテレーション(一連の工程を短期間で繰り返す作業)の面ではすごく有利」だそうだ。こうしたセーブシステムがライブサービスゲームに合っており,それによって重要度の高いコンテンツ制作の環境が整ったという。
開発イテレーション向上のための環境づくり
最後のテーマは,開発イテレーション向上のための環境づくりについて。イテレーションを早くするためには,依存した機能を経由せずチェックできるようにする必要がある。そう話す西田氏は,「ゲームは樹のように機能同士が依存している」とも付け加えた。
ヘブバンでは,ゲームを起動するメインシーケンスから,ADVパートやフィールドパート,バトルパートなどへとつながり,各パートからもそこを経由しないと見られない機能が存在する。確認したい機能へたどり着くため,いくつもの機能を経由する必要があるのは,時間はかかるし効率化の面でもマイナスとなる。
西田氏は,「多くのメーカーで作っていると思う」と前置きしつつ,そういった問題に対処する開発環境の効率化の方法の1つとして,「ゲームを起動しなくても確認可能なビューア」を紹介した。ビューアは,「開発環境ではなく実機に導入する形で確認できることが重要」だとし,キャラクターの3DモデルだけでなくADVパートでの2Dキャラクターの表情や背景の変化など,細かい制御も可能なビューアを整備していると説明する。
デバッグにおいても,ADVパートは切り出してのデバッグを可能にしており,実機での確認ももちろんだが,こうした効率的なデバッグ作業も可能になっているようだ。なお,こうしたデバッグシーンを活用してADVパートを量産し,再生しながら細かく調整するといったことも行っているそうだ。
デバッグについては,例えばADVパートなどで1000行以上のスクリプトの中の500行目を修正した際,そこへ素早く移動できるコードジャンプに似たよな仕組みを作っており,ショートカットを使うことで修正箇所まで高速再生が可能になっている。これも開発の効率化と高速化につながる大きな要素だと言える。
他にも,Unity Editorを再生したままLuaのリロードを可能にするような環境を作っており,この環境ではLuaのインポートも不要になっているため,リロードがスピーディに行える。
さらに,コード補完やコードジャンプ,特定の単語を入力するとその単語が含まれる一連のコードが自動で表示されるライブテンプレート,再生中のLuaを素早く編集できるボタンなど,細かい部分での作業効率や利便性を向上させるツールを開発しているという。
最後に西田氏は,Luaやセーブシステムによる恩恵,開発イテレーションを意識したさまざまなツールの開発・活用の重要性をまとめとして説明し,「(このセッションの内容で)参考になるものがあれば幸いです」とメッセージを送り,講演を締めくくった。
「CEDEC+KYUSHU 2023」公式サイト
4Gamerの「CEDEC+KYUSHU 2023」記事一覧ページ
- 関連タイトル:
ヘブンバーンズレッド
- 関連タイトル:
ヘブンバーンズレッド
- 関連タイトル:
ヘブンバーンズレッド
- この記事のURL:
キーワード
(C)VISUAL ARTS/Key(C)WFS
(C)VISUAL ARTS/Key(C)WFS
(C)VISUAL ARTS/Key(C)WFS