2023年12月17日(日)、インディーゲーム開発者向けカンファレンス『Indie Developers Conference 2023』が東京・新橋で開催されました。
本記事では、1年半という定められた開発期間の中で初めて本格的に触れるUnityとどう向き合って技術を習得し、ツインスティックシューター『NeverAwake』のリリースに至ったかについて語られた講演「1年半でNeverAwakeを完成させるための技術習得」についてレポートします。
2023年12月17日(日)、インディーゲーム開発者向けカンファレンス『Indie Developers Conference 2023』が東京・新橋で開催されました。
本記事では、1年半という定められた開発期間の中で初めて本格的に触れるUnityとどう向き合って技術を習得し、ツインスティックシューター『NeverAwake』のリリースに至ったかについて語られた講演「1年半でNeverAwakeを完成させるための技術習得」についてレポートします。
TEXT / じく
EDIT / 藤縄 優佑
講演に登壇したのは、『NeverAwake』を開発した株式会社ネオトロの佐渡 大志氏。同作の開発にあたっては、企画・ディレクション・グラフィックデザイン・プログラミングなど、そのほとんどを担当しています。
佐渡氏が開発した『NeverAwake』は、目を覚まさない少女「レム」がみる悪夢を舞台に、彼女の嫌いなものと戦うツインスティックシューターです。2024年1月現在、Steam/Nintendo Switch/PlayStation 4/PlayStation 5/Xbox Seriesで発売されています。
『NeverAwake』は予算の都合で開発期間が1年半と定められていました。開発チームはイラストレーション・BGM・SEの制作が各1名、それ以外はすべて佐渡氏が担当。
主な開発ツールはUnityとBlenderで、開発スタート時点での佐渡氏のUnity経験はほぼゼロだったそうです。
やりたいことを取捨選択した結果、Unityでは開発環境の学習やC#の使用を優先する一方でシェーダーを捨て、Blnederではモデリングを捨てる代わりにリギングやモーションを自ら行いました。
本作の開発ではUnityの学習も兼ね、機能は純正に絞って自前で処理を書くようにしていましたが、2日以上悩むことがあればアセットも使いました。
学習は開発中だけでなく、休日や空き時間も書籍・Webサイト・動画などを見る習慣を付けて“Unity漬け”の生活を送っていました。
『NeverAwake』の開発環境は、佐渡氏にとってチートのようだったといい、その理由を4つ挙げました。
1点目は、同じシューティングゲーム(以下、STGと表記)作家でUnityを使用する友人がおり、困ったことがあればすぐに相談できたこと。
2点目は、iGi(※)の1期生に選ばれ、『NeverAwake』の作品のクオリティ向上やUnityに関する相談が可能だったこと。
※ iGi indie Game incubatorは、日本在住のインディーゲーム開発者向けの無償インキュベーションプログラム。開発・ビジネス・コネクション、そして作品を世界に届けるサポートを行っている
3点目は、パブリッシャーがコンシューマー版への移植に関するさまざまなサポートをしてくれたこと。
そして4点目に、自分自身の会社だからこそできることとして、1日あたりの労働時間としておよそ12時間を費やせたことを挙げました。
土日などの休みは確保していましたが、ある程度はプライベートを犠牲にして開発していたそうです。
講演では、ここから開発の過程を時系列順に紹介しています。
開発は、まずUnityでSTGを作れるかをたしかめるため、モックの制作からスタートしました。
Unityで当たり判定を実装する際は、ColliderとRigidbodyを使うのが一般的です。しかし、STGでは敵弾が1,000発出ることも起こり得るため、処理速度を優先。C#を用いて自前で実装しました。
実装は昔ながらの円と回転矩形の判定を用いました。最適化の段階でこれらをすべてC# Job System(※1) & Burst(※2)化したところ、処理速度が10倍ほど速くなりました。
※1 アプリケーションで使用可能なすべてのCPUコアを使用して、コードを実行できるようなマルチスレッドコードを作成し、ゲームパフォーマンスを向上させる
※2 UnityのJob Systemに対応したコンパイラで、アプリケーションのパフォーマンスを高めるコードを作成できる
敵キャラなどのオブジェクトを生成するたびにInstantiateしてしまうと負荷がかかるので、あらかじめ必要となるオブジェクトを作成して出す・消す・非表示にする処理を行いました。
ステージのオブジェクト予想必要数は、ステージエディタである程度自動で算出できるようにしていました。
Unityのコントローラー対応には、新しく導入されたInput System、エディターに組み込まれている旧バージョンのInput Managerの2種類があります。それぞれの動作を検証してみたところ、ボタンを押してから画面に反映されるまでInput Managerでは3フレーム、Input Systemでは6フレーム(2021年検証時点)でした。
自身もSTGプレイヤーである佐渡氏によれば、STGプレイヤーは3フレーム遅延なら許容、4フレーム遅延だとアウトと判断するだろうと考え、旧バージョンの入力システムを使用することにしました。
ただし、旧バージョンの入力システムは各種コントローラーへの対応が煩雑です。これはRewiredというアセットを使用して解決しました。
Unityを使用するにあたり当初分かりにくかったのがUpdateとFixedUpdateという仕組みだったと佐渡氏は振り返ります。これらは、どちらもフレームごとのタイミングでループ処理を行います。
Updateはモニターのリフレッシュレートの回数分だけ処理を実行しようとします。“実行しようとする”というのは、処理負荷がかかってしまうと処理落ちが発生し、命令の実行回数が均一でなくなるという意味です。
FixedUpdateは毎秒指定回数分、しっかり命令を実行します。ただし、処理負荷がかかった場合は画面がスローになります。オールドスタイルなSTGでは、大量の弾幕をFixedUpdateの処理落ちを活用してかわすゲームもあるとのこと。
『NeverAwake』は、1秒間に60回という内部処理は確保しつつハイリフレッシュレートに対応したかったので、当たり判定・座標系処理などの内部処理はFixedUpdateで60fps固定、アニメーション処理・UI・メニューなどの表示部分はUpdateで可変フレーム対応としました。
ここまでのモック制作で、佐渡氏はUnityでSTGを作れそうな手応えを感じられたと話します。
少女の悪夢が舞台である『NeverAwake』。悪夢感のある絵作り・悪夢的世界観の構築をローコストで作る方法を調査しました。
基本は、手描きの2Dイメージにノーマルマップ(法線マップ)、ライティングをプラスさせ印象的な絵を作りました。
特定方向から光が当たるような描き方は、ライティングが変わったときに違和感が生じてしまいます。イラストレーターを含めて検討を重ねた結果、正面からライトが当たっている2DイラストにUnity側で陰影を付けるこの方法に決まりました。
印象的な絵作りも大切ですが、STGとして視認性を確保するのも大事な要素です。そこで、レイヤー構造は前面のノーマルマップを付けたオブジェクト・その間の仕切りとしてのフォグ・背面のオブジェクトの3つに分けています。
『NeverAwake』の舞台は悪夢なので、佐渡氏はどこかに違和感のある映像にしなければと考えていました。そこで、例えば以下のワールド2の背景では、静止画では普通に見える道がキャラクターを動かすと歪んで見えるようにしています。こうした効果は、実際に3D上で歪ませたり傾かせたりして配置しました。
アニメーションはUnity純正のAnimatorとAnimationを使用し、ボーン入れ、リギング、メッシュアニメーションの工程を経て制作しました。
AnimatorとAnimationは処理速度が遅く負荷も高いといわれていましたが、最近ではBurst対応もされているらしく、いわれているほどの負荷は感じなかったそうです。
開発2か月目のこの辺りで、どんなクオリティの絵作りができそうかという算段が付いてきました。佐渡氏としては目を引く絵にできそうだと考え、この方針で進行することに決断しました。
『NeverAwake』は、近年のインディーゲームの流行も積極的に取り入れたSTGにしたいと画策していました。ゲームに取り入れた要素を紹介します。
インパクトの瞬間などに画面を一時的に停止したりスローにしたりして、手応えの向上を狙うヒットストップ。
テンポを阻害してミスに直結することもあるのでプレイヤーに嫌われることもある演出ですが、今回は最新型のSTGを作ろうと考えてヒットストップを積極的に取り入れました。
ヒットストップの基本パラメーターには、「静止するフレーム数」と「スローモーション時間」を設定しました。ヒットストップはフレームを静止させるものと思われがちですが、スローモーションも併用することで効果が上がると佐渡氏は考えました。
これに加えて、武器側と敵側でもそれぞれパラメーターを準備。例えば「武器によっては一定以上HPを持つ敵のときだけヒットストップする」「ショットガンのような武器は近距離で敵に着弾したときだけヒットストップする」「反射レーザーのような武器は一切ヒットストップしない」といった、武器と敵の掛け算でヒットストップの反応を変えています。
これにより、武器や敵が変わると手触りも変わる実装になっています。
細かいこだわりとしては、自機の当たり判定と自弾の射出位置の整合を取りました。これがないと操作感が気持ち悪いだけでなく、当たり判定のズレによる事故の原因にもなります。
『NeverAwake』では操作キャラの首を当たり判定の中心にし、弾を射出する手が360度どの角度を向いていてもズレないように調整しています。
メニューやオブジェクトのイージング(動きの速度に緩急をつける)による演出は、快適な操作感を実現するために最小限にしました。
制作側としては、つい気持ち良くなっていろいろと動かしたくなりますが、プレイヤーのインプットにクイックに反応する操作感を最優先にしています。代わりに揺れものなどのオマケの動きで違和感をカバーするようにしました。
これらの調整や工夫を経て、ノータイムでコントローラーに反応する自機と敵を倒した時の手触りを兼ね備えた実装ができあがりました。
インゲーム以外の機能実装は必ずしも楽しいものではありませんが、今回はUnityを学ぶためということもあり粛々と実装することに。
『NeverAwake』はそれほど規模の大きいゲームではありませんが、ステージ数は80、武器やアクセサリーは合わせて100以上。ストーリーや多言語対応もしており、そこそこのデータ量を備えています。
マスターデータの生成や管理方法はいろいろありますが、佐渡氏は効率化のためにGoogleスプレッドシート上に直接コードを書く手法を取りました。シートのセルにそのまま書かれたクラス、セパレーター、引数などを、テキストリーダーに直接コピー&ペーストすればC#コードになるという仕組みです。
この手法は細かい仕様変更や微調整に耐えやすく、規模の小さいプロジェクトに適している、と佐渡氏は語りました。
セーブデータは素直にJSONの文字列にして、それをSHA256(※1)で暗号化保存しています。
ファイル保存の処理はコンシューマー機ごとに異なるので何かしらラップ(※2)をしていたほうがいいとのこと。
※1 任意の長さの入力値から256ビットのハッシュ値を生成する関数
※2 既存のコード(関数、クラス、ライブラリなど)を包んで別の形で提供すること
ここで、続くステージ量産フェーズに備えて、ステージエディタの準備をしました。
『NeverAwake』では、基本のスクロール処理などはUnityのTimelineを使用しています。画面に各シンボルが入ることがオブジェクト出現のトリガーとなります。
ステージエディタは、敵キャラなどを出現させScriptableObjectにデータを保存する「録画モード」とそれらを再生させる「再生モード」に分けました。このようなモード切替は本来なくてもよいのですが、少しでも実行時の負荷を下げるためにこのような構造にしたそうです。
ここまでの機能実装の工数はそれほど大きくなく、最もボリュームがあり期間も長いのがこの量産~仕上げのフェーズです。佐渡氏は、基本的に必要なのは“気合”としていて、いかに効率よく自分自身を飽きさせずに量産をこなしていくかが大事なのだそうです。
まず、通常ステージの開発です。『NeverAwake』は全80ステージ、ボスは全24体いてかなりのボリュームです。これだけステージ数があるとプレイヤーも退屈してしまうので、見た目やどんなプレイをプレイヤーにさせたいかという全ステージのコンセプトを80ステージ分全部書き出しました。
それらをプレイヤーの成長に合わせたレベルデザインを踏まえて「この順番で出したらプレイヤーも飽きないだろう」とシャッフルしていきました。このようにステージコンセプトを最初に決めておくと、ステージ開発そのものに悩む時間が減って効率が上がり、全体像をつかみやすくなります。
開発は1ステージにつき約1日、ボス戦は1体につき4日で完成させるという目標で進めました。
ボス戦は1日目が画像の切り分け、ボーン入れ、リギング、2日目でアニメーション、3~4日目で攻撃の実装というスケジュール感です。
ハードスケジュールではありますが、初期構築時は70%くらいの完成度で済ませておくのが良いと佐渡氏。詰めは時間がある時に後からすればよく、また、他パート進行時にさらに良いアイデアが出る可能性もあります。100%を目指すといつまで経っても終わらないので、完成クオリティの見極めを自分の中でしっかりと持つのが大事だそうです。
Unityを学び、それなりにしっかり組んでいるつもりでしたが、Nintendo Switchで動作させると15fpsくらいしか出ませんでした。STGでは30fpsでも手触りが悪く、60fpsを死守しなければならないと考えて最適化を試みました。
方法としては特別なことはせず、プロファイラとフレームデバッガで粛々と対応していきました。描画のドローコール(※)を抑えたり、CPUの処理負荷のボトルネックを特定して潰したり、マテリアルとスプライトアトラスの最適化をしたりしています。
※ グラフィックスAPIを使用して画面に描画を行う際に呼び出す命令。オブジェクトや要素をレンダリングする回数を意味する
また、先に述べたとおり、当たり判定や一部の計算処理をC# Job System & Burstに移行することで場合によっては10倍くらい早くなることもあり、CPU処理でボトルネックになっている部分が明らかに分かる部分があればこういった手法を検討するのも良いとのこと。
他にも、制御があまり必要ない連番のスプライトアニメは動作の軽いパーティクルシステムに移行するなどしました。
それでもNintendo Switchでは若干フレームレートが足りなかったので、一部の敵機をAnimationから連番のスプライトアニメに移行したり、ロースペック時のみライト数を減らしたりする調整を行いました。
コンシューマー移植に関しては、まず機種依存になるところをあらかじめラップして、機種ごとに処理を振り分けられる仕組みを持たせるのが大切と佐渡氏。
例えば、以下のような箇所が機種依存となると考えられます。
また、Unity開発の場合は、外部アセットの読み込みのためにAddressableを導入し、Nintendo Switchでの動作検証をするのがお勧めだと佐渡氏。Nintendo Switchで最適化を進めておけばプロジェクトのトータルの動作負荷も下がっていきます。
STGで遊んだことのないような方を中心とした初心者層と、トップスコアラーのような上級者層、それぞれの層でテストプレイを実施しました。初心者層には作品が遊びやすいか、クリアまで到達できるかを、上級者層にはSTGとしての強度、やり込みに値するゲームになっているかをチェックしてもらいました。
目的に合わせてテストプレイ層を変えると、広い客層にリーチするゲームになりやすいです。
こういった1年半にわたる工程を経て、2022年6月に『NeverAwake』は完成しました。パブリッシャーの販売計画に準じ、9月の発売まで細かい調整やコンシューマー版の移植作業を行いました。
最後に、開発に関する工夫や実体験が披露されました。
本講演では、STGをUnityで開発する際に役立つ技術情報が多く語られました。それと同時に、限られた期間で開発するために佐渡氏が実施した数々の工夫が共有された点も大きな特徴で、聴講者に知見をもたらす価値ある内容でした。
『NeverAwake』 公式サイト「Indie Developers Conference」 Xアカウントゲーム会社で16年間、マニュアル・コピー・シナリオとライター職を続けて現在フリーライターとして活動中。 ゲーム以外ではパチスロ・アニメ・麻雀などが好きで、パチスロでは他媒体でも記事を執筆しています。 SEO検定1級(全日本SEO協会)、日本語検定 準1級&2級(日本語検定委員会)、DTPエキスパート・マイスター(JAGAT)など。
西川善司が語る“ゲームの仕組み”の記事をまとめました。
Blenderを初めて使う人に向けたチュートリアル記事。モデル制作からUE5へのインポートまで幅広く解説。
アークライトの野澤 邦仁(のざわ くにひと)氏が、ボードゲームの企画から制作・出展方法まで解説。
ゲーム制作の定番ツールやイベント情報をまとめました。
CEDEC2024で行われた講演レポートをまとめました。
BitSummitで展示された作品のプレイレポートをまとめました。
ゲームメーカーズ スクランブル2024で行われた講演のアーカイブ動画・スライドをまとめました。
CEDEC2023で行われた講演レポートをまとめました。
東京ゲームショウ2023で展示された作品のプレイレポートやインタビューをまとめました。
UNREAL FEST 2023で行われた講演レポートをまとめました。
BitSummitで展示された作品のプレイレポートをまとめました。
ゲームメーカーズ スクランブルで行われた講演のアーカイブ動画・スライドをまとめました。
UNREAL FEST 2022で行われた講演レポートやインタビューをまとめました。
CEDEC2022で行われた講演レポートをまとめました。