質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.50%
C#

C#はマルチパラダイムプログラミング言語の1つで、命令形・宣言型・関数型・ジェネリック型・コンポーネント指向・オブジェクティブ指向のプログラミング開発すべてに対応しています。

Unity

Unityは、Unity Technologiesが開発・販売している、IDEを内蔵するゲームエンジンです。主にC#を用いたプログラミングでコンテンツの開発が可能です。

Q&A

解決済

1回答

4311閲覧

UnityでクラスまるごとJSONで保存する

momiji0210

総合スコア60

C#

C#はマルチパラダイムプログラミング言語の1つで、命令形・宣言型・関数型・ジェネリック型・コンポーネント指向・オブジェクティブ指向のプログラミング開発すべてに対応しています。

Unity

Unityは、Unity Technologiesが開発・販売している、IDEを内蔵するゲームエンジンです。主にC#を用いたプログラミングでコンテンツの開発が可能です。

0グッド

0クリップ

投稿2020/02/12 05:44

Unityでクラスをまるごと保存するサンプルを制作しております。

参考サイトを見ながら、保存まではできたのですが読み込み時にエラーが出てしまいます。
対処方法わかる方おりませんでしょうか。

保存先についてはStreamingAssetsフォルダにて行っており、Jsonの文字列の取得はできておりました。

参考サイト
https://kan-kikuchi.hatenablog.com/entry/Json_SaveData

ArgumentException: Cannot deserialize JSON to new instances of type 'DataManager.' UnityEngine.JsonUtility.FromJson (System.String json, System.Type type) (at C:/buildslave/unity/build/Modules/JSONSerialize/Public/JsonUtility.bindings.cs:48) UnityEngine.JsonUtility.FromJson[T] (System.String json) (at C:/buildslave/unity/build/Modules/JSONSerialize/Public/JsonUtility.bindings.cs:33) DataManager.LoadJson () (at Assets/Scripts/Others/DataManager.cs:323) DataManager.Awake () (at Assets/Scripts/Others/DataManager.cs:130) UnityEngine.Object:Instantiate(GameObject) AddManager:Awake() (at Assets/Scripts/Others/AddManager.cs:25)

C#

1using UnityEngine; 2using UnityEngine.SceneManagement; 3using System; 4using System.IO; 5using System.Collections; 6using System.Collections.Generic; 7using System.Runtime.Serialization.Formatters.Binary; 8 9 10// オリジナルクラス 11public class MyFunction { 12 13 // 使用例 14 /* 15 MyFunction myFunc = new MyFunction(); 16 string filePath = myFunc.GetPathFileNameStreamingAssets("category.json"); 17 string datastr = myFunc.ReadData(filePath); 18 */ 19 20 // Androidの場合、StreamingAssetのファイル名から文字列を返す 21 public string GetStringAndroidStreamingAssets(string fileName){ 22 23 // Androidの場合 24 #if UNITY_ANDROID 25 string path = "jar:file://" + Application.dataPath + "!/assets" + "/" + fileName; 26 WWW www = new WWW(path); 27 while (!www.isDone) {} 28 return www.text; 29 30 #else 31 Debug.Log("not android"); 32 return ""; 33 #endif 34 35 } 36 37 // StreamingAssetsのPathを取得 38 public string GetPathStreamingAssets(){ 39 40 string path = ""; 41 42 #if UNITY_EDITOR 43 path = Application.dataPath + "/StreamingAssets/"; 44 45 #elif UNITY_IOS 46 path = Application.dataPath + "/Raw/"; 47 48 #elif UNITY_ANDROID 49 path = "jar:file://" + Application.dataPath + "!/assets" + "/"; 50 WWW www = new WWW(path); 51 while (!www.isDone) {} 52 53 #else 54 path = Application.dataPath + "/StreamingAssets/"; 55 #endif 56 57 return path; 58 } 59 60 // StreamingAssetsのPathを取得してFileNameを付加する 61 public string GetPathFileNameStreamingAssets(string fileName){ 62 63 return (GetPathStreamingAssets() + fileName); 64 65 } 66 67 public string ReadData(string filePath) { 68 string str = ""; 69 StreamReader reader; 70 reader = new StreamReader (filePath); 71 str = reader.ReadToEnd (); 72 reader.Close (); 73 //Debug.Log(str); 74 return str; 75 } 76 77} 78 79/* ====================================================================== 80* 全シーンで使える変数。 81* [DataManager.Instance.変数名]で各種処理を呼び出すことが可能。 82*====================================================================== */ 83[Serializable] 84public class DataManager : MonoBehaviour { 85 86 private static DataManager instance = null; 87 88 public bool bgmFlag; 89 public int playerMax = 3; 90 public int playerLow = 1; 91 public int playerHigh = 2; 92 93 //SaveDataをJsonに変換したテキスト(リロード時に何度も読み込まなくていいように保持) 94 [SerializeField] 95 private static string _jsonText = ""; 96 97 void Start() { 98 } 99 100 // 初期化 101 public static DataManager Instance{ 102 get{ 103 if( null == instance ){ 104 instance = (DataManager)FindObjectOfType(typeof(DataManager)); 105 if( null == instance ){ 106 Debug.Log(" DataManager Instance Error "); 107 } 108 } 109 return instance; 110 } 111 112 } 113 114 void Awake(){ 115 116 GameObject[] obj = GameObject.FindGameObjectsWithTag("DataManager"); 117 118 if( 1 < obj.Length ){ 119 // 既に存在しているなら削除 120 Destroy( gameObject ); 121 }else{ 122 // シーン遷移では破棄させない 123 DontDestroyOnLoad( gameObject ); 124 LoadJson(); 125 //Load(); 126 } 127 128 } 129 130 // リストを保存 131 public static void SaveList<T>(string key , List<T> value){ 132 string serizlizedList = Serialize<List<T>> (value); 133 PlayerPrefs.SetString (key, serizlizedList); 134 } 135 136 // リストを読み込み 137 public static List<T> LoadList<T> (string key){ 138 //keyがある時だけ読み込む 139 if (PlayerPrefs.HasKey (key)) { 140 string serizlizedList = PlayerPrefs.GetString (key); 141 return Deserialize<List<T>> (serizlizedList); 142 } 143 144 return new List<T> (); 145 } 146 147 //引数のオブジェクトをシリアライズして返す 148 private static string Serialize<T> (T obj){ 149 BinaryFormatter binaryFormatter = new BinaryFormatter (); 150 MemoryStream memoryStream = new MemoryStream (); 151 binaryFormatter.Serialize (memoryStream , obj); 152 return Convert.ToBase64String (memoryStream .GetBuffer ()); 153 } 154 155 //引数のテキストを指定されたクラスにデシリアライズして返す 156 private static T Deserialize<T> (string str){ 157 BinaryFormatter binaryFormatter = new BinaryFormatter (); 158 MemoryStream memoryStream = new MemoryStream (Convert.FromBase64String (str)); 159 return (T)binaryFormatter.Deserialize (memoryStream); 160 } 161 162 //保存しているJsonを取得する 163 private static string GetJson(){ 164 //既にJsonを取得している場合はそれを返す。 165 if(!string.IsNullOrEmpty(_jsonText)){ 166 return _jsonText; 167 } 168 169 //Jsonを保存している場所のパスを取得。 170 string filePath = ""; 171 172 MyFunction myFunc = new MyFunction(); 173 filePath = myFunc.GetPathFileNameStreamingAssets("DataManager.json"); 174 175 //Jsonが存在するか調べてから取得し変換する。存在しなければ新たなクラスを作成し、それをJsonに変換する。 176 if(File.Exists(filePath)){ 177 _jsonText = File.ReadAllText (filePath); 178 } 179 else{ 180 _jsonText = JsonUtility.ToJson(new DataManager ()); 181 } 182 183 Debug.Log(_jsonText); 184 185 return _jsonText; 186 } 187 188 //データを読み込む。 189 private static void LoadJson(){ 190 instance = JsonUtility.FromJson<DataManager>(GetJson ()); 191 } 192 193 public void ReloadJson(){ 194 JsonUtility.FromJsonOverwrite (GetJson(), this); 195 } 196 197 public void SaveJson(){ 198 _jsonText = JsonUtility.ToJson(this, true); 199 File.WriteAllText (GetSaveFilePath(), _jsonText); 200 } 201 202 // 削除 203 public void DeleteJson(){ 204 _jsonText = JsonUtility.ToJson(new DataManager ()); 205 ReloadJson (); 206 } 207 208 //保存する場所のパスを取得。 209 private static string GetSaveFilePath(){ 210 211 string filePath = ""; 212 213 MyFunction myFunc = new MyFunction(); 214 filePath = myFunc.GetPathFileNameStreamingAssets("DataManager.json"); 215 Debug.Log(filePath); 216 /* 217 //確認しやすいようにエディタではAssetsと同じ階層に保存し、それ以外ではApplication.persistentDataPath以下に保存するように。 218 #if UNITY_EDITOR 219 filePath += ".json"; 220 #else 221 filePath = Application.persistentDataPath + "/" + filePath; 222 #endif 223*/ 224 225 return filePath; 226 } 227}

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

nanami12

2020/02/12 05:49

どこで、何というエラーが表示されるか 記載したほうが、回答を得られやすいとおもいます。
izmktr

2020/02/12 06:37

JSONの中身も欲しいです
退会済みユーザー

退会済みユーザー

2020/02/12 08:50

コードを丸投げしてデバッグしてくれと言ってるみたいですね。少しは自分で切り分けしてから質問するようにした方が解決が早いと思いますよ。エラーメッセージは「JSON 文字列を DataManager 型にデシリアライズできない」と言っているのですから、その部分だけ切り出して検証するとか。
momiji0210

2020/02/12 11:31

>>nanami12様 ご回答ありがとうございます。 Awake内のLoadJson();部分で、エラーが出ています。 エラーについては、一番上のコードの内容です。 >>izmktr様 StartなどでSaveJsonすると自動生成されます。 下記のような普通のJsonが出力されていました。 { "bgmFlag": false, "playerMax": 3, "playerLow": 1, "playerHigh": 2 } >>SurferOnWww様 ご指摘のような形になって申し訳ございません。 参考サイトを読み進めながら、試しているのですがこのエラーだけどうしてもとれず・・・。 エラー内容については何となくわかるのですが、なぜ書き出したものが不具合なのかわからず。 別のサンプルを試してJsonUtilityで読み込めることは確認しているため、このエラーの解消方法がわかりませんでした。
退会済みユーザー

退会済みユーザー

2020/02/13 01:00

上の私のコメントで、 > エラーメッセージは「JSON 文字列を DataManager 型にデシリアライズできない」と言っているのですから、その部分だけ切り出して検証するとか。 ・・・と書きましたけど、それをやってみませんか? それで原因が分かれば自己解決できるかもしれません。できない事情はないはずですが。
guest

回答1

0

ベストアンサー

・原因
MonoBehaviorを継承しているクラスでJsonUtility.FromJsonを行うとクラスの生成に失敗します。

・解決法
MonoBehaviorを継承しない作りに戻す。
MonoBehaviorを継承しない受け皿となるクラスを別に作ってそれを用いる。
JsonUtility.FromJsonOverwriteを使う。

上記どれかで良いです。

詳しくは下記サイトを見て下さい。
https://creive.me/archives/14311/

投稿2020/02/13 10:29

編集2020/02/13 10:58
Hawn

総合スコア1222

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

momiji0210

2020/02/14 01:29

コメントありがとうございます。 そうだったのですね・・・。こちら知らなかったため、非常に助かりました。 ha_wn様の言う通り、継承しない作り試したところ、うまく動作しました。 こちらありがとうございました。 後ほど、ベストアンサーとして設定させてくださいませ。 別件になってしまい恐縮なのですが、独自で作ったクラスに 直接Loadさせる方法はないでしょうか。 現在だと、下記のようなイメージでLoadさせています。 hoge.Instance.Item = hoge.Instance.Item.LoadJson(); // 現在のイメージ hoge.Instance.Item.LoadJson(); で読めるようにしたい この辺、おそらくstaticなどを使って実装するのかもしれないのですが、よくわかっておらず。。。 [Serializable] public class ITEM { public int id; public string name; public string description; public List<int> arrayInt; public List<string> array; private string _jsonText = ""; private string pathJson = "Item.json"; // ログ public void Log(){ Debug.Log("id => " + id); Debug.Log("name => " + name); Debug.Log("description => " + description); Debug.Log("arrayInt => " + string.Join(", ", arrayInt)); Debug.Log("array => " + string.Join(", ", array)); } public void LogJson(){ this.ReloadJson(); Debug.Log("json => " + _jsonText); } //保存する場所のパスを取得。 private string GetSaveFilePath(){ string filePath = ""; MyFunction myFunc = new MyFunction(); filePath = myFunc.GetPathFileNameStreamingAssets(pathJson); Debug.Log(filePath); return filePath; } //保存しているJsonを取得する private string GetJson(){ //既にJsonを取得している場合はそれを返す。 if(!string.IsNullOrEmpty(_jsonText)){ return _jsonText; } // //Jsonを保存している場所のパスを取得。 string filePath = ""; MyFunction myFunc = new MyFunction(); filePath = myFunc.GetPathFileNameStreamingAssets(pathJson); //Jsonが存在するか調べてから取得し変換する。存在しなければ新たなクラスを作成し、それをJsonに変換する。 if(File.Exists(filePath)){ _jsonText = File.ReadAllText (filePath); } else{ _jsonText = JsonUtility.ToJson(new ITEM ()); } Debug.Log(_jsonText); return _jsonText; } //データを読み込む。 public ITEM LoadJson(){ return JsonUtility.FromJson<ITEM>(GetJson ()); } //データを読み込む。 これをしたい public void LoadJson1(){ //this = JsonUtility.FromJson<ITEM>(GetJson ()); } // 再読み込み public void ReloadJson(){ JsonUtility.FromJsonOverwrite (GetJson(), this); } // 削除 public void DeleteJson(){ _jsonText = JsonUtility.ToJson(new ITEM ()); this.ReloadJson (); } // 保存 public void SaveJson(){ _jsonText = JsonUtility.ToJson(this, true); File.WriteAllText (GetSaveFilePath(), _jsonText); } }
Hawn

2020/02/14 02:26 編集

参考サイトの_instanceに代入する作りに戻せば良いと思います。 何か弊害があるのでしょうか?
BluOxy

2020/02/14 02:26

別件は別件として新たに質問を立て、この質問自体はBAを選択してクローズすべきと思います。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.50%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問