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

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

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

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

Unity3D

Unity3Dは、ゲームや対話式の3Dアプリケーション、トレーニングシュミレーション、そして医学的・建築学的な技術を可視化する、商業用の開発プラットフォームです。

Unity

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

Q&A

解決済

2回答

2799閲覧

【エディタ拡張】serializedObjectの中にあるserializedObjectの値を参照したい

sh0u

総合スコア17

C#

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

Unity3D

Unity3Dは、ゲームや対話式の3Dアプリケーション、トレーニングシュミレーション、そして医学的・建築学的な技術を可視化する、商業用の開発プラットフォームです。

Unity

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

0グッド

0クリップ

投稿2022/06/29 13:47

実現したいこと

大目標

Unityエディタ拡張を利用した、ゲーム変数・フラグを管理するためのデータベースの作成
↓デザインモックアップ
イメージ説明

小目標

親となるserializedObjectで参照(インスペクタ等で事前に設定)した別のserializedObject の中の値の参照
(serializedObjectの中にあるserializedObjectの値の参照)

試したこと

各要素の表示名(Label部分)、及び設定する値の型種類を設定するための「Database Config Data」を作成。
それを参照して「DatabaseData」で表示する値フィールドを決定しようとするが、NullReferenceExceptionエラーによりフィールドが生成されない

イメージ説明

発生している問題・エラーメッセージ

NullReferenceException: Object reference not set to an instance of an object sh0uRoom.GFE.DatabaseEditor.OnInspectorGUI () (at Assets/Scripts/GFE/DatabaseEditor.cs:64) UnityEditor.UIElements.InspectorElement+<>c__DisplayClass62_0.<CreateIMGUIInspectorFromEditor>b__0 () (at <7f1875e8b70e4492a480b76271c08a6f>:0) UnityEngine.GUIUtility:ProcessEvent(Int32, IntPtr, Boolean&)

該当のソースコード

【DatabaseData.cs】

csharp

1using System.Collections; 2using System.Collections.Generic; 3using UnityEditor; 4using UnityEngine; 5using static sh0uRoom.GFE.DatabaseConfigElement; 6 7namespace sh0uRoom.GFE 8{ 9 /// <summary> 10 /// DatabaseEditor内で設定したデータ 11 /// </summary> 12 [System.Serializable] 13 [CreateAssetMenu(menuName = "GFE/データベース")] 14 public class DatabaseData : ScriptableObject 15 { 16 public DatabaseConfigData databaseConfig; 17 public string databaseName; 18 public List<DatabaseElement> databaseElementList; 19 } 20 21 [System.Serializable] 22 public class DatabaseElement 23 { 24 public int databaseType; 25 26 public string stringValue; 27 public int intValue; 28 public bool boolValue; 29 } 30}

【DatabaseConfigData.cs】

csharp

1using System.Collections; 2using System.Collections.Generic; 3using UnityEditor; 4using UnityEngine; 5 6namespace sh0uRoom.GFE 7{ 8 /// <summary> 9 /// DatabaseConfigEditorで設定したデータ 10 /// </summary> 11 [System.Serializable] 12 [CreateAssetMenu(menuName = "GFE/データベース設定")] 13 public class DatabaseConfigData : ScriptableObject 14 { 15 public List<DatabaseConfigElement> databaseConfigElements; 16 } 17 18 [System.Serializable] 19 public class DatabaseConfigElement 20 { 21 //表示名 22 public string displayName; 23 24 public enum DatabaseElementType 25 { 26 String, 27 Value, 28 Flag 29 } 30 //型の種類(文字列、数、フラグ) 31 public DatabaseElementType dataType; 32 33 //ホバー時説明 34 public string hoverDescription; 35 } 36}

【DatabaseEditor.cs】

csharp

1using System.Collections; 2using System.Collections.Generic; 3using UnityEditor; 4using UnityEngine; 5using static sh0uRoom.GFE.DatabaseConfigElement; 6 7namespace sh0uRoom.GFE 8{ 9 /// <summary> 10 /// ゲーム内フラグ・変数を管理,設定するエディタ 11 /// </summary> 12 [CustomEditor(typeof(DatabaseData))] 13 public class DatabaseEditor : Editor 14 { 15 SerializedProperty databaseDataList; 16 SerializedProperty databaseConfigElementList; 17 18 List<bool> foldList; 19 20 private void OnEnable() 21 { 22 databaseDataList = serializedObject.FindProperty("databaseElementList"); 23 databaseConfigElementList = serializedObject.FindProperty("databaseConfig").FindPropertyRelative("databaseConfigElements"); 24 Debug.Log($"configlist = {databaseConfigElementList}"); 25 26 foldList = new List<bool> { false }; 27 foldList.Clear(); 28 for (int i = 0; i < databaseDataList.arraySize; i++) 29 { 30 foldList.Add(false); 31 } 32 } 33 34 public override void OnInspectorGUI() 35 { 36 serializedObject.Update(); 37 38 var databaseName = serializedObject.FindProperty("databaseName"); 39 databaseName.stringValue = EditorGUILayout.TextField("データベース名", databaseName.stringValue); 40 41 var databaseConfig = serializedObject.FindProperty("databaseConfig"); 42 databaseConfig.objectReferenceValue = EditorGUILayout.ObjectField("設定ファイル", databaseConfig.objectReferenceValue, typeof(DatabaseConfigData), false); 43 //Debug.Log($"databaseConfig = {databaseConfig.objectReferenceValue}"); 44 45 if (databaseConfig.objectReferenceValue) 46 { 47 //var databaseConfigElements = databaseConfig.FindPropertyRelative("databaseConfigElements"); 48 //リスト要素処理 49 for (int i = 0; i < databaseDataList.arraySize; i++) 50 { 51 if (databaseConfig.objectReferenceValue == null) return; 52 53 var databaseDataElement = databaseDataList.GetArrayElementAtIndex(i); 54 55 56 foldList[i] = EditorGUILayout.Foldout(foldList[i], $"Type.{i} 項目名"); 57 //foldoutが開かれている場合のみ表示 58 if (foldList[i]) 59 { 60 GUILayout.BeginVertical(GUI.skin.box); 61 { 62 if (GUILayout.Button("削除")) RemoveElement(i); 63 EditorGUILayout.HelpBox($"dataConfigIndex = {databaseConfig.GetArrayElementAtIndex(i)}", MessageType.Info); 64 //var databaseDatatype = databaseConfig.GetArrayElementAtIndex(i).FindPropertyRelative("dataType"); 65 //Debug.Log($"typename...:{databaseDatatype}"); 66 //OnElementGUI(databaseDatatype.enumValueIndex, i); 67 } 68 GUILayout.EndVertical(); 69 } 70 } 71 GUILayout.Space(10); 72 if (GUILayout.Button("項目を追加")) AddElement(); 73 GUILayout.Space(10); 74 } 75 else 76 { 77 EditorGUILayout.HelpBox("設定ファイルをアタッチしてください", MessageType.Error); 78 } 79 80 serializedObject.ApplyModifiedProperties(); 81 82 var creditStyle = new GUIStyle(EditorStyles.label); 83 creditStyle.richText = true; 84 creditStyle.alignment = TextAnchor.MiddleCenter; 85 GUILayout.Box("<size=10>(c)2022 sh0uRoom Green Fox Engine v0.01</size>", creditStyle, GUILayout.ExpandWidth(true)); 86 } 87 88 public void OnElementGUI(int type, int index) 89 { 90 switch ((DatabaseElementType)type) 91 { 92 case DatabaseElementType.Value: 93 EditorGUILayout.IntField("", 0); 94 break; 95 case DatabaseElementType.String: 96 EditorGUILayout.TextField("", ""); 97 break; 98 case DatabaseElementType.Flag: 99 EditorGUILayout.Toggle("", false); 100 break; 101 } 102 } 103 104 public void AddElement() 105 { 106 DebugLogger.Instance.DebugOutput($"データ{databaseDataList.arraySize}を作成します"); 107 foldList.Insert(databaseDataList.arraySize, false); 108 var newElementID = databaseDataList.arraySize; 109 databaseDataList.InsertArrayElementAtIndex(databaseDataList.arraySize); 110 InitializeElement(newElementID); 111 serializedObject.ApplyModifiedProperties(); 112 } 113 114 public void RemoveElement(int index) 115 { 116 DebugLogger.Instance.DebugOutput($"データ{databaseDataList.arraySize}を削除します"); 117 foldList.RemoveAt(index); 118 databaseDataList.DeleteArrayElementAtIndex(index); 119 serializedObject.ApplyModifiedProperties(); 120 } 121 122 public void InitializeElement(int index) 123 { 124 125 } 126 } 127}

補足情報(FW/ツールのバージョンなど)

Unity 2022.1.5f1
Visual Studio 2022

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

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

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

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

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

guest

回答2

0

ベストアンサー

databaseConfig上のデータにアクセスするとなると、たとえばOnInspectorGUIOnElementGUIを下記のようにしてみてはいかがでしょうか。

C#

1 public override void OnInspectorGUI() 2 { 3 serializedObject.Update(); 4 5 var databaseName = serializedObject.FindProperty("databaseName"); 6 databaseName.stringValue = EditorGUILayout.TextField("データベース名", databaseName.stringValue); 7 8 var databaseConfig = serializedObject.FindProperty("databaseConfig"); 9 databaseConfig.objectReferenceValue = EditorGUILayout.ObjectField("設定ファイル", databaseConfig.objectReferenceValue, typeof(DatabaseConfigData), false); 10 //Debug.Log($"databaseConfig = {databaseConfig.objectReferenceValue}"); 11 12 if (databaseConfig.objectReferenceValue) 13 { 14 // オブジェクトを参照するSerializedPropertyの場合、objectReferenceValueを 15 // 参照先の型にキャストすれば、参照先のデータにアクセスできるかと思います 16 var databaseConfigData = databaseConfig.objectReferenceValue as DatabaseConfigData; 17 18 //リスト要素処理 19 for (int i = 0; i < databaseDataList.arraySize; i++) 20 { 21 if (databaseConfig.objectReferenceValue == null) return; 22 23 var databaseDataElement = databaseDataList.GetArrayElementAtIndex(i); 24 25 foldList[i] = EditorGUILayout.Foldout(foldList[i], $"Type.{i} 項目名"); 26 //foldoutが開かれている場合のみ表示 27 if (foldList[i]) 28 { 29 GUILayout.BeginVertical(GUI.skin.box); 30 { 31 if (GUILayout.Button("削除")) RemoveElement(i); 32 else OnElementGUI(databaseDataElement, databaseConfigData.databaseConfigElements); 33 } 34 GUILayout.EndVertical(); 35 } 36 } 37 GUILayout.Space(10); 38 if (GUILayout.Button("項目を追加")) AddElement(); 39 GUILayout.Space(10); 40 } 41 else 42 { 43 EditorGUILayout.HelpBox("設定ファイルをアタッチしてください", MessageType.Error); 44 } 45 46 serializedObject.ApplyModifiedProperties(); 47 48 var creditStyle = new GUIStyle(EditorStyles.label); 49 creditStyle.richText = true; 50 creditStyle.alignment = TextAnchor.MiddleCenter; 51 GUILayout.Box("<size=10>(c)2022 sh0uRoom Green Fox Engine v0.01</size>", creditStyle, GUILayout.ExpandWidth(true)); 52 } 53 54 public void OnElementGUI(SerializedProperty databaseElement, IEnumerable<DatabaseConfigElement> configs) 55 { 56 foreach (var config in configs) 57 { 58 var elementLabel = new GUIContent(config.displayName, config.hoverDescription); 59 SerializedProperty elementValue; 60 switch (config.dataType) 61 { 62 case DatabaseElementType.Value: 63 elementValue = databaseElement.FindPropertyRelative("intValue"); 64 elementValue.intValue = EditorGUILayout.IntField(elementLabel, elementValue.intValue); 65 break; 66 case DatabaseElementType.String: 67 elementValue = databaseElement.FindPropertyRelative("stringValue"); 68 elementValue.stringValue = EditorGUILayout.TextField(elementLabel, elementValue.stringValue); 69 break; 70 case DatabaseElementType.Flag: 71 elementValue = databaseElement.FindPropertyRelative("boolValue"); 72 elementValue.boolValue = EditorGUILayout.Toggle(elementLabel, elementValue.boolValue); 73 break; 74 } 75 } 76 }

図

ご提示のモックアップ図からこんな感じだろうか...と想像して書き換えてみたのですが、とりあえず現状ではDatabaseConfigElementdataTypeValueならDatabaseElementintValueを、StringならstringValueを、FlagならboolValueを編集する、といった具合に決め打ちにしてしまいました。
ですが、もしかしてご質問者さんが想定なさっていたのはもっと動的な作りだったりしますかね?たとえば「後でDatabaseConfigDataアセットに『氷属性耐性、Flag型』を追加したとすると、DatabaseDataアセット上のデータにも自動的にbool型のデータが追加される」みたいな(もしそうでしたら、DatabaseDataの作りにも手を加える必要がありそうです)...

投稿2022/06/29 19:57

Bongo

総合スコア10811

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

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

0

元のコードを疑問点に答える回答じゃなくて申し訳ないんですけど
Odin InspectorというAssetを使えば、想定している表示は変数の宣言の前にアトリビュート書くだけ実現できます。
List内でいじった数値は、対象のScriptableObjectにそのまま反映されます。

イメージ説明
イメージ説明

で、このデータベースScriptableObjectはそのままエディター拡張に持ってくることができます。

イメージ説明

こんな感じでOdin使えば割りと簡単にやりたいことができるんじゃないかなぁと思います。
「新規ScreiptableObject作成ボタン」とか「押したら指定フォルダ内のScriptableObjectを全部取得してリストに足すボタン」をScriptableObject内に表示させることも可能です。
ただまあそうなるとUnityEditor使うので、そこら辺の処理とボタン類をまとめた「Editor拡張用ScriptableObject」的なものを作って、その中でデータベースScriptableObjectをさらに表示させるみたいな感じになってくるかな?
って感じでデフォルトのエディター拡張よりかは簡単にツールが作れると思います。

OdinはUnityが公認?的な感じで激推ししている、InspectorやEditor拡張を超パワーアップさせるAssetです。
https://unity.com/ja/products/odin
https://assetstore.unity.com/packages/tools/utilities/odin-inspector-and-serializer-89041

多分Unityがそのうち公式で買い上げるんじゃないかなってレベルで便利なAssetなのでオススメです。
回し者みたいですみません。

C#

1public class CharacterDatabase : ScriptableObject 2{ 3 public string settingData = ""; 4 public string categoryName = ""; 5 [InlineEditor] // ←これ書くと対象クラスの編集フィールドが出る 6 public List<Character> characterList = new List<Character>(); 7} 8 9public class Character : ScriptableObject 10{ 11 public string characterName = ""; 12 public int hp = 0; 13 public int fireResist = 0; 14}

C#

1public class ElementDatabase : ScriptableObject 2{ 3 [InlineEditor] 4 public List<Element> elementList = new List<Element>(); 5} 6 7public class Element : ScriptableObject 8{ 9 public enum Category 10 { 11 Int,String,Bool 12 } 13 14 public string elementName = ""; 15 [EnumToggleButtons] // ←Enumの水平トグル表示 16 public Category category = Category.Int; 17 [MultiLineProperty] // ←複数行表示 18 public string description = ""; 19}

C#

1public class DatabaseEditor : OdinMenuEditorWindow 2{ 3 [MenuItem("Tools/DatabaseEditor")] 4 private static void OpenWindow() 5 { 6 GetWindow<DatabaseEditor>().Show(); 7 } 8 9 //ツリー表示 10 protected override OdinMenuTree BuildMenuTree() 11 { 12 13 OdinMenuTree tree = new OdinMenuTree(); 14 tree.Selection.SupportsMultiSelect = false; 15 tree.AddAssetAtPath("ElementDatabase", いいかんじにScriptableObjectのパスを書く); 16 tree.AddAssetAtPath("CharacterDatabase", いいかんじにScriptableObjectのパスを書く); 17 return tree; 18 } 19}

投稿2022/06/30 00:52

編集2022/06/30 03:56
UnchFullburst

総合スコア669

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

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

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.37%

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

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

質問する

関連した質問