【Unity】JsonUtilityを勉強してみた

いつものサボり癖…
ではないですよ~

体重管理アプリを作っていて泥沼にハマっています。

データ管理を月別に保存や表示させるのに
どうやったらいいか悩んでおります。

今までは、コードがなんとなく思い浮かんだのですが、
今回は頭がまったく働いてくれません。
(ノ_<。)うっうっうっ


思考停止で進んでないので、記事も書けなかった次第です。
(´~`;)才能ないな~

そんな状況なんですが、少し調べた事があったので、
記事にしてみたいと思います。


大量のテキストデータを保存するには、
CSV形式かJson形式を利用する事になるのですが、
以前、CSVを記事にしたので、
今回は、Json形式を記事にしたいと思います。

ジェイソンと言えば、13日の金曜日!
(;^o^) \(ToT )昭和か!


JSONとはJavaScript Object Notationの略で、
JavaScriptのオブジェクトの書き方を元にしたデータ定義方法なんだそうです。

UnityでJsonを使うには、いくつかの方法があるみたいですが、
JsonUtilityが機能としてあるので勉強してみます。


侍ブログさん
【Unity入門】5分で簡単解決!JSON形式のデータを扱う方法

メモの穴さん
UnityでJSONファイルを読み込むメモ
有益な情報ありがとうございます。<(_ _)>


ブログを参考にJsonを組んでみます。
Unityで適当にプロジェクトを立ち上げて、空のオブジェクトを追加します。
Json①.jpg
新規スクリプトを作成して、JsonTestにリネームして
空のオブジェクトにアタッチしておきます。

侍ブログさんで紹介されている情報を元に作成してみました。
Json⑧.jpg
説明によると、keyを設定してデータを紐づけるとの事なので、
””で囲われているのがkeyで:の後ろがデータとなるようです。

“Hp” : 100だとHpで呼び出せば、100と言うデータが返ってくるみたいです。
keyに紐づいたデータを読み込んだり、書き換えたりする事ができるようです。

この段階では、このデータをどこに書けばいいの?となりました。
スクリプトにいきなり書き込んでもエラーがでるだけなので、
Jsonとして読み込めるように処理を作っていきます。

まず、紹介されているスクリプトを組んでみます。
JsonTest

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


[Serializable]
public class Player
{
public int hp;
public int attack;
public int defense;
}

public class JsonTest : MonoBehaviour
{
// Start is called before the first frame update
void Start()
{
Player player = new Player();
player.hp = 100;
player.attack = 20;
player.defense = 7;
string jsonstr = JsonUtility.ToJson(player);

Debug.Log(jsonstr);
}
}


JsonUtilityは、Systemを呼び出す必要があるので宣言しておきます。

Jsonの構成をクラスで定義する必要があるみたいなので、
public class Playerを作成します。

このPlayerクラスは、シリアライズしないと利用できないみたいなので、
[Serializable]を設定しておきます。

定義ができたらStart内で処理を作ります。

Player player = new Player();でインスタンスを生成します。
これで、playerには、クラスで定義した構造が内包している事になります。

ここから意味を把握するのに時間が掛かったのですが、
string jsonstr = JsonUtility.ToJson(player);
の意味が分かりませんでした。

例えば
JsonTest

// Start is called before the first frame update
void Start()
{
Player player = new Player();
player.hp = 100;
player.attack = 20;
player.defense = 7;

Debug.Log(player);
}

これで表示されるのでは?と思ったのですが、

Json③.jpg
こんな感じになります。

あくまで構造を利用して、Json形式に変換しなといけないので、
string jsonstr = JsonUtility.ToJson(player);が必要になってきます。

JsonUtility.ToJson(player)を使って変換すると
Json④.jpg
こんな感じに出力されます。

侍ブログさんでは、続いてオブジェクトに変換を紹介されています。
JsonTest

// Start is called before the first frame update
void Start()
{
Player player = new Player();
player.hp = 100;
player.attack = 20;
player.defense = 7;
string jsonstr = JsonUtility.ToJson(player);

Debug.Log(jsonstr);

Player player2 = JsonUtility.FromJson<Player>(jsonstr);

Debug.Log(player2.hp);
Debug.Log(player2.attack);
Debug.Log(player2.defense);
}

これの実行結果は
Json⑤.jpg
playerのデータをplayer2に渡す事ができました。

一度、Json形式にしたデータを別のオブジェクトに渡す時は、
JsonUtility.FromJson<クラス>(Jsonデータ);
これで指定できるようです。

使い方が分かってきたので、最初に用意したメモ帳のテキストをロードしてみます。

ResourcesホルダーにTestとしてメモ帳を保存します。
Json⑥.jpg
JsonTest

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

[Serializable]
public class Player
{
public int hp;
public int attack;
public int defense;
}

public class JsonTest : MonoBehaviour
{
// Start is called before the first frame update
void Start()
{
string inputText = Resources.Load<TextAsset>("Test").ToString();
Player player = JsonUtility.FromJson<Player>(inputText);

Debug.Log(player.hp);
Debug.Log(player.attack);
Debug.Log(player.defense);
}
}

これでログを出すと
Json⑨.jpg
無事に読み込む事ができました。

この方法だとテキストデータを元にインスタンスも生成してくれます。

CSVは、単語毎にセパレートする必要があるのですが、
セパレートする必要が無いので、Jsonは便利ですね~ ヽ(´▽`)/~♪

しかし難点もあります。
スクリプト上でJsonデータを作成して更新する場合、

string inputText = "{\"hp\":100,\"attack\":20,\"defense\":7}";

データを作るのがややこしかったりします。

後は、配列の処理が複雑になります。
メモの穴さんで配列処理を記載されているので、
パターン3を流用させてもらいます。
JsonTest

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

[Serializable]
public class InputJson
{
public int[] aaa;
}

public class JsonTest : MonoBehaviour
{
// Start is called before the first frame update
void Start()
{
string inputString = "{\"aaa\": [1, 3, 5, 7, 9]}";
InputJson inputJson = JsonUtility.FromJson(inputString);
Debug.Log(inputJson.aaa[3]); // 7
}
}

実行するとConsoleに7が表示されます。
ここまでは良いのですが変数のように代入をしようとすると
JsonTest

// Start is called before the first frame update
void Start()
{
InputJson inputJson = new InputJson();
inputJson.aaa[0] = 1;

Debug.Log(inputJson.aaa[0]);
}

これで実行すると
Json⑩.jpg
ヌルですよ~ (T-T) グスッ

構造内の配列変数は初期化されないようです。

配列を使う場合は、初期化が必要になります。
クラスで初期化
JsonTest

[Serializable]
public class InputJson
{
public int[] aaa = new int[5];
}

もしくは、Start内で初期化

// Start is called before the first frame update
void Start()
{
InputJson inputJson = new InputJson()
{
aaa = new int[5]
};

inputJson.aaa[0] = 1;
Debug.Log(inputJson.aaa[0]);
}


Json⑪.jpg
これで使えるようになります(^.^; オホホホ

単純な配列なら使えるようですが、
多次元やジャグは、JsonUtilityが対応してないんだとか…

ただし、シンプルな変数の重なりは、対応しているとの事で
メモの穴さんが紹介されている方法なら階層を増やす事ができるようです。
パターン4がそれになります。

ただ、パターン4の初期化の方法が分からないので、
テキストデータからインスタンスを生成しないと使えないってのが、
目下の課題なんですよね。(- .-)ヾ ポリポリ

なにはともあれ、
うまく使えばCSVより保存・読込みが楽になるかもと思っています。

また、Jsonは暗号化する事ができるんだとか。
見られたくない情報などは、CSVよりJsonで作る方がよさそうですね。

体重管理アプリ作りも、これで進むといいのですが
(~ヘ~;)ウーン

Jsonについては以上となります。
それでは、この辺で(^^)/~~デハデハ

この記事へのコメント