フロントエンド開発Blog

オレには鈍器がある

JavaScript , unity , webview

前回の記事「Unity3Dのgree webviewでローカルHTMLを表示し、JSからUnityのコードを実行してファイル読み書きする」でなんとなくwebviewからUnityコードをたたくところまで試してみました。

今日はもう少し突っ込んでやってみました。

  • セーブデータはローカルに保存
  • データ形式はJavaScriptオブジェクトをJSON形式に変換してからbase64にしてテキストとして保存
  • ロード時に上記を逆変換してJavaScriptオブジェクトにする

C#スクリプトは前回とほぼ同じ

using UnityEngine;
using System.Collections;
using System.IO;
using System.Text;
using System.Text.RegularExpressions;

public class attachWevView : MonoBehaviour {
	//private string url = "file:///android_asset/streamingAssets/index.html";
	WebViewObject webViewObject;
	
	// Use this for initialization
	void Start () {
		webViewObject = (new GameObject("WebViewObject")).AddComponent();
		webViewObject.Init((msg) =>
        {
            Debug.Log("------------------------------------------");
            Debug.Log(msg);

            string savePattern = "save__";
            Match match = Regex.Match(msg, savePattern);

            if (match.Success)
            {
                Debug.Log("persistentDataPath:" + Application.persistentDataPath);
                StreamWriter sw = new StreamWriter(Application.persistentDataPath + "/savefile.txt", false); //true=追記 false=上書き
                sw.WriteLine(msg);
                sw.Flush();
                sw.Close();
            }
            else if(msg == "load")
            {
                FileInfo fi = new FileInfo(Application.persistentDataPath + "/savefile.txt");
                using (StreamReader sr = new StreamReader(fi.OpenRead(), Encoding.UTF8))
                {
                    string loadedText = sr.ReadToEnd();
                    Debug.Log("LOG: " + loadedText);
                    webViewObject.EvaluateJS(
                        "Unity.updatePlayerStatusByUnity('" + loadedText + "');"
                    );
                }
            }
        });
        webViewObject.LoadURL("file:///android_asset/index.html");

        webViewObject.SetMargins(0, 0, 0, 0);
		webViewObject.SetVisibility(true);
	}
	
	// Update is called once per frame
	void Update () {
	
	}
}

変わったところだけかいつまんでみていくと、まず正規表現によるmatchが使いたいのでSystem.Text.RegularExpressionsをインポートしました。

WebViewのUnity.call()save__から始まるメッセージが送られてきたらセーブ書き込みとして処理したいため、Regex.Match(msg, savePattern)でマッチングチェックをします。StreamWriterを使った書き込み処理自体は前回と同じです(Android実機のファイルマネージャー内部ストレージの./Android/data/{アプリケーションドメイン}/files配下にファイルを書き出しできます)

続いてload処理ですが、Unity.call("load")が呼ばれたらStreamReaderでテキストファイルから文字情報を読み込みます。ここでひとつ注意ですが、ストリームリーダーは一度endまで読み込んだら次回以降は空文字列がかえってくる点です。

FileInfo fi = new FileInfo(Application.persistentDataPath + "/savefile.txt");
using (StreamReader sr = new StreamReader(fi.OpenRead(), Encoding.UTF8))
    Debug.Log("LOG: " + sr.ReadToEnd());
    Debug.Log("LOG2: " + sr.ReadToEnd());
}

こちらの例でいうと、一回目のLOGは正常に文字列が書き出されますが二回目のLOG2は空になります。sedとかになじみのない方は戸惑うかもしれませんので念のため。

load側では読み込んだテキストをWebView側に渡すために「EvaluateJS」を追加しています。これはUnityからWebViewのJSを実行するメソッドになります。updatePlayerStatusByUnityというJS側のメソッドにloadした文字列を渡して実行しています。

JavaScriptでセーブファイルを作ってUnityに投げる

base64化はMasanao Izumo様のbase64.jsを使うと古いブラウザでもbase64化ができます。モダンブラウザの場合はatobメソッドでエンコード、btoaメソッドでデコードできますが念のためライブラリを使わせていただきます。

function getSaveObj(datas){
  return base64encode(escape(JSON.stringify(datas)));
}

日本語が含まれていてもbase64化できるように念のためescapeしておきます。あとはbase64化したテキストにsave__文字列を追加してUnityに投げます。

Unity.call("save__" + getSaveObj({a:1,b:2}))

これでローカルにsave__2upoifds;lakfds;lafjdsaoiみたいなテキストファイルが保存されたと思います。

JavaScriptでセーブファイルをloadする

先ほど、Unity側でload時にWebViewの「Unity.updatePlayerStatusByUnity」を実行するようにしました。JS側にこのメソッドを作ります。

Unity.updatePlayerStatusByUnity = function(data){
  data = data.replace(/^save__/,"");
  var obj = JSON.parse(unescape(base64decode(data)));
  
  //復元されたセーブデータから状態を復元
  player.status = obj;
}

saveのときと逆順に、bse64デコードし、unescapeしてJSON.parseしてオブジェクト化します。これだけでOKです。

ページトップへ

関連ページ

ページトップへ