- Home /
Cannot get a class to show up correctly in a custom inspector
Hi,
I am working on a story game, and am creating a ScriptableObject script that defines the order in which functions will occur for each day (like a scene) in my game. I'm using an instance of a class inside the class that the custom inspector is made for (the declaration of this class is in another script). When I try to create the PropertyField, all I get is this. Notice how dialogue only appears as a label that says "dialogue." What I want to appear is this: I have no idea why, but when I put a SerializedProperty that represents an instance of a class into a property field, all I get is the label, not even a dropdown arrow. No error is thrown. Below is the code for the scriptable object.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System.Reflection;
using System.Linq;
//A scriptable object used to store data in a scene. DOES NOT STORE DAY'S FUNCTIONS (Inside MinorStoryManager)
[CreateAssetMenu(fileName = "New Day", menuName = "Day")]
public class Day : ScriptableObject
{
//The GameObject scene to be instantiated
[Tooltip("The GameObject scene to be instantiated")]
public GameObject scene;
//Which day it is in the journey
[Tooltip("Which day it is in the journey")]
public int DayValue;
//Whether Captain Nova is player-controlled during the day or not
[Tooltip("Whether Captain Nova is player-controlled during the day or not")]
public bool dynamic;
//The initial delay between when the day starts and the first function is called
[Tooltip("The initial delay between when the day starts and the first function is called")]
public float initialDelay;
//Data for the functions run in the scene
[System.Serializable]
public class FuncData
{
//Is this dialogue?
[HideInInspector]
public bool isDialogue = false;
//The child objects of the scene (by name)
[HideInInspector]
public string[] childrenNames;
//Child selected from dropdown
[HideInInspector]
public int childIndex = 0;
//The methods of the children (by name)
[HideInInspector]
public string[] methodNames;
//Method selected from dropdown
[HideInInspector]
public int methodIndex = 0;
//Actual child selected
[HideInInspector]
public GameObject functionGO;
//Dialogue
[HideInInspector]
public Dialogue dialogue;
//Actual method selected
public string method;
//Delay between this function and the next one
[HideInInspector]
public float delay = 0.0f;
}
[HideInInspector]
public FuncData[] fDatas = new FuncData[0];
public void OnValidate()
{
if (scene != null)
{
for (int i = 0; i < fDatas.Length; i++)
{
//When OnValidate is called, searches for all children and adds them to a list
fDatas[i].childrenNames = new string[scene.transform.childCount];
for (int j = 0; j < scene.transform.childCount; j++)
{
fDatas[i].childrenNames[j] = scene.transform.GetChild(j).name;
}
//When OnValidate is called, searches for all methods of the aforementioned child and adds them to a list
//flags for functions
var flags = BindingFlags.Instance | BindingFlags.Public | BindingFlags.ExactBinding | BindingFlags.DeclaredOnly;
//getComponents
var components = scene.transform.GetChild(fDatas[i].childIndex).GetComponents(typeof(MonoBehaviour));
List<MethodInfo> methodList = new List<MethodInfo>();
foreach (var component in components)
{
var methods = component.GetType().GetMethods(flags);
foreach (var method in methods)
{
methodList.Add(method);
}
}
fDatas[i].methodNames = new string[methodList.Count];
//Converts methodList to methodArray
MethodInfo[] methodArray = methodList.ToArray();
//Each method gives its name to the string array
for (int j = 0; j < methodArray.Length; j++)
{
fDatas[i].methodNames[j] = methodArray[j].Name;
}
//Sets the Function GameObject to selected
fDatas[i].functionGO = scene.transform.GetChild(fDatas[i].childIndex).gameObject;
//Sets the Function Method to method selected (if there are methods)
if (fDatas[i].methodNames.Length > 0)
{
fDatas[i].method = fDatas[i].methodNames[fDatas[i].methodIndex];
}
else
{
Debug.LogWarning(fDatas[i].functionGO.name + " doesn't have methods!");
}
}
} else {
//Logs an error if day has no scene
Debug.LogError("Day " + scene.name + " has no scene attached!");
}
}
}
Dialogue Script
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
/*
This dialogue script contains the system serializable values that is called to be entered in the dialogue trigger
*/
[System.Serializable]
public class Dialogue
{
//Name of character speaking
[SerializeField]
public string name;
//Their sentence
//[TextArea(2, 10)]
[SerializeField]
public string[] sentences;
//The sprite associated with the speaker
[SerializeField]
public Sprite dialogueSprite;
}
Editor Script
using UnityEditor;
using UnityEngine;
using System.Collections.Generic;
[CustomEditor(typeof(Day))]
public class DayEditor : Editor
{
public override void OnInspectorGUI()
{
//Header for day data
EditorGUILayout.LabelField("Day Data", EditorStyles.boldLabel);
//Draws base GUI
base.OnInspectorGUI();
//Sets target so it is easy to reference
Day day = (Day)target;
//Sets scene as dirty
//EditorUtility.SetDirty(day.scene);
//No indent for size, updates serialized objects
EditorGUI.indentLevel = 0;
serializedObject.Update();
//Sets fDatas as serialized properties
SerializedProperty fDatas = this.serializedObject.FindProperty("fDatas");
//Seperator between other data and function data
EditorGUILayout.Separator();
//Header for function data
EditorGUILayout.LabelField("Function Data", EditorStyles.boldLabel);
//Helpbox to help instruct how to populate a day with functions
EditorGUILayout.HelpBox("Select how many functions that will run in a day using the 'Size' field. For each function you want to enter, select the GameObject the function's script is attached to in the scene in the first dropdown and then the actual function in the second dropdown.", MessageType.Info);
//Makes a property field for the size of the fData array
EditorGUILayout.PropertyField(fDatas.FindPropertyRelative("Array.size"));
//Changes indent to 1 for actual entries in fData list
EditorGUI.indentLevel = 1;
//For each fData...
for (int i = 0; i < fDatas.arraySize; i++)
{
//IndentLevel = 0 for header
EditorGUI.indentLevel = 0;
//Header for each function
EditorGUILayout.LabelField("Function " + (i+1), EditorStyles.boldLabel);
//Changes indent to 1 for all entries in fData list
EditorGUI.indentLevel = 1;
/*
* IS DIALOGUE?
*/
//Begins line for GameObject
EditorGUILayout.BeginHorizontal();
//Label
EditorGUILayout.LabelField("Function " + (i + 1) + " isDialogue", GUILayout.Width(175));
//Draws the checkbox
fDatas.GetArrayElementAtIndex(i).FindPropertyRelative("isDialogue").boolValue = EditorGUILayout.Toggle(fDatas.GetArrayElementAtIndex(i).FindPropertyRelative("isDialogue").boolValue);
//Ends line
EditorGUILayout.EndHorizontal();
/*
* CHILD GAME OBJECT
*/
//Only shows GO & methods if not dialogue
if (fDatas.GetArrayElementAtIndex(i).FindPropertyRelative("isDialogue").boolValue == false)
{
//Begins line for GameObject
EditorGUILayout.BeginHorizontal();
//Labels each function element
EditorGUILayout.LabelField("Function " + (i + 1) + " GO", GUILayout.Width(175));
//Defines childrenNames as a serialized property
SerializedProperty childrenNames = fDatas.GetArrayElementAtIndex(i).FindPropertyRelative("childrenNames");
//String to unpack serializedproperty to
string[] namesChildren = new string[childrenNames.FindPropertyRelative("Array.size").intValue];
//Unpacks childrenNames serializedproperty back into a string array
for (int j = 0; j < childrenNames.FindPropertyRelative("Array.size").intValue; j++)
{
namesChildren[j] = childrenNames.GetArrayElementAtIndex(j).stringValue;
}
//Draws the dropdown with all possible children
fDatas.GetArrayElementAtIndex(i).FindPropertyRelative("childIndex").intValue = EditorGUILayout.Popup(fDatas.GetArrayElementAtIndex(i).FindPropertyRelative("childIndex").intValue, namesChildren);
//Ends line
EditorGUILayout.EndHorizontal();
/*
* METHOD
*/
//Defines methodNames as a serialized property
SerializedProperty methodNames = fDatas.GetArrayElementAtIndex(i).FindPropertyRelative("methodNames");
//Only shows method name box if the function has methods
if (methodNames.arraySize > 0)
{
//Begins line for Method
EditorGUILayout.BeginHorizontal();
//Labels each function element
EditorGUILayout.LabelField("Function " + (i + 1) + " Name", GUILayout.Width(175));
//String to unpack serializedproperty to
string[] namesMethod = new string[methodNames.FindPropertyRelative("Array.size").intValue];
//Unpacks methodNames serializedproperty back into a string array
for (int j = 0; j < methodNames.FindPropertyRelative("Array.size").intValue; j++)
{
namesMethod[j] = methodNames.GetArrayElementAtIndex(j).stringValue;
}
//Draws the dropdown with all possible methods
fDatas.GetArrayElementAtIndex(i).FindPropertyRelative("methodIndex").intValue = EditorGUILayout.Popup(fDatas.GetArrayElementAtIndex(i).FindPropertyRelative("methodIndex").intValue, namesMethod);
//Ends line
EditorGUILayout.EndHorizontal();
}
}
/*
* DIALOGUE
*/
//Dialogue does not show up if function is not selected as dialogue
if (fDatas.GetArrayElementAtIndex(i).FindPropertyRelative("isDialogue").boolValue == true)
{
//Labels dialogue
EditorGUILayout.LabelField("Function " + (i + 1) + " Dialogue", GUILayout.Width(175));
//The dialogue (!!LINE THAT ISN'T WORKING AS EXPECTED!!)
EditorGUILayout.PropertyField(fDatas.GetArrayElementAtIndex(i).FindPropertyRelative("dialogue"), true);
}
/*
* DELAY
*/
//Begins horizontal
EditorGUILayout.BeginHorizontal();
//Labels field differently for last function for clarification
if (i < (fDatas.arraySize - 1))
{
EditorGUILayout.LabelField("Function " + (i + 1) + " Delay", GUILayout.Width(175));
}
else
{
EditorGUILayout.LabelField("Delay to End of Day", GUILayout.Width(175));
}
//The field to input the float value for the delay
fDatas.GetArrayElementAtIndex(i).FindPropertyRelative("delay").floatValue = EditorGUILayout.FloatField(fDatas.GetArrayElementAtIndex(i).FindPropertyRelative("delay").floatValue);
//End horizontal
EditorGUILayout.EndHorizontal();
}
//Applies the properties
serializedObject.ApplyModifiedProperties();
}
}
Thank you so much for any assistance!