Custom Inspector for a list of custom class members.
I am trying to make an in-editor content creator for my strategy game. I thought it was the easiest way to do it rather then type XML or hardcode class instances; output it as XML and save. But unfortunately I ran into inability to edit list members' appearance and limit values to an extent I need.
My goal is to prevent MaxElevation and MaxHumidity from having lower values then MinElevation and MinHumidity respectively in each member. (From there I can draw analogy to apply to more tricky parts of other content generators)
My MonoBehaviour (do not mind the methods of BiomM) :
using UnityEngine;
using System.Collections;
using System.Collections.Generic;
using System;
public class BiomsListGenerator : MonoBehaviour
{
public List<BiomM> bioms;
public void Load ()
{
bioms = new List<BiomM> ();
foreach (string key in DataHub.Bioms.Keys) {
bioms.Add (BiomM.BiomToBiomM (key, DataHub.Bioms [key]));
}
}
public void Save ()
{
List<BiomContainer.BiomSaveFormat> biomsSF = new List<BiomContainer.BiomSaveFormat> ();
foreach (BiomM biom in bioms) {
biomsSF.Add (BiomM.BiomMToBiom (biom));
}
BiomContainer.Save (biomsSF);
}
}
//All you need to know are the properties of that class.
[System.Serializable]
public class BiomM
{
public string name;
public string officialName;
[Range (0f, 1000f)]
public float minElevation;
[Range (0f, 1000f)]
public float maxElevation;
[Range (0f, 1000f)]
public float minHumidity;
[Range (0f, 1000f)]
public float maxHumidity;
public bool primary;
public GameObject modelPrefab;
public GameObject guiPrifab;
public BiomM (string name, string officialName, float minElevation, float minHumidity, float maxElevation, float maxHumidity, bool primary, GameObject modelPrefabName, GameObject guiPrifabName)
{
this.name = name;
this.officialName = officialName;
this.minElevation = minElevation;
this.minHumidity = minHumidity;
this.maxElevation = maxElevation;
this.maxHumidity = maxHumidity;
this.primary = primary;
this.modelPrefab = modelPrefabName;
this.guiPrifab = guiPrifabName;
}
public static BiomContainer.BiomSaveFormat BiomMToBiom (BiomM bm)
{
string s1 = "";
string s2 = "";
try {
s1 = bm.modelPrefab.name;
} catch {
}
try {
s2 = bm.guiPrifab.name;
} catch {
}
return new BiomContainer.BiomSaveFormat (bm.name, new Biom (bm.officialName, bm.minElevation / 1000, bm.minHumidity / 1000, bm.maxElevation / 1000, bm.maxHumidity / 1000, bm.primary, s1, s2));
}
public static BiomM BiomToBiomM (string name, Biom biom)
{
return new BiomM (
name,
biom.officialName,
biom.minElevation * 1000,
biom.minHumidity * 1000,
biom.maxElevation * 1000,
biom.maxHumidity * 1000,
biom.primary,
Resources.Load (BiomContainer.modelPrefabFolderPath + biom.modelPrefabName) as GameObject,
Resources.Load (BiomContainer.guiPrefabFolderPath + biom.guiPrifabName) as GameObject
);
}
public static BiomM BiomToBiomM (BiomContainer.BiomSaveFormat b)
{
return BiomToBiomM (b.key,b.biom);
}
}
My Editor Script:
using UnityEngine;
using System.Collections;
using UnityEditor;
[CustomEditor (typeof(BiomsListGenerator))]
public class BiomsListGeneratorEditor: Editor
{
public override void OnInspectorGUI ()
{
BiomsListGenerator blg = (BiomsListGenerator)target;
DrawDefaultInspector (); //what should replace this?
if (GUILayout.Button ("Load")) {
blg.Load ();
}
if (GUILayout.Button ("Save")) {
blg.Save ();
}
}
}
Answer by Adam-Mechtley · Oct 10, 2016 at 07:57 AM
Could you achieve this using a PropertyDrawer for the BioM type?
Yes! Thank you very much! I just overlooked that class because I focused too much on word "Editor". Solution is below if you are interested.
Answer by Daniil-Besedin · Oct 10, 2016 at 03:38 PM
Here is the end result for those who are interested (new Editor Script):
using UnityEngine;
using System.Collections;
using UnityEditor;
using System.Collections.Generic;
[CustomEditor (typeof(BiomsListGenerator))]
public class BiomsListGeneratorEditor: Editor
{
public Dictionary<int,bool> dictionary = new Dictionary<int, bool> ();
public override void OnInspectorGUI ()
{
BiomsListGenerator blg = (BiomsListGenerator)target;
serializedObject.Update ();
SerializedProperty myIterator = serializedObject.FindProperty ("bioms");
for (int i = 0; i < short.MaxValue; i++) {
if (!dictionary.ContainsKey (i)) {
dictionary [i] = false;
}
if (i >= 3) {
dictionary [i] = EditorGUILayout.Foldout (dictionary [i], myIterator.FindPropertyRelative ("officialName").stringValue);
}
if (dictionary [i] && i >= 3) {
EditorGUILayout.PropertyField (myIterator);
EditorGUILayout.BeginHorizontal ();
if (GUILayout.Button ("Copy")) {
serializedObject.FindProperty ("bioms").InsertArrayElementAtIndex (i - 3);
}
if (GUILayout.Button ("Delete")) {
serializedObject.FindProperty ("bioms").DeleteArrayElementAtIndex (i - 3);
}
EditorGUILayout.EndHorizontal ();
EditorGUILayout.Space ();
EditorGUILayout.Space ();
}
if (!myIterator.Next (i < 3)) {
break;
}
}
serializedObject.ApplyModifiedProperties ();
if (GUILayout.Button ("Load")) {
blg.Load ();
}
if (GUILayout.Button ("Save")) {
blg.Save ();
}
}
}
[CustomPropertyDrawer (typeof(BiomM))]
public class BiomMpd : PropertyDrawer
{
public override void OnGUI (Rect position, SerializedProperty property, GUIContent label)
{
float minElevation = property.FindPropertyRelative ("minElevation").floatValue;
float maxElevation = property.FindPropertyRelative ("maxElevation").floatValue;
float minHumidity = property.FindPropertyRelative ("minHumidity").floatValue;
float maxHumidity = property.FindPropertyRelative ("maxHumidity").floatValue;
property.FindPropertyRelative ("name").stringValue = EditorGUI.TextField (position, "Unique Name", property.FindPropertyRelative ("name").stringValue);
property.FindPropertyRelative ("officialName").stringValue = EditorGUILayout.TextField ("Displayed Name", property.FindPropertyRelative ("officialName").stringValue);
EditorGUILayout.BeginHorizontal ();
minElevation = EditorGUILayout.FloatField (minElevation);
EditorGUILayout.PrefixLabel ("Elevation");
maxElevation = EditorGUILayout.FloatField (maxElevation);
EditorGUILayout.EndHorizontal ();
EditorGUILayout.MinMaxSlider (ref minElevation, ref maxElevation, 0f, 1000f);
EditorGUILayout.BeginHorizontal ();
minHumidity = EditorGUILayout.FloatField (minHumidity);
EditorGUILayout.PrefixLabel ("Humidity");
maxHumidity = EditorGUILayout.FloatField (maxHumidity);
EditorGUILayout.EndHorizontal ();
EditorGUILayout.MinMaxSlider (ref minHumidity, ref maxHumidity, 0f, 1000f);
property.FindPropertyRelative ("primary").boolValue = EditorGUILayout.ToggleLeft (" Essential at the start of the game.", property.FindPropertyRelative ("primary").boolValue);
property.FindPropertyRelative ("modelPrefab").objectReferenceValue = EditorGUILayout.ObjectField (
new GUIContent ("In-Game Model Prefab", "Must be located in Assets/Resources/" + BiomContainer.modelPrefabFolderPath),
property.FindPropertyRelative ("modelPrefab").objectReferenceValue, typeof(GameObject), false);
property.FindPropertyRelative ("guiPrifab").objectReferenceValue = EditorGUILayout.ObjectField (
new GUIContent ("GUI Representation Prefab", "Must be located in Assets/Resources/" + BiomContainer.guiPrefabFolderPath),
property.FindPropertyRelative ("guiPrifab").objectReferenceValue, typeof(GameObject), false);
property.FindPropertyRelative ("minElevation").floatValue = minElevation;
property.FindPropertyRelative ("maxElevation").floatValue = maxElevation;
property.FindPropertyRelative ("minHumidity").floatValue = minHumidity;
property.FindPropertyRelative ("maxHumidity").floatValue = maxHumidity;
}
}
Your answer
Follow this Question
Related Questions
How to remove an item from a list of custom variables 1 Answer
Custom inspector. Pick one bool from a list. 1 Answer
c# foreach does not work 1 Answer
Custom Inspector changes not updating target in Edit Mode 1 Answer
InvalidOperationException: Operation is not valid due to the current state of the object 1 Answer