目次
今回は社内の成果発表会「P-Review ’19」にて発表した、エンジニア 鈴木 健太さんの資料を紹介します。
※この記事は個人の研究発表で、会社としての見解ではございません。
P-Review19_suzuki-1鈴木 健太
2019年4月ゲームサービス部(現:アピゲー部)エンジニアとして入社。
入社後は主にクライアントエンジニアとしてゲーム制作を行っている。
(※挨拶省略)
非同期読み込みはなぜ大事?
今回のテーマ設定理由は、学生のゲーム制作では触れる機会が少ないにも関わらず、製品としてのゲーム制作では必須となる技術だからです。
実際に私も学生時代にゲーム制作を行っていましたが、非同期読み込みについては触れておらず、実際の業務で初めて触れてつまづいてしまった点でした。
ですので、後世の新卒が私と同じ箇所でつまづかないようにしたいと思い、このテーマを設定致しました!
また、テーマにもあるアセットですが、この発表内ではゲーム内の画像やサウンドなどのファイルデータを指すものと定義します。
何につまづいてしまったのか
それでは実際に私が非同期読み込みでつまづいた点ですが……
「AssetBundle」「コルーチン」「コールバック」
この3つについて「なにそれ、おいしいの?」となってしまいました。
なにがなんだかわからなくなってしまって、つまづきました。
なぜなら、調べても基本がわかっていることが前提となっていて「実際のプログラムでは、こう書くよ」といったような記事が多かったことや、概要を知りたいのにより深いところまで解説されていて、求めているもの以上の情報がありすぎて、基本がわからないことが原因でした。
この問題は時間をかけて少しずつ読み解いていくしかなかったのですが、この作業を新卒が毎回やっていたら、流石に時間がもったいない!
ということで、「AssetBundle」「コルーチン」「コールバック」がどんなものなのか、新卒の方でもイメージが掴めるようにまとめてみました。
AssetBundle(アセットバンドル)を学ぼう
まず「AssetBundle」ですが、これはアセットの格納および読み込みのシステムで、Unity独自で搭載されているものになります。
その特徴としては、複数のアセットを1つに圧縮でき、ゲーム内での任意のタイミングで「AssetBundle」を読み込むことで、アセットを使用することができるようになります。
ただし、実際にゲーム内でアセットを使用する場合は、そのアセットが含まれる「AssetBundle」を読み込んだあとに、アセットの読み込みを別途行う必要があります。
そして、「AssetBundle化」する場合、どれだけのアセットを1つの「AssetBundle」として圧縮するのかは、プロジェクトによって異なります。
たとえば、1つの「AssetBundle」に1つのアセットとする場合もあれば、キャラクターごとに「AssetBundle」を分ける場合もあります。
AssetBundleを例えると?
もう少し、「AssetBundle」をイメージしやすいものに例えますと、zipフォルダのようなものという認識で問題ありません。
こちらの表にあるように、アセットの圧縮はフォルダ圧縮する処理にあたり、「AssetBundle」の読み込みと、アセットの読み込みは2つの機能を合わせて、zipフォルダでのフォルダ解凍のようなものです。
AssetBundleはどこに置く?
では、この「AssetBundle」をプロジェクトに組み込むとどうなるのかなんですが……
「AssetBundle」はアプリ本体に組み込むこともできますがサーバーに置くこともできます。
サーバーに置くと、サーバーから「AssetBundle」をダウンロードする必要が出てきてしまいますが、アプリ本体からアセットを取り除くことができます。
なのでアセットの量が多いソシャゲなどでも、アプリ本体のサイズ自体は小さく保つことができます。
逆にアプリ本体に置いた場合は、ダウンロードは不要ですがアセットが増えるほどアプリ本体の容量も増えていきます。
アセットが使用可能になるまでの3ステップ
実際にアセットが使用可能になるまでを図に表したものがこちらになります。
①「AssetBundle」のダウンロードが必要ならダウンロード
②ダウンロード後「AssetBundle」の読み込み
③最後に、アセットの読み込み
「AssetBundle」はzipフォルダのようなものと例えましたが、zipフォルダはダウンロードして解凍してファイルが使用可能になるまでに時間がかかると思うのですが、同様に「AssetBundle」でも必要なアセットを読み込み終わるまでにとても時間がかかってしまいます。
そのため多くのゲームでは、この時間がかかる処理はロード画面を表示することで対応しています。
ロード画面はこういうイメージのもので、よくアプリゲーム内でも場面が変わる時によく表示されていて、「早くロード終われ〜」とか思ったことがある人が多いんじゃないかなと思います。
メイン処理で先ほどのようなロード画面を表示し、その裏でダウンロードや読み込みなどの時間のかかる処理を行います。
このようにメイン処理の裏で別の処理を実行することを、非同期処理といいます。
そして、Unityにおけるアセットの非同期読み込みの処理を実装する手法の1つとして、コルーチンとコールバックを組み合わせたものがあります。
ですので、次にコルーチンの説明をしていきます。
コルーチンを学ぼう
コルーチンというのは、メイン処理から独立して処理が実行されるメソッドです。
つまり、コルーチンは非同期処理ができるメソッドになります。
特徴としてレジューム機能を持っており、一連の処理の途中で一旦停止して、その停止した箇所から任意のタイミングで処理を再開することができます。
この再開する任意のタイミングというのは、例えば特定の処理が終わった時だったり、一定時間経過した時だったりします。
このレジューム機能があることで、一連の処理をフレームを跨いで実行することができます。
補足ですが、Unityのコルーチンのレジューム機能は厳密にいうとコルーチンそのものは止まってはおらず、処理を進めずに何もしないという処理をするもので、見た目上、停止しているように見えます。
コルーチンの用例
一連の処理をフレームを跨いで処理することができることにより、例えば時間経過を用いるイベントを実装したいときに、コルーチンを用いて簡単に実装することができます。
フェード処理であれば1フレームごとにα値を更新することでフェード処理を進めていき、フェードアウトであれば徐々に見えなくしたり、フェードインなら徐々に現れるようにしたりできます。
また、重い処理を実行することにも向いておりまして、複数のフレームに処理を分割することで処理落ちを防ぐこともできたりします。
例えば、テーマにもしているアセットの読み込みで、「AssetBundle」のダウンロードや読み込みなどを複数のフレームに分割して実行することで処理落ちを防ぐことができます。
最後にコールバックの説明に移ります。
コールバックを学ぼう
「コールバック」というのは、別のメソッドに呼んでもらうためのメソッドや処理の塊のことです。
引数として処理の塊を渡すことが多く、呼び出し側の好きなタイミングで呼ぶことができるものになります。
そのため、処理Aと処理Bの間で呼べるようにすることもできたり、非同期処理と組み合わせて非同期処理の終了を常に監視していなくても、処理が終わったタイミングで勝手にコールバックを呼んでもらうみたいなことができます。
アセットの非同期読み込みの流れ
「AssetBundle」「コルーチン」「コールバック」について説明してきましたが、これらを用いてアセットの非同期読み込みの流れについてまとめます。
①ロード画面を表示し、ダウンロードが必要なら「AssetBundle」をサーバーからダウンロードする
②「AssetBundle」を読み込み、必要なアセットの読み込みを行う
③これらの重い処理をコルーチンで行い、アセットの読み込みが終わったタイミングでコールバックとしてロード画面の表示を終了する処理を呼ぶ
この流れで、アセットを非同期で読み込むことができます。
つまづきやすいポイントをおさらい
アセットの非同期読み込みでつまづきやすいポイントは「AssetBundle」「コルーチン」「コールバック」の3つあります。
「AssetBundle」はアセットの格納と読み込みのシステムでzipフォルダみたいなものです。
また、サーバーに置いておくこともできるため、ダウンロードする手間はありますが、アプリ本体の容量を小さくするというような働きもあります。
「コルーチン」は非同期処理ができる特殊なメソッドで、レジューム機能があります。
そして「コールバック」は、処理の塊を好きな時に別のメソッドから呼ぶ手法で、非同期読み込みでは読み込みが終わったことを通知してくれるものになります!
非同期読み込みを使いこなして、快適なゲーム制作をしていきましょう!
製品としてのゲーム制作には必須の技術なのに、わかりやすい資料が少なかったなんて……。
鈴木さんのまとめから、難しい「AssetBundle」でつまづく新人が減るといいですね!!