⚠この記事はブログ移転前のアーカイブです

スマホ向けゲームを作る際に、ソーシャルゲームみたいに「今月のアップデート!」ってな感じで定期的に新しいゲームデータを提供する仕組みを組み込んでおけばユーザーは長く遊んでくれるはずです。

でもゲームデータの中身が変わったらアプリのアップデートをしなければいけない。データ更新のたびにユーザーにアップデートボタンを押させるのはユーザー離れの要因にもなる。特にiPhone, iPadプラットフォームはAppleの審査でものすごい待たされる。

なのでアプリをアップデートさせずにゲームデータだけを更新する仕組みを導入したい。幸いUnityは公式でこの仕組を提供してくれている。

Unityには便利なAssetBundleがある

AssetBundleがあれば必要なときにインターネット上からゲームデータをDLして使うことが出来る。ゲーム内で新キャラの画像とか新ダンジョンのマップなんかもAssetBundleで配信すれば素早くアップデートできる。

でも以下の欠点がある。

  1. 永続的なデータ保存には面倒臭い
  2. 展開に時間かかる。メモリ食い
  3. 高い
  4. 高い
  5. 高い

**高いUnityの**AssetBundle機能を使うには【Pro】版を買わなくちゃならない。【Pro】版でしか使えないんです。

WS000276

UnityProの価格。162,000円也(2014/12現在)。学生の分際でこの価格は無理。

学生向けPro版もありますが、1ライセンスしか認められない=複数台にインストール出来ないので、WindowsとMacを行き来する自分にとってはネックなので今回はなし。学生向けPro版の購入方法は複雑ですのでここを参考にすると良いのではないでしょうか。

学生向けUnityPro版年間ライセンス(12900JPY)を買ったので流れをまとめてみる。 – cstech (id:CST_negi) 

 

2016/02/14【追記】:Unity5がリリースされた現在この機能は無償版に含まれています。特別な理由がない限り、自分で実装するよりAssetBundleを利用するほうが良いと思われます。

 

AssetBundleを使わずにデータを更新する方法を考える

ネットからデータを取ってきて保存する方法を考えましょう。Unityから与えられたデータの保存パスは

Application.temporaryCachePath
  • Android:/data/data/com.XXXXX.MyGame/cache/
  • iOS      :~アプリID/Library/Caches/
Application.persistentDataPath
  • Android:/data/data/com.XXXXX.MyGame/files/
  • iOS      :~アプリID/Documents

Application.temporaryCachePathは文字通りキャッシュ。一時的なファイルの保存に使われる。DLしたzipとかのアーカイブをここに落として展開するなんて使い方が想定できる。OS側から勝手に削除したりすることもある。必要に応じて開放されるってことですね。

Application.persistentDataPathは永続的なデータの保存先。ここにゲームデータを保存するのが良さそう。

注意点

 

  1. Androidは機種によってSDカードにデータ保存することもある。Unity側で制御できるので必ず確認しておくこと。
  2. iOSではApplication.persistentDataPathすなわちDocumentフォルダは【iCloud】のバックアップ対象です。容量の多いデータを保存すると審査に落ちます。(数MB程度でもアウトになった人もいるようです)
  3. 【重要】データの暗号化は必須。

iCloudでバックアップしないように設定する

保存し過ぎるとAppleからreject食らうようですが、フォルダやファイルにNoBackup属性をつけることによってiCloudがそのファイルをバックアップしなくなります。

iPhone.SetNoBackupFlag(string path);

Unityにはパスを入れるだけでNoBackup属性を付けてくれるようです。

データの暗号化は必須

著作権的にもヤバイのでやっておきましょう。AndroidはSDカードに保存してると丸見えですし、rootや脱獄されたら内部データも見放題なので。C#には暗号化APIもいくつかあるようなので自力で実装しなくても良さそうです。AESとかあるしその辺でいいんじゃないでしょうか。

素のデータをダウンロードしてみる

Application.persistentDataPathに対象のファイルが存在すればそれをロード。なければネット上のサーバーからDLして保存する。

IEnumerator LoadData(){
		string filename = "test1.bin";
#if UNITY_EDITOR
		string path = "file:///"+Application.persistentDataPath+"/";
#elif UNITY_ANDROID
		string path = "file://"+Application.persistentDataPath+"/";
#endif
		string url = "https://example.com/data/";
		if (System.IO.File.Exists (Application.persistentDataPath+"/"+ filename)) {
			Debug.Log("find local file");
			www = new WWW (path + filename);
			while(!www.isDone){
				yield return null;
			}
		}
		else if (!System.IO.File.Exists (Application.persistentDataPath+"/"+ filename)) {
			Debug.Log("Can't find local file, Downloading...");
			www = new WWW (url + filename);
			while(!www.isDone){
				yield return null;
			}
			Debug.Log("Done");
			System.IO.File.WriteAllBytes(Application.persistentDataPath+"/"+ filename , www.bytes);
		}
	}

WWWクラスでローカルファイルを取得する場合はパスの頭に「file://」を付けるんですが、windowsやeditorなどは「file:///」じゃないと動きませんでした。iOSは試してませんが「file://」で動くはずです。