teratail header banner
teratail header banner
質問するログイン新規登録

回答編集履歴

5

nullチェック時の動作を、一方がnullなら他方もnullにするよう変更

2017/10/27 23:49

投稿

Bongo
Bongo

スコア10816

answer CHANGED
@@ -103,18 +103,12 @@
103
103
 
104
104
  public void OnBeforeSerialize()
105
105
  {
106
- if (this.map != null)
107
- {
108
- this.serializableMap = this.map.Select(subList => new ListInt(subList)).ToList();
106
+ this.serializableMap = this.map == null ? null : this.map.Select(subList => new ListInt(subList)).ToList();
109
- }
110
107
  }
111
108
 
112
109
  public void OnAfterDeserialize()
113
110
  {
114
- if (this.serializableMap != null)
115
- {
116
- this.map = this.serializableMap.Select(listInt => listInt.data).ToList();
111
+ this.map = this.serializableMap == null ? null : this.serializableMap.Select(listInt => listInt.data).ToList();
117
- }
118
112
  }
119
113
  }
120
114
 

4

念のためnullのチェックを追加

2017/10/27 23:49

投稿

Bongo
Bongo

スコア10816

answer CHANGED
@@ -103,12 +103,18 @@
103
103
 
104
104
  public void OnBeforeSerialize()
105
105
  {
106
+ if (this.map != null)
107
+ {
106
- this.serializableMap = this.map.Select(subList => new ListInt(subList)).ToList();
108
+ this.serializableMap = this.map.Select(subList => new ListInt(subList)).ToList();
109
+ }
107
110
  }
108
111
 
109
112
  public void OnAfterDeserialize()
110
113
  {
114
+ if (this.serializableMap != null)
115
+ {
111
- this.map = this.serializableMap.Select(listInt => listInt.data).ToList();
116
+ this.map = this.serializableMap.Select(listInt => listInt.data).ToList();
117
+ }
112
118
  }
113
119
  }
114
120
 
@@ -119,7 +125,7 @@
119
125
 
120
126
  public ListInt(List<int> list)
121
127
  {
122
- this.data = list;
128
+ this.data = list ?? new List<int>();
123
129
  }
124
130
  }
125
131
  ```

3

別パターンを思いついたので追記

2017/10/27 23:43

投稿

Bongo
Bongo

スコア10816

answer CHANGED
@@ -72,4 +72,127 @@
72
72
  }
73
73
  }
74
74
  }
75
+ ```
76
+
77
+ [改善案を思いついたので追記]
78
+ [ISerializationCallbackReceiver](https://docs.unity3d.com/ScriptReference/ISerializationCallbackReceiver.html)を実装することでシリアライズ時の挙動をコントロールできるらしいので、今さらながら試してみました。
79
+
80
+ まず、MapManagerの方の基本戦略としては、シリアライズして保存しておくためのラッパークラス方式のデータ(コード中の```serializableMap```)と、他のスクリプトから使うときのためのList<List<int>>(コード中の```map```)に二重化しておいて、シリアライズ・デシリアライズ時に一方を他方に変換して同期することにしました。データ量が増えてしまいますが、一応それっぽく動くのではないでしょうか(同期部分は手抜きして毎回新しいオブジェクトを再生成していますが、既存のオブジェクトを再利用する形にすればいくらか効率的だと思います)。
81
+
82
+ ```C#
83
+ using System;
84
+ using System.Collections.Generic;
85
+ using System.Linq;
86
+ using UnityEngine;
87
+
88
+ public class MapManager : MonoBehaviour, ISerializationCallbackReceiver
89
+ {
90
+ [NonSerialized]
91
+ public List<List<int>> map;
92
+
93
+ [SerializeField, HideInInspector]
94
+ private List<ListInt> serializableMap;
95
+
96
+ void Start() {
97
+ Debug.Log(map);
98
+ }
99
+
100
+ public void SetMap(List<List<int>> newMap) {
101
+ map = newMap;
102
+ }
103
+
104
+ public void OnBeforeSerialize()
105
+ {
106
+ this.serializableMap = this.map.Select(subList => new ListInt(subList)).ToList();
107
+ }
108
+
109
+ public void OnAfterDeserialize()
110
+ {
111
+ this.map = this.serializableMap.Select(listInt => listInt.data).ToList();
112
+ }
113
+ }
114
+
115
+ [Serializable]
116
+ public class ListInt
117
+ {
118
+ public List<int> data;
119
+
120
+ public ListInt(List<int> list)
121
+ {
122
+ this.data = list;
123
+ }
124
+ }
125
+ ```
126
+
127
+ エディターウィンドウの方ですが、プレイモードにすると操作対象のMapManagerの参照が失われるので、代わりにMapManagerを持っているゲームオブジェクトへの参照を保持させることにしました。
128
+ それ以外は、2次元表示を試すためにIntFieldを入れてみたりしましたが、```map```へのアクセス自体はご質問者さんご提示のコードに倣っています。
129
+
130
+ ```C#
131
+ using System.Collections.Generic;
132
+ using UnityEditor;
133
+ using UnityEngine;
134
+
135
+ public class MapManagerEditorWindow : EditorWindow
136
+ {
137
+ private const float MinWidth = 16.0f;
138
+ private const float MaxWidth = 1024.0f;
139
+
140
+ private GameObject mapManagerObject;
141
+ private bool foldoutMapList;
142
+
143
+ [MenuItem("Window/Map Editor")]
144
+ static void Open() {
145
+ EditorWindow.GetWindow<MapManagerEditorWindow>("Map Editor");
146
+ }
147
+
148
+ void OnGUI() {
149
+ MapManager mapManager = EditorGUILayout.ObjectField("MapManagerコンポーネント を持ったオブジェクト", mapManagerObject == null ? null : mapManagerObject.GetComponent<MapManager>(), typeof(MapManager), true) as MapManager;
150
+ if (mapManager == null)
151
+ return;
152
+ mapManagerObject = mapManager.gameObject;
153
+ List<List<int>> map = mapManager.map;
154
+ int mapSize = 0;
155
+ Debug.Log(map);
156
+ if (map != null) {
157
+ mapSize = map.Count;
158
+ } else {
159
+ mapManager.map = new List<List<int>>();
160
+ map = mapManager.map;
161
+ }
162
+ foldoutMapList = EditorGUILayout.Foldout(foldoutMapList, "map");
163
+ if (this.foldoutMapList) {
164
+ mapSize = EditorGUILayout.IntField("Size", mapSize);
165
+ mapSize = Mathf.Clamp(mapSize, 1, 5);
166
+ EditorGUILayout.BeginHorizontal(GUI.skin.box);
167
+ {
168
+ for (int index = 0; index < mapSize; index++) {
169
+ EditorGUILayout.BeginVertical(GUI.skin.box);
170
+ {
171
+ if (index < map.Count) {
172
+ EditorGUILayout.LabelField(index.ToString(), GUILayout.MinWidth(MinWidth), GUILayout.MaxWidth(MaxWidth));
173
+ } else {
174
+ map.Add(new List<int>());
175
+ }
176
+ List<int> column = map[index];
177
+ for (int rowIndex = 0; rowIndex < mapSize; rowIndex++) {
178
+ if (rowIndex >= column.Count) {
179
+ column.Add(0);
180
+ }
181
+ column[rowIndex] = EditorGUILayout.IntField(column[rowIndex], GUILayout.MinWidth(MinWidth), GUILayout.MaxWidth(MaxWidth));
182
+ }
183
+ EditorGUILayout.EndVertical();
184
+ if (mapSize < column.Count) {
185
+ column.RemoveRange(mapSize, column.Count - mapSize);
186
+ }
187
+ }
188
+ }
189
+ EditorGUILayout.EndHorizontal();
190
+ if (mapSize < map.Count) {
191
+ map.RemoveRange(mapSize, map.Count - mapSize);
192
+ }
193
+ }
194
+ mapManager.SetMap(map);
195
+ }
196
+ }
197
+ }
75
198
  ```

2

コメントを受けて追記

2017/10/27 23:37

投稿

Bongo
Bongo

スコア10816

answer CHANGED
@@ -33,4 +33,43 @@
33
33
  ---
34
34
 
35
35
  [追記]
36
- [多次元のListをInspectorに表示する【Unity】 - (:3[kanのメモ帳]](http://kan-kikuchi.hatenablog.com/entry/ValueListList)で、同様にラッパー方式で多次元Listをインスペクタ上でも取り扱えるようにする方法が紹介されていました。こちらもご参考になりそうです。
36
+ [多次元のListをInspectorに表示する【Unity】 - (:3[kanのメモ帳]](http://kan-kikuchi.hatenablog.com/entry/ValueListList)で、同様にラッパー方式で多次元Listをインスペクタ上でも取り扱えるようにする方法が紹介されていました。こちらもご参考になりそうです。
37
+
38
+ [コメントを受けて追記]
39
+ いまいちしっくりいく回答を提示できず申し訳ないです...
40
+ 下記のような感じで[インデクサー](https://docs.microsoft.com/ja-jp/dotnet/csharp/programming-guide/indexers/)を追加してやれば多少はスクリプトの見た目がすっきりしますかね?あんまり大差はないですが...
41
+ ```C#
42
+ using System;
43
+ using System.Collections.Generic;
44
+ using UnityEngine;
45
+
46
+ public class List2DTest : MonoBehaviour
47
+ {
48
+ public List<ListInt> Test;
49
+
50
+ private void Start()
51
+ {
52
+ Debug.Log(this.Test[0][0]);
53
+ }
54
+ }
55
+
56
+ [Serializable]
57
+ public class ListInt
58
+ {
59
+ [SerializeField]
60
+ private List<int> storage = new List<int>();
61
+
62
+ public int this[int i]
63
+ {
64
+ get
65
+ {
66
+ return this.storage[i];
67
+ }
68
+
69
+ set
70
+ {
71
+ this.storage[i] = value;
72
+ }
73
+ }
74
+ }
75
+ ```

1

参考サイトを追加

2017/10/24 11:57

投稿

Bongo
Bongo

スコア10816

answer CHANGED
@@ -30,4 +30,7 @@
30
30
  > List<ListWrapper> nList =new List<ListWrapper>();
31
31
  > ```
32
32
 
33
- ---
33
+ ---
34
+
35
+ [追記]
36
+ [多次元のListをInspectorに表示する【Unity】 - (:3[kanのメモ帳]](http://kan-kikuchi.hatenablog.com/entry/ValueListList)で、同様にラッパー方式で多次元Listをインスペクタ上でも取り扱えるようにする方法が紹介されていました。こちらもご参考になりそうです。