Unity を検索

永続データ ― ゲームの状態と設定を保存する方法

2021年2月23日 カテゴリ: テクノロジー | 10 分 で読めます
Game scene with space soldier shooting a robot
Game scene with space soldier shooting a robot
シェア

データの保存は、どんなゲームにとっても重要です。ハイスコア、設定、ゲームの状態など、保存するデータの種類によらず、Unity は PlayerPrefs からデータのシリアル化、暗号化、ファイルへの書き込みまで、データを保存するさまざまな方法を提供します。

Unite Now 2020 の一環として、Unity でのデータの永続性に関するヒントをまとめたセッションを行いました。このセッションでは、Unity プロジェクトでデータを保存したり読み込んだりするための一般的な方法をいくつか取り上げましたが、すべてを網羅できたわけではありませんでした。つまり、データをシリアル化する方法は皆さんが必要とするものの他にも存在しており、それぞれのアプローチが特定の問題を解決し、またそれぞれ長所と短所を持っているということです。このブログ記事では、Unite Now のセッションで話したのと同じ一般的な方法を紹介します。

PlayerPrefs

PlayerPrefs はゲームの状態を保存するために作られたものではありません。しかし、便利なのでここで取り上げます。PlayerPrefs を使って、セッション間のプレイヤーの設定(品質設定、オーディオの音量、その他必須ではないデータなど)を保存することができます。PlayerPrefs は、プロジェクトとは別に、デバイス上のどこかに保存されます。正確な場所はオペレーティングシステムによって異なりますが、通常はグローバルにアクセスでき、OS によって管理されている場所になります。保存されるデータは、単純なキーと値のペアになっています。アクセスが容易なため、それらを開いて変更しようとするユーザーからは守られていませんし、プロジェクトの外に保存され、OS によって管理されているため、誤って削除されることもあります。

PlayerPrefs は数行のコードで比較的簡単に実装できますが、float 型、int 型、string 型の値しかサポートしていないため、大規模で複雑なオブジェクトをシリアル化するのは困難です。ユーザーが本気で対処するならば、保存したデータをこれらの基本型のいずれかで表される形式に変換することでこの制限を克服することもできますが、データを保存するためのより良いツールがあるので、おすすめできません。

その上、各 Unity アプリケーションは、すべての PlayerPrefs を 1 つのファイルに保存するため、複数のセーブファイルやクラウドセーブを扱うのには適していません。こうした要件を満たすには、様々な場所からセーブデータを受け取り、保存することが求められるためです。

JSON

JSON は人間が読めるデータ形式です。これは、人にも機械にも簡単に理解できるということを意味します。このことは長所でもあり、短所でもあります。セーブデータを読み取って理解できるようになれば、テスト目的でセーブデータをデバッグしたり、新たにセーブデータを作成したりするのが格段に楽になりますが、その反面、プレイヤーがデータを読み取ったり変更したりすることも容易になります。データを読み込んで変更できることは、改造をサポートする場合には便利ですが、不正行為を防ぎたい場合には有害です。それぞれのユースケースは異なり、開発者が他のデータ形式を多数作成するのは、このような種類のトレードオフがあるためです。

JSON は標準化されており、様々なアプリケーションで広く使われています。このため、すべてのプラットフォームで強力にサポートされており、クロスプラットフォームのゲームを構築する際に役立ちます。JSON は Web ブラウザの通信プロトコルとして開発されたもので、本来はネットワークを介してデータを送信するのに適しています。そのため、JSON はサーバーのバックエンドとのデータの送受信に優れています。

JsonUtility

 

JsonUtility は、JSON データをシリアル化、逆シリアル化するための Unity の組み込み API です。PlayerPrefs と同様に、実装も比較的簡単です。ただし、PlayerPrefs とは異なり、JSON データを自分でファイルかネットワーク経由で保存する必要があります。データの保存を自分で扱うことでファイルをそれぞれ別の場所に保存できるので、複数の保存ファイルを管理しやすくなります。これを簡単にするために、基本的なファイルマネージャーを書いてみました。こちらのサンプルレポジトリでご利用いただくことができます。

重要なこととして、JsonUtility はすべての機能を備えた JSON の実装ではないことに言及しておきます。JSON データの操作に慣れている人は、特定の機能のサポートがないことに気づくかもしれません。特定の機能を提供していないことは設計上の意図的な選択です。その選択の結果、JsonUtility は他の .NET JSON ソリューションよりも高速で効率的なものとなっています。

JsonUtility は Unity 内部のシリアライザーと同じ制約を受けます。つまり、あるフィールドをインスペクターでシリアル化できない場合、JSON にシリアル化することもできません。これらの制限を回避するには、すべてのセーブデータを保持する Plain Old Data(POD)型を作成します。保存時には、ランタイム型から POD にデータを映して、ディスクに保存します。必要に応じて、Unity のシリアライザーがデフォルトでサポートしていない型をサポートするためのカスタムのシリアル化コールバックを作成することもできます。

JsonUtility について言えば、EditorJsonUtility も便利な道具です。JsonUtility が MonoBehaviour や ScriptableObject ベースのオブジェクトに対応しているのに対し、EditorJsonUtility は Unity のエンジン型に対応しています。そのため、Unity エディターで任意のオブジェクトの JSON 表現を作成することもできますし、逆に JSON ファイルからアセットを作成することもできます。

その他のライブラリ

組み込みのシリアル化のオプション以外にも、役立つ外部ライブラリが存在します。

  • EasySave は Unity アセットストアで入手できるアセットで、サポートが行き届いていて人気のあるプラグインです。まったくコードを書かずにあらゆるデータを保存することができるので、特に初心者の方におすすめです。また、知識のあるユーザー向けに、このプラグインを思い通りに動作させるためのパワフルで柔軟性のある API も用意されています。無料ではありませんが、最初から必要な機能をすべて備えたソリューションをお求めの方にとっては、値段に見合った価値はあるアセットです。
  • JSON.NET は、すべての .NET プラットフォームに対応した、無料で使えるオープンソースの JSON 実装です。組み込みの JsonUtility とは異なり、すべての機能を備えています。標準版は Unity のすべてのプラットフォームをサポートしていませんが、Unity アセットストアではサポートを追加した修正版が提供されています。
  • XML も利用候補となりうるデータ形式です。JSON のように比較的人間が読みやすく、名前空間など、ある種のアプリケーションで有用な機能を持っています。.NET には組み込みの XML サポートがあります。
  • BinaryFormatter は、オブジェクトを直接バイナリ形式で保存するための .NET ライブラリです。しかし、BinaryFormatter には危険度の高いセキュリティ上の脆弱性があり、使用を避けるべきです。セキュリティ上のリスクについてはこちらをご覧ください。

データセキュリティ

セキュリティといえば、ほとんどの人がまず暗号化を思い浮かべます。しかし、プレイヤーのデバイスにデータをローカルに保存する場合、暗号化は比較的簡単に破られてしまいます。暗号化を破らなくても、ユーザーはフリーのツールを使って、メモリ内のデータを直接操作することができます。つまり、ローカルに保存されているあらゆるものは信用できないと思っておいた方が無難です。

セキュリティが本当に必要な場合は、ユーザーが変更できないようにサーバー上にデータを保管するのが最善の方法です。このやり方を機能させるためには、アプリケーションにデータを直接サーバーに送信させるべきではありません。その代わり、アプリケーションはサーバーにコマンドを送信し、サーバーにデータを変更させ、その結果をアプリケーションに送り返させるようにします。データのセキュリティが重要ならば、このような要素はプロジェクトのアーキテクチャに影響を与えるので、できるだけ早く認識しておくべきでしょう。

シリアル化の詳細については、マニュアルのページをチェックしてください。シリアル化の動作を見てみたい方は、こちらの Unite Now セッションをご覧ください。

2021年2月23日 カテゴリ: テクノロジー | 10 分 で読めます