[Unity]JsonUtilityを使ったセーブロード機能の作り方

Unity

※本記事でのversion Unity2020.3.32f1

はじめに

こんな人の役に立つかも!

  • JsonUtilityで何ができるの?
  • UnityでJsonデータを扱いたい
  • 外部データのセーブロードについて知りたい
えきふる
えきふる

C#詳しいわけじゃないけども、今回も頑張っていこー

Jsonとは

JavaScript Object NotationJSON、ジェイソン)はデータ記述言語の1つである。軽量なテキストベースのデータ交換用フォーマットでありプログラミング言語を問わず利用できる[1]。名称と構文はJavaScriptにおけるオブジェクトの表記法に由来する。

https://ja.wikipedia.org/wiki/JavaScript_Object_Notation

上記引用のようにデータ交換の際に良く使われるテキストデータのフォーマットのことです。
JavaScript Object Notation」のことでJavaScriptの表記法に似ているんだとか。
(えきふるはC#以外知らない)

JSONは下記のような形で記述されます。左側にデータ名(キー)、右側に値を記述です。

"name":"ekifuru",
"hp": 5,
"atk": 0,
"def": 10000,

「name」というキーに「ekifuru」という値が入っているということになりますね。

JsonUtilityでできる3つの関数

実際にJsonUtilityで出来ることを確認していきましょう!
公式のJsonUtilityドキュメントを確認すると、なんとStatic関数が3つ記載されているだけ

  1. JsonUtility.FromJson(string json);
  2. JsonUtility.FromJsonOverwrite (string json, object objectToOverwrite);
  3. JsonUtility.ToJson (object obj, bool prettyPrint);

それぞれ、下記のようなイメージです。

それでは1つ1つ何ができるのか詳しく見ていきましょう!

えきふる
えきふる

全スクリプトこのくらいシンプルで頼む

JsonUtility.FromJson

FromJsonという名前の通りで、JsonからUnityオブジェクトを作成します。

まずUnityでJSONデータを渡すためにクラスを作成します。
この際クラス上部に[System.Serializable]という記述をしてください。※理由は後述。
また、変数名はJSONで扱うキーと同じにする必要がありますのでこちらも注意。

[System.Serializable]
public class ChClass
{
    public string name;
    public int hp;
    public int atk;
    public int def;
}

これでChClassというクラスができました。

えきふる
えきふる

クラスはインスタンスで作成されるオブジェクトの設計図のようなもの

次にスタート時にjsonデータを作成して、読み込みます。
記述の仕方は JsonUtility.FromJson<クラス名>(JSONデータ名)となります。

void Start()
    {
        string json = "{ \"name\": \"ekifuru\", \"hp\": 5, \"atk\": 0, \"def\": 10000}";//JSONの作成
        ChClass ekifuru = JsonUtility.FromJson<ChClass>(json);//作成したJSONからJsonUtilityでChClassを作成
        Debug.Log("名前:" + ekifuru.name + " HP:" + ekifuru.hp + " Atk:" + ekifuru.atk + " Def:" + ekifuru.def);
    
    }

Debugログを出力すると確かにJsonが変換されて渡されています。

UnityゲームエンジンでのDebug表示

以下全文です。

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

[System.Serializable]
public class ChClass
{
    public string name;
    public int hp;
    public int atk;
    public int def;
}

public class JsonTest : MonoBehaviour
{

    void Start()
    {
        string json = "{ \"name\": \"ekifuru\", \"hp\": 5, \"atk\": 0, \"def\": 10000}";//JSONの作成
        ChClass ekifuru = JsonUtility.FromJson<ChClass>(json);//作成したJSONからJsonUtilityでChClassを作成
        Debug.Log("名前:" + ekifuru.name + " HP:" + ekifuru.hp + " Atk:" + ekifuru.atk + " Def:" + ekifuru.def);
    
    }

}
オマケ:JSONのC#上での記述について

上記でJSONデータの所を

string json = "{ \"name\": \"ekifuru\", \"hp\": 5, \"atk\": 0, \"def\": 10000}";

と記述しました。これは下記のJSONデータをC#上でstring型変数に記述して格納したという事になります。

"name":"ekifuru",
"hp": 5,
"atk": 0,
"def": 10000,
えきふる
えきふる

\”とかをつけ忘れるだけでエラーになるから結構繊細ね

オマケ:シリアライズに関して

JsonUtilityではJSON化するためにシリアライズ可能なものしかJSON化できないようです。
公式のUnityドキュメントを見る限りでは、UnityのJSONシリアライズ機能でオブジェクトをJSON化したりしているので、納得です。※詳細は公式ドキュメント見てくださいませませ。

JsonUtility.FromJsonOverwrite

FromJsonと似ていますが、FromJsonOverwriteと記載されているとおり、既存のオブジェクトデータにJSONのデータをOverwrite=上書きをする関数になります。

FromJsonの項目で作成したオブジェクトekifuruに上書きしてみましょう。
記述の仕方は
JsonUtility.FromJsonOverwrite (JSONデータ名, 上書きするオブジェクト名);
となります。

void Start()
    {
        string json = "{ \"name\": \"ekifuru\", \"hp\": 5, \"atk\": 0, \"def\": 10000}";//JSONの作成
        ChClass ekifuru = JsonUtility.FromJson<ChClass>(json);//作成したJSONからJsonUtilityでChClassを作成
        Debug.Log("名前:" + ekifuru.name + " HP:" + ekifuru.hp + " Atk:" + ekifuru.atk + " Def:" + ekifuru.def);
//下記追加
        string overwritejson = "{ \"name\": \"ekifuru2gou\", \"hp\": 50000, \"atk\": 50, \"def\": 0}";//上書き用のJSONの作成
        JsonUtility.FromJsonOverwrite(overwritejson,ekifuru);//上書き用のJSONでJsonUtilityを使いでChClass「ekifuru」を上書き
        Debug.Log("えきふるは上書きされた!" + "名前:" + ekifuru.name + " HP:" + ekifuru.hp + " Atk:" + ekifuru.atk + " Def:" + ekifuru.def);
    }

Debugログを出力すると上書きされているのが確認できます。

UnityゲームエンジンでのDebug表示

なお、FromJsonOverwriteは上書きするオブジェクトの全ての変数の値を上書きする側のJSONが持っていないとエラーになるので注意が必要です。

一応こちらも全文載せておきます。

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

[System.Serializable]
public class ChClass
{
    public string name;
    public int hp;
    public int atk;
    public int def;
}

public class JsonTest : MonoBehaviour
{
void Start()
    {
        string json = "{ \"name\": \"ekifuru\", \"hp\": 5, \"atk\": 0, \"def\": 10000}";//JSONの作成
        ChClass ekifuru = JsonUtility.FromJson<ChClass>(json);//作成したJSONからJsonUtilityでChClassを作成
        Debug.Log("名前:" + ekifuru.name + " HP:" + ekifuru.hp + " Atk:" + ekifuru.atk + " Def:" + ekifuru.def);
//下記追加
        string overwritejson = "{ \"name\": \"ekifuru2gou\", \"hp\": 50000, \"atk\": 50, \"def\": 0}";//上書き用のJSONの作成
        JsonUtility.FromJsonOverwrite(overwritejson,ekifuru);//上書き用のJSONでJsonUtilityを使いでChClass「ekifuru」を上書き
        Debug.Log("えきふるは上書きされた!" + "名前:" + ekifuru.name + " HP:" + ekifuru.hp + " Atk:" + ekifuru.atk + " Def:" + ekifuru.def);
    }
}

JsonUtility.ToJson

名前でもうピンとくるかと思いますが、FromJsonの逆、Unityのインスタンス側から jsonを作成する関数になっています。

えきふる
えきふる

勘の良いガキは嫌いじゃないよ・・・

実際にやってみましょう。
ChClassに新しくappleというインスタンスを作り、値を入れてJsonUtility.ToJsonで json化してみます。
記述は
JsonUtility.ToJson (オブジェクト名, bool);
となります。
第2引き数のboolは記述がなくても良いのですが、trueと記述しておくと json形式のように綺麗にテキストを整理してくれます。

ChClass apple = new ChClass();
        apple.name = "ringo";
        apple.hp = 99999;
        apple.atk = 88888;
        apple.def = 77777;

        string json = JsonUtility.ToJson(apple,true);//クラスからJSONの作成
        Debug.Log(json);

Debugログで確認してもちゃんと json化できていますね。テキストの整理もされています。

UnityゲームエンジンでのDebug表示

こちらも全文を載せておきますね。

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

[System.Serializable]
public class ChClass
{
    public string name;
    public int hp;
    public int atk;
    public int def;
}

public class JsonTest : MonoBehaviour
{
    void Start()
    {
        ChClass apple = new ChClass();
        apple.name = "ringo";
        apple.hp = 99999;
        apple.atk = 88888;
        apple.def = 77777;

        string json = JsonUtility.ToJson(apple,true);//クラスからJSONの作成
        Debug.Log(json);
    }
}

JSONを使ったセーブ &ロード

さて、ここまで JsonUtyilityの機能を見てきましたが、わざわざjsonを使わず、普通に変数使えば良いんじゃない?と思った方も多いのではないでしょうか。

Jsonファイルを扱う大きな利点はテキストファイルとして外部に保存、読み込みができることです。
そう!ゲームが終了しても最後に実行した結果が保存されるんですね!これセーブロードや!

えきふる
えきふる

セーブ &ロードに使えるのだ

実際にセーブ(書き出し)とロード(読み込み)の仕方を見ていきましょう。

JSON ファイルの書き出し(セーブ)

まずusing System.IOを先頭に記述します。
これはファイルやフォルダ、ストリームデータを読み書きするのに必要なI/O処理=Input/Output処理を行えるようにするものです。

ここでは書き込むスクリプトとして
WriteAllText(ファイルパス, ファイルに書き込むコンテンツ)
を使います。

事前にUnityのAssetsフォルダ内にResourcesフォルダを作成しておきましょう。
これは後で読み込む際にResources.Loadを使用してデータをロードする為に必要だからです。

今回は下記のように記述しました。

    void Start()
    {
        ChClass Player01 = new ChClass();
        Player01.name = "えきふる";
        Player01.hp = 100;
        Player01.atk = 25;
        Player01.def = 5;
        Save(Player01);//saveメソッドを別に作成して呼び出すようにしました。
    }

public void Save(ChClass player)
    {
        string json = JsonUtility.ToJson(player, true);//jsonに変換
        File.WriteAllText($"Assets/Resources/ChClass.json", json);//Assetsフォルダ直下に書き出し。最終媒体に合わせてパスは変更してください。
    }

実行するとResourcesフォルダ内にjson形式のテキストデータが作成され、player01の内容が記述されています。これでjsonファイルの出力、セーブができましたね!

Resouracesフォルダ直下にテキストアセットが作成される

実行する全文を下記に載せておきます。

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System.IO;

[System.Serializable]
public class ChClass
{
    public string name;
    public int hp;
    public int atk;
    public int def;
}

public class JsonTest : MonoBehaviour
{

    void Start()
    {
        ChClass Player01 = new ChClass();
        Player01.name = "えきふる";
        Player01.hp = 100;
        Player01.atk = 25;
        Player01.def = 5;
        Save(Player01);


    }
public void Save(ChClass player)
    {
        string json = JsonUtility.ToJson(player, true);
        File.WriteAllText($"Assets/Resources/ChClass.json", json);
       
    }
}

JSON ファイルの読み込み(ロード)

それでは、先ほど書き出ししたJSONファイルを読み込んで、ロードしてみましょう!
これは凄く簡単で先ほどRosourcesフォルダに書き出したJSONファイルをTextAssetとしてResources.Loadで読み込むだけです。

   public void Load(ChClass player)
    {
        TextAsset jsonLoad = Resources.Load<TextAsset>("ChClass");
        ChClass Player01 = JsonUtility.FromJson<ChClass>(jsonLoad.text);
        Debug.Log("ロードした!" + jsonLoad);

    }

Debugログでロードされていることが確認できました。

UnityゲームエンジンでのDebug表示

こちらも全文載せておきます。

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System.IO;

[System.Serializable]
public class ChClass
{
    public string name;
    public int hp;
    public int atk;
    public int def;
}

public class JsonTest : MonoBehaviour
{
    void Start()
    {
        ChClass Player01 = new ChClass();
        Load(Player01);//Loadメソッドを作成

    }

    public void Load(ChClass player)
    {
        TextAsset jsonLoad = Resources.Load<TextAsset>("ChClass");//TextAsset形式でResources直下のJSONを読み込む
        ChClass Player01 = JsonUtility.FromJson<ChClass>(jsonLoad.text);//読み込んだJSONからChClassを作成
        Debug.Log("ロードした!" + jsonLoad);
    }
}

※StreamWriter、StreamReaderを使ってファイルを読み書きする方法もありますので、別の記事で記載したいなと思っています。

オマケ:パフォーマンスが優れている

JsonUtilityは(機能は .NET JSON より少ないですが)、よく使用されている .NET JSON よりも著しく早いことが、ベンチマークテストで示されています。

JSON 形式にシリアライズ

Unityドキュメントによると、パフォーマンス面でもJsonUtilityは優れているようです。

最後に

JsonUtilityの使い方とセーブロードの方法を解説してみました。
自分もまだまだ勉強中の身なので、より理解が深まったら随時加筆していきます。
もし、認識違うよ!ここおかしいよ!とかありましたら教えてください。
勉強になりますので大変助かります。

えきふる
えきふる

のんびりいこう!

※このブログは、UnityTechnologiesまたはその関連会社が後援または提携しているものではありません。「Unity」は、UnityTechnologiesまたはその関連会社の米国およびその他の国における商標または登録商標です。

コメント

タイトルとURLをコピーしました