[フレーム]
Last Updated: October 29, 2016
·
3.059K
· ProGM

Show a popup field to serialize string or integer values from a list of choices in unity3d

In a previous coderwall post of mine, I tried to explain how to create show a popup in the editor to select easily the sorting layer in a MonoBehavior.

My question, after that, was: how could I make this more generic?

For instance, I want that my string property to stay inside a list of values.

Here's a simple solution:

using System;
using UnityEngine;
#if UNITY_EDITOR
using UnityEditor;
#endif

public class StringInList : PropertyAttribute {
 public delegate string[] GetStringList();

 public StringInList(string [] list) {
 List = list;
 }

 public string[] List {
 get;
 private set;
 }
}


#if UNITY_EDITOR
[CustomPropertyDrawer(typeof(StringInList))]
public class StringInListDrawer : PropertyDrawer {
 // Draw the property inside the given rect
 public override void OnGUI (Rect position, SerializedProperty property, GUIContent label) {
 var stringInList = attribute as StringInList;
 var list = stringInList.List;
 if (property.propertyType == SerializedPropertyType.String) {
 int index = Mathf.Max (0, Array.IndexOf (list, property.stringValue));
 index = EditorGUI.Popup (position, property.displayName, index, list);

 property.stringValue = list [index];
 } else if (property.propertyType == SerializedPropertyType.Integer) {
 property.intValue = EditorGUI.Popup (position, property.displayName, property.intValue, list);
 } else {
 base.OnGUI (position, property, label);
 }
 }
}
#endif

And here's how to use it:

public class MyBehavior : MonoBehaviour {
 [StringInList(new [] { "Cat", "Dog"})] public string Animal;
 // This will store the index of the array value
 [StringInList(new [] { "John", "Jack", "Jim"})] public int PersonID;
}

However this is not very useful, as is. I would like to create a set of useful property drawers that could show some game informations.

Here's an example: Assuming I have a Component that should change its behavior when it's loaded in a certain Scene.

public class SomeBehavior : MonoBehaviour {
 public string SceneName;

 void Start() {
 if (SceneManager.GetCurrentScene().name == SceneName) {
 Debug.Log("Special things");
 }
 }
}

It would be really cool if the scene selection could be shown as a list of scene names.

Here's how I edited the "SceneInList" property drawer:

public class StringInList : PropertyAttribute {
 public delegate string[] GetStringList();

 public StringInList(string [] list) {
 List = list;
 }

 public StringInList(Type type, string methodName) {
 var method = type.GetMethod (methodName);
 if (method != null) {
 List = method.Invoke (null, null) as string[];
 } else {
 Debug.LogError ("NO SUCH METHOD " + methodName + " FOR " + type);
 }
 }

 public string[] List {
 get;
 private set;
 }
}

Now, using reflection, I can define a static method that creates the list of scene names:

public static class PropertyDrawersHelper {
 #if UNITY_EDITOR

 public static string[] AllSceneNames()
 {
 var temp = new List<string>();
 foreach (UnityEditor.EditorBuildSettingsScene S in UnityEditor.EditorBuildSettings.scenes)
 {
 if (S.enabled)
 {
 string name = S.path.Substring(S.path.LastIndexOf('/')+1);
 name = name.Substring(0,name.Length-6);
 temp.Add(name);
 }
 }
 return temp.ToArray();
 }

 #endif
}

And here's how it could be used:

[StringInList(typeof(PropertyDrawersHelper), "AllSceneNames")] public string SceneName;

Here's the complete example:
https://gist.github.com/ProGM/9cb9ae1f7c8c2a4bd3873e4df14a6687

We used this code in Oh! I'm Getting Taller :D

I hope it'll be useful!

AltStyle によって変換されたページ (->オリジナル) /