回答編集履歴

5

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

2017/10/27 23:49

投稿

Bongo
Bongo

スコア10807

test CHANGED
@@ -208,27 +208,183 @@
208
208
 
209
209
  {
210
210
 
211
- if (this.map != null)
212
-
213
- {
214
-
215
- this.serializableMap = this.map.Select(subList => new ListInt(subList)).ToList();
211
+ this.serializableMap = this.map == null ? null : this.map.Select(subList => new ListInt(subList)).ToList();
212
+
213
+ }
214
+
215
+
216
+
217
+ public void OnAfterDeserialize()
218
+
219
+ {
220
+
221
+ this.map = this.serializableMap == null ? null : this.serializableMap.Select(listInt => listInt.data).ToList();
222
+
223
+ }
224
+
225
+ }
226
+
227
+
228
+
229
+ [Serializable]
230
+
231
+ public class ListInt
232
+
233
+ {
234
+
235
+ public List<int> data;
236
+
237
+
238
+
239
+ public ListInt(List<int> list)
240
+
241
+ {
242
+
243
+ this.data = list ?? new List<int>();
244
+
245
+ }
246
+
247
+ }
248
+
249
+ ```
250
+
251
+
252
+
253
+ エディターウィンドウの方ですが、プレイモードにすると操作対象のMapManagerの参照が失われるので、代わりにMapManagerを持っているゲームオブジェクトへの参照を保持させることにしました。
254
+
255
+ それ以外は、2次元表示を試すためにIntFieldを入れてみたりしましたが、```map```へのアクセス自体はご質問者さんご提示のコードに倣っています。
256
+
257
+
258
+
259
+ ```C#
260
+
261
+ using System.Collections.Generic;
262
+
263
+ using UnityEditor;
264
+
265
+ using UnityEngine;
266
+
267
+
268
+
269
+ public class MapManagerEditorWindow : EditorWindow
270
+
271
+ {
272
+
273
+ private const float MinWidth = 16.0f;
274
+
275
+ private const float MaxWidth = 1024.0f;
276
+
277
+
278
+
279
+ private GameObject mapManagerObject;
280
+
281
+ private bool foldoutMapList;
282
+
283
+
284
+
285
+ [MenuItem("Window/Map Editor")]
286
+
287
+ static void Open() {
288
+
289
+ EditorWindow.GetWindow<MapManagerEditorWindow>("Map Editor");
290
+
291
+ }
292
+
293
+
294
+
295
+ void OnGUI() {
296
+
297
+ MapManager mapManager = EditorGUILayout.ObjectField("MapManagerコンポーネント を持ったオブジェクト", mapManagerObject == null ? null : mapManagerObject.GetComponent<MapManager>(), typeof(MapManager), true) as MapManager;
298
+
299
+ if (mapManager == null)
300
+
301
+ return;
302
+
303
+ mapManagerObject = mapManager.gameObject;
304
+
305
+ List<List<int>> map = mapManager.map;
306
+
307
+ int mapSize = 0;
308
+
309
+ Debug.Log(map);
310
+
311
+ if (map != null) {
312
+
313
+ mapSize = map.Count;
314
+
315
+ } else {
316
+
317
+ mapManager.map = new List<List<int>>();
318
+
319
+ map = mapManager.map;
216
320
 
217
321
  }
218
322
 
323
+ foldoutMapList = EditorGUILayout.Foldout(foldoutMapList, "map");
324
+
325
+ if (this.foldoutMapList) {
326
+
327
+ mapSize = EditorGUILayout.IntField("Size", mapSize);
328
+
329
+ mapSize = Mathf.Clamp(mapSize, 1, 5);
330
+
331
+ EditorGUILayout.BeginHorizontal(GUI.skin.box);
332
+
333
+ {
334
+
335
+ for (int index = 0; index < mapSize; index++) {
336
+
337
+ EditorGUILayout.BeginVertical(GUI.skin.box);
338
+
339
+ {
340
+
341
+ if (index < map.Count) {
342
+
343
+ EditorGUILayout.LabelField(index.ToString(), GUILayout.MinWidth(MinWidth), GUILayout.MaxWidth(MaxWidth));
344
+
345
+ } else {
346
+
347
+ map.Add(new List<int>());
348
+
219
- }
349
+ }
350
+
220
-
351
+ List<int> column = map[index];
352
+
221
-
353
+ for (int rowIndex = 0; rowIndex < mapSize; rowIndex++) {
354
+
222
-
355
+ if (rowIndex >= column.Count) {
356
+
357
+ column.Add(0);
358
+
359
+ }
360
+
361
+ column[rowIndex] = EditorGUILayout.IntField(column[rowIndex], GUILayout.MinWidth(MinWidth), GUILayout.MaxWidth(MaxWidth));
362
+
363
+ }
364
+
223
- public void OnAfterDeserialize()
365
+ EditorGUILayout.EndVertical();
366
+
224
-
367
+ if (mapSize < column.Count) {
368
+
369
+ column.RemoveRange(mapSize, column.Count - mapSize);
370
+
225
- {
371
+ }
372
+
226
-
373
+ }
374
+
375
+ }
376
+
377
+ EditorGUILayout.EndHorizontal();
378
+
227
- if (this.serializableMap != null)
379
+ if (mapSize < map.Count) {
228
-
229
- {
380
+
230
-
231
- this.map = this.serializableMap.Select(listInt => listInt.data).ToList();
381
+ map.RemoveRange(mapSize, map.Count - mapSize);
382
+
383
+ }
384
+
385
+ }
386
+
387
+ mapManager.SetMap(map);
232
388
 
233
389
  }
234
390
 
@@ -236,172 +392,4 @@
236
392
 
237
393
  }
238
394
 
239
-
240
-
241
- [Serializable]
242
-
243
- public class ListInt
244
-
245
- {
246
-
247
- public List<int> data;
248
-
249
-
250
-
251
- public ListInt(List<int> list)
252
-
253
- {
254
-
255
- this.data = list ?? new List<int>();
256
-
257
- }
258
-
259
- }
260
-
261
395
  ```
262
-
263
-
264
-
265
- エディターウィンドウの方ですが、プレイモードにすると操作対象のMapManagerの参照が失われるので、代わりにMapManagerを持っているゲームオブジェクトへの参照を保持させることにしました。
266
-
267
- それ以外は、2次元表示を試すためにIntFieldを入れてみたりしましたが、```map```へのアクセス自体はご質問者さんご提示のコードに倣っています。
268
-
269
-
270
-
271
- ```C#
272
-
273
- using System.Collections.Generic;
274
-
275
- using UnityEditor;
276
-
277
- using UnityEngine;
278
-
279
-
280
-
281
- public class MapManagerEditorWindow : EditorWindow
282
-
283
- {
284
-
285
- private const float MinWidth = 16.0f;
286
-
287
- private const float MaxWidth = 1024.0f;
288
-
289
-
290
-
291
- private GameObject mapManagerObject;
292
-
293
- private bool foldoutMapList;
294
-
295
-
296
-
297
- [MenuItem("Window/Map Editor")]
298
-
299
- static void Open() {
300
-
301
- EditorWindow.GetWindow<MapManagerEditorWindow>("Map Editor");
302
-
303
- }
304
-
305
-
306
-
307
- void OnGUI() {
308
-
309
- MapManager mapManager = EditorGUILayout.ObjectField("MapManagerコンポーネント を持ったオブジェクト", mapManagerObject == null ? null : mapManagerObject.GetComponent<MapManager>(), typeof(MapManager), true) as MapManager;
310
-
311
- if (mapManager == null)
312
-
313
- return;
314
-
315
- mapManagerObject = mapManager.gameObject;
316
-
317
- List<List<int>> map = mapManager.map;
318
-
319
- int mapSize = 0;
320
-
321
- Debug.Log(map);
322
-
323
- if (map != null) {
324
-
325
- mapSize = map.Count;
326
-
327
- } else {
328
-
329
- mapManager.map = new List<List<int>>();
330
-
331
- map = mapManager.map;
332
-
333
- }
334
-
335
- foldoutMapList = EditorGUILayout.Foldout(foldoutMapList, "map");
336
-
337
- if (this.foldoutMapList) {
338
-
339
- mapSize = EditorGUILayout.IntField("Size", mapSize);
340
-
341
- mapSize = Mathf.Clamp(mapSize, 1, 5);
342
-
343
- EditorGUILayout.BeginHorizontal(GUI.skin.box);
344
-
345
- {
346
-
347
- for (int index = 0; index < mapSize; index++) {
348
-
349
- EditorGUILayout.BeginVertical(GUI.skin.box);
350
-
351
- {
352
-
353
- if (index < map.Count) {
354
-
355
- EditorGUILayout.LabelField(index.ToString(), GUILayout.MinWidth(MinWidth), GUILayout.MaxWidth(MaxWidth));
356
-
357
- } else {
358
-
359
- map.Add(new List<int>());
360
-
361
- }
362
-
363
- List<int> column = map[index];
364
-
365
- for (int rowIndex = 0; rowIndex < mapSize; rowIndex++) {
366
-
367
- if (rowIndex >= column.Count) {
368
-
369
- column.Add(0);
370
-
371
- }
372
-
373
- column[rowIndex] = EditorGUILayout.IntField(column[rowIndex], GUILayout.MinWidth(MinWidth), GUILayout.MaxWidth(MaxWidth));
374
-
375
- }
376
-
377
- EditorGUILayout.EndVertical();
378
-
379
- if (mapSize < column.Count) {
380
-
381
- column.RemoveRange(mapSize, column.Count - mapSize);
382
-
383
- }
384
-
385
- }
386
-
387
- }
388
-
389
- EditorGUILayout.EndHorizontal();
390
-
391
- if (mapSize < map.Count) {
392
-
393
- map.RemoveRange(mapSize, map.Count - mapSize);
394
-
395
- }
396
-
397
- }
398
-
399
- mapManager.SetMap(map);
400
-
401
- }
402
-
403
- }
404
-
405
- }
406
-
407
- ```

4

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

2017/10/27 23:49

投稿

Bongo
Bongo

スコア10807

test CHANGED
@@ -208,7 +208,13 @@
208
208
 
209
209
  {
210
210
 
211
+ if (this.map != null)
212
+
213
+ {
214
+
211
- this.serializableMap = this.map.Select(subList => new ListInt(subList)).ToList();
215
+ this.serializableMap = this.map.Select(subList => new ListInt(subList)).ToList();
216
+
217
+ }
212
218
 
213
219
  }
214
220
 
@@ -218,7 +224,13 @@
218
224
 
219
225
  {
220
226
 
227
+ if (this.serializableMap != null)
228
+
229
+ {
230
+
221
- this.map = this.serializableMap.Select(listInt => listInt.data).ToList();
231
+ this.map = this.serializableMap.Select(listInt => listInt.data).ToList();
232
+
233
+ }
222
234
 
223
235
  }
224
236
 
@@ -240,7 +252,7 @@
240
252
 
241
253
  {
242
254
 
243
- this.data = list;
255
+ this.data = list ?? new List<int>();
244
256
 
245
257
  }
246
258
 

3

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

2017/10/27 23:43

投稿

Bongo
Bongo

スコア10807

test CHANGED
@@ -147,3 +147,249 @@
147
147
  }
148
148
 
149
149
  ```
150
+
151
+
152
+
153
+ [改善案を思いついたので追記]
154
+
155
+ [ISerializationCallbackReceiver](https://docs.unity3d.com/ScriptReference/ISerializationCallbackReceiver.html)を実装することでシリアライズ時の挙動をコントロールできるらしいので、今さらながら試してみました。
156
+
157
+
158
+
159
+ まず、MapManagerの方の基本戦略としては、シリアライズして保存しておくためのラッパークラス方式のデータ(コード中の```serializableMap```)と、他のスクリプトから使うときのためのList<List<int>>(コード中の```map```)に二重化しておいて、シリアライズ・デシリアライズ時に一方を他方に変換して同期することにしました。データ量が増えてしまいますが、一応それっぽく動くのではないでしょうか(同期部分は手抜きして毎回新しいオブジェクトを再生成していますが、既存のオブジェクトを再利用する形にすればいくらか効率的だと思います)。
160
+
161
+
162
+
163
+ ```C#
164
+
165
+ using System;
166
+
167
+ using System.Collections.Generic;
168
+
169
+ using System.Linq;
170
+
171
+ using UnityEngine;
172
+
173
+
174
+
175
+ public class MapManager : MonoBehaviour, ISerializationCallbackReceiver
176
+
177
+ {
178
+
179
+ [NonSerialized]
180
+
181
+ public List<List<int>> map;
182
+
183
+
184
+
185
+ [SerializeField, HideInInspector]
186
+
187
+ private List<ListInt> serializableMap;
188
+
189
+
190
+
191
+ void Start() {
192
+
193
+ Debug.Log(map);
194
+
195
+ }
196
+
197
+
198
+
199
+ public void SetMap(List<List<int>> newMap) {
200
+
201
+ map = newMap;
202
+
203
+ }
204
+
205
+
206
+
207
+ public void OnBeforeSerialize()
208
+
209
+ {
210
+
211
+ this.serializableMap = this.map.Select(subList => new ListInt(subList)).ToList();
212
+
213
+ }
214
+
215
+
216
+
217
+ public void OnAfterDeserialize()
218
+
219
+ {
220
+
221
+ this.map = this.serializableMap.Select(listInt => listInt.data).ToList();
222
+
223
+ }
224
+
225
+ }
226
+
227
+
228
+
229
+ [Serializable]
230
+
231
+ public class ListInt
232
+
233
+ {
234
+
235
+ public List<int> data;
236
+
237
+
238
+
239
+ public ListInt(List<int> list)
240
+
241
+ {
242
+
243
+ this.data = list;
244
+
245
+ }
246
+
247
+ }
248
+
249
+ ```
250
+
251
+
252
+
253
+ エディターウィンドウの方ですが、プレイモードにすると操作対象のMapManagerの参照が失われるので、代わりにMapManagerを持っているゲームオブジェクトへの参照を保持させることにしました。
254
+
255
+ それ以外は、2次元表示を試すためにIntFieldを入れてみたりしましたが、```map```へのアクセス自体はご質問者さんご提示のコードに倣っています。
256
+
257
+
258
+
259
+ ```C#
260
+
261
+ using System.Collections.Generic;
262
+
263
+ using UnityEditor;
264
+
265
+ using UnityEngine;
266
+
267
+
268
+
269
+ public class MapManagerEditorWindow : EditorWindow
270
+
271
+ {
272
+
273
+ private const float MinWidth = 16.0f;
274
+
275
+ private const float MaxWidth = 1024.0f;
276
+
277
+
278
+
279
+ private GameObject mapManagerObject;
280
+
281
+ private bool foldoutMapList;
282
+
283
+
284
+
285
+ [MenuItem("Window/Map Editor")]
286
+
287
+ static void Open() {
288
+
289
+ EditorWindow.GetWindow<MapManagerEditorWindow>("Map Editor");
290
+
291
+ }
292
+
293
+
294
+
295
+ void OnGUI() {
296
+
297
+ MapManager mapManager = EditorGUILayout.ObjectField("MapManagerコンポーネント を持ったオブジェクト", mapManagerObject == null ? null : mapManagerObject.GetComponent<MapManager>(), typeof(MapManager), true) as MapManager;
298
+
299
+ if (mapManager == null)
300
+
301
+ return;
302
+
303
+ mapManagerObject = mapManager.gameObject;
304
+
305
+ List<List<int>> map = mapManager.map;
306
+
307
+ int mapSize = 0;
308
+
309
+ Debug.Log(map);
310
+
311
+ if (map != null) {
312
+
313
+ mapSize = map.Count;
314
+
315
+ } else {
316
+
317
+ mapManager.map = new List<List<int>>();
318
+
319
+ map = mapManager.map;
320
+
321
+ }
322
+
323
+ foldoutMapList = EditorGUILayout.Foldout(foldoutMapList, "map");
324
+
325
+ if (this.foldoutMapList) {
326
+
327
+ mapSize = EditorGUILayout.IntField("Size", mapSize);
328
+
329
+ mapSize = Mathf.Clamp(mapSize, 1, 5);
330
+
331
+ EditorGUILayout.BeginHorizontal(GUI.skin.box);
332
+
333
+ {
334
+
335
+ for (int index = 0; index < mapSize; index++) {
336
+
337
+ EditorGUILayout.BeginVertical(GUI.skin.box);
338
+
339
+ {
340
+
341
+ if (index < map.Count) {
342
+
343
+ EditorGUILayout.LabelField(index.ToString(), GUILayout.MinWidth(MinWidth), GUILayout.MaxWidth(MaxWidth));
344
+
345
+ } else {
346
+
347
+ map.Add(new List<int>());
348
+
349
+ }
350
+
351
+ List<int> column = map[index];
352
+
353
+ for (int rowIndex = 0; rowIndex < mapSize; rowIndex++) {
354
+
355
+ if (rowIndex >= column.Count) {
356
+
357
+ column.Add(0);
358
+
359
+ }
360
+
361
+ column[rowIndex] = EditorGUILayout.IntField(column[rowIndex], GUILayout.MinWidth(MinWidth), GUILayout.MaxWidth(MaxWidth));
362
+
363
+ }
364
+
365
+ EditorGUILayout.EndVertical();
366
+
367
+ if (mapSize < column.Count) {
368
+
369
+ column.RemoveRange(mapSize, column.Count - mapSize);
370
+
371
+ }
372
+
373
+ }
374
+
375
+ }
376
+
377
+ EditorGUILayout.EndHorizontal();
378
+
379
+ if (mapSize < map.Count) {
380
+
381
+ map.RemoveRange(mapSize, map.Count - mapSize);
382
+
383
+ }
384
+
385
+ }
386
+
387
+ mapManager.SetMap(map);
388
+
389
+ }
390
+
391
+ }
392
+
393
+ }
394
+
395
+ ```

2

コメントを受けて追記

2017/10/27 23:37

投稿

Bongo
Bongo

スコア10807

test CHANGED
@@ -69,3 +69,81 @@
69
69
  [追記]
70
70
 
71
71
  [多次元のListをInspectorに表示する【Unity】 - (:3[kanのメモ帳]](http://kan-kikuchi.hatenablog.com/entry/ValueListList)で、同様にラッパー方式で多次元Listをインスペクタ上でも取り扱えるようにする方法が紹介されていました。こちらもご参考になりそうです。
72
+
73
+
74
+
75
+ [コメントを受けて追記]
76
+
77
+ いまいちしっくりいく回答を提示できず申し訳ないです...
78
+
79
+ 下記のような感じで[インデクサー](https://docs.microsoft.com/ja-jp/dotnet/csharp/programming-guide/indexers/)を追加してやれば多少はスクリプトの見た目がすっきりしますかね?あんまり大差はないですが...
80
+
81
+ ```C#
82
+
83
+ using System;
84
+
85
+ using System.Collections.Generic;
86
+
87
+ using UnityEngine;
88
+
89
+
90
+
91
+ public class List2DTest : MonoBehaviour
92
+
93
+ {
94
+
95
+ public List<ListInt> Test;
96
+
97
+
98
+
99
+ private void Start()
100
+
101
+ {
102
+
103
+ Debug.Log(this.Test[0][0]);
104
+
105
+ }
106
+
107
+ }
108
+
109
+
110
+
111
+ [Serializable]
112
+
113
+ public class ListInt
114
+
115
+ {
116
+
117
+ [SerializeField]
118
+
119
+ private List<int> storage = new List<int>();
120
+
121
+
122
+
123
+ public int this[int i]
124
+
125
+ {
126
+
127
+ get
128
+
129
+ {
130
+
131
+ return this.storage[i];
132
+
133
+ }
134
+
135
+
136
+
137
+ set
138
+
139
+ {
140
+
141
+ this.storage[i] = value;
142
+
143
+ }
144
+
145
+ }
146
+
147
+ }
148
+
149
+ ```

1

参考サイトを追加

2017/10/24 11:57

投稿

Bongo
Bongo

スコア10807

test CHANGED
@@ -63,3 +63,9 @@
63
63
 
64
64
 
65
65
  ---
66
+
67
+
68
+
69
+ [追記]
70
+
71
+ [多次元のListをInspectorに表示する【Unity】 - (:3[kanのメモ帳]](http://kan-kikuchi.hatenablog.com/entry/ValueListList)で、同様にラッパー方式で多次元Listをインスペクタ上でも取り扱えるようにする方法が紹介されていました。こちらもご参考になりそうです。