Serialize Nested Lists - Unity Answers によると、どうやらUnityは入れ子のListをシリアライズしてくれないようですね...
回答者の方は、下記のようにラッパークラスを作る方法を提案されていますが、この形に書き換えてみるとどうでしょうか?
absameen による 質問 · 2012年07月24日 17:29
Serialize Nested Lists
Will Unity not serialize nested lists such as:
List<List<int>> nList = new List<List<int>>();
How can we serialize this list?
CapnCromulent による 回答 · 2012年09月14日 04:16
Unfortunately, you'll have to write a wrapper class, like:
[System.Serializable]
public class ListWrapper
{
public List<int> myList;
}
then declare within your ScriptableObject
List<ListWrapper> nList =new List<ListWrapper>();
[追記]
多次元のListをInspectorに表示する【Unity】 - (:3[kanのメモ帳] で、同様にラッパー方式で多次元Listをインスペクタ上でも取り扱えるようにする方法が紹介されていました。こちらもご参考になりそうです。
[コメントを受けて追記]
いまいちしっくりいく回答を提示できず申し訳ないです...
下記のような感じでインデクサー を追加してやれば多少はスクリプトの見た目がすっきりしますかね?あんまり大差はないですが...
C#
1 using System ;
2 using System . Collections . Generic ;
3 using UnityEngine ;
4
5 public class List2DTest : MonoBehaviour
6 {
7 public List < ListInt > Test ;
8
9 private void Start ( )
10 {
11 Debug . Log ( this . Test [ 0 ] [ 0 ] ) ;
12 }
13 }
14
15 [ Serializable ]
16 public class ListInt
17 {
18 [ SerializeField ]
19 private List < int > storage = new List < int > ( ) ;
20
21 public int this [ int i ]
22 {
23 get
24 {
25 return this . storage [ i ] ;
26 }
27
28 set
29 {
30 this . storage [ i ] = value ;
31 }
32 }
33 }
[改善案を思いついたので追記]
ISerializationCallbackReceiver を実装することでシリアライズ時の挙動をコントロールできるらしいので、今さらながら試してみました。
まず、MapManagerの方の基本戦略としては、シリアライズして保存しておくためのラッパークラス方式のデータ(コード中のserializableMap
)と、他のスクリプトから使うときのためのList<List<int>>(コード中のmap
)に二重化しておいて、シリアライズ・デシリアライズ時に一方を他方に変換して同期することにしました。データ量が増えてしまいますが、一応それっぽく動くのではないでしょうか(同期部分は手抜きして毎回新しいオブジェクトを再生成していますが、既存のオブジェクトを再利用する形にすればいくらか効率的だと思います)。
C#
1 using System ;
2 using System . Collections . Generic ;
3 using System . Linq ;
4 using UnityEngine ;
5
6 public class MapManager : MonoBehaviour , ISerializationCallbackReceiver
7 {
8 [ NonSerialized ]
9 public List < List < int >> map ;
10
11 [ SerializeField , HideInInspector ]
12 private List < ListInt > serializableMap ;
13
14 void Start ( ) {
15 Debug . Log ( map ) ;
16 }
17
18 public void SetMap ( List < List < int >> newMap ) {
19 map = newMap ;
20 }
21
22 public void OnBeforeSerialize ( )
23 {
24 this . serializableMap = this . map == null ? null : this . map . Select ( subList = > new ListInt ( subList ) ) . ToList ( ) ;
25 }
26
27 public void OnAfterDeserialize ( )
28 {
29 this . map = this . serializableMap == null ? null : this . serializableMap . Select ( listInt = > listInt . data ) . ToList ( ) ;
30 }
31 }
32
33 [ Serializable ]
34 public class ListInt
35 {
36 public List < int > data ;
37
38 public ListInt ( List < int > list )
39 {
40 this . data = list ? ? new List < int > ( ) ;
41 }
42 }
エディターウィンドウの方ですが、プレイモードにすると操作対象のMapManagerの参照が失われるので、代わりにMapManagerを持っているゲームオブジェクトへの参照を保持させることにしました。
それ以外は、2次元表示を試すためにIntFieldを入れてみたりしましたが、map
へのアクセス自体はご質問者さんご提示のコードに倣っています。
C#
1 using System . Collections . Generic ;
2 using UnityEditor ;
3 using UnityEngine ;
4
5 public class MapManagerEditorWindow : EditorWindow
6 {
7 private const float MinWidth = 16.0f ;
8 private const float MaxWidth = 1024.0f ;
9
10 private GameObject mapManagerObject ;
11 private bool foldoutMapList ;
12
13 [ MenuItem ( "Window/Map Editor" ) ]
14 static void Open ( ) {
15 EditorWindow . GetWindow < MapManagerEditorWindow > ( "Map Editor" ) ;
16 }
17
18 void OnGUI ( ) {
19 MapManager mapManager = EditorGUILayout . ObjectField ( "MapManagerコンポーネント を持ったオブジェクト" , mapManagerObject == null ? null : mapManagerObject . GetComponent < MapManager > ( ) , typeof ( MapManager ) , true ) as MapManager ;
20 if ( mapManager == null )
21 return ;
22 mapManagerObject = mapManager . gameObject ;
23 List < List < int >> map = mapManager . map ;
24 int mapSize = 0 ;
25 Debug . Log ( map ) ;
26 if ( map != null ) {
27 mapSize = map . Count ;
28 } else {
29 mapManager . map = new List < List < int >> ( ) ;
30 map = mapManager . map ;
31 }
32 foldoutMapList = EditorGUILayout . Foldout ( foldoutMapList , "map" ) ;
33 if ( this . foldoutMapList ) {
34 mapSize = EditorGUILayout . IntField ( "Size" , mapSize ) ;
35 mapSize = Mathf . Clamp ( mapSize , 1 , 5 ) ;
36 EditorGUILayout . BeginHorizontal ( GUI . skin . box ) ;
37 {
38 for ( int index = 0 ; index < mapSize ; index ++ ) {
39 EditorGUILayout . BeginVertical ( GUI . skin . box ) ;
40 {
41 if ( index < map . Count ) {
42 EditorGUILayout . LabelField ( index . ToString ( ) , GUILayout . MinWidth ( MinWidth ) , GUILayout . MaxWidth ( MaxWidth ) ) ;
43 } else {
44 map . Add ( new List < int > ( ) ) ;
45 }
46 List < int > column = map [ index ] ;
47 for ( int rowIndex = 0 ; rowIndex < mapSize ; rowIndex ++ ) {
48 if ( rowIndex >= column . Count ) {
49 column . Add ( 0 ) ;
50 }
51 column [ rowIndex ] = EditorGUILayout . IntField ( column [ rowIndex ] , GUILayout . MinWidth ( MinWidth ) , GUILayout . MaxWidth ( MaxWidth ) ) ;
52 }
53 EditorGUILayout . EndVertical ( ) ;
54 if ( mapSize < column . Count ) {
55 column . RemoveRange ( mapSize , column . Count - mapSize ) ;
56 }
57 }
58 }
59 EditorGUILayout . EndHorizontal ( ) ;
60 if ( mapSize < map . Count ) {
61 map . RemoveRange ( mapSize , map . Count - mapSize ) ;
62 }
63 }
64 mapManager . SetMap ( map ) ;
65 }
66 }
67 }
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
2017/10/24 10:37