Mostra um campo pop-up para serializar valores de string ou inteiros de uma lista de opções no Unit3d

Em um post anterior meu no coderwall, tentei explicar como criar um pop-up de show no editor para selecionar facilmente a camada de classificação em um MonoBehavior.

Minha pergunta, depois disso, era: como eu poderia tornar isso mais genérico?

Por exemplo, quero que minha propriedade string permaneça dentro de uma lista de valores.

Aqui está uma solução simples:

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

E aqui está como usá-lo:

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;
}

No entanto, isso não é muito útil, como é. Gostaria de criar um conjunto de gavetas de propriedades úteis que pudessem mostrar algumas informações do jogo.

Aqui está um exemplo: Supondo que eu tenha um componente que deve mudar seu comportamento quando é carregado em uma determinada cena.

public class SomeBehavior : MonoBehaviour {
public string SceneName;

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

Seria muito legal se a seleção de cena pudesse ser mostrada como uma lista de nomes de cena.

Veja como editei a gaveta de propriedades “SceneInList”:

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;
}
}

Agora, usando reflexão, posso definir um método estático que cria a lista de nomes de cena:

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
}

E aqui está como ele pode ser usado:

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

Aqui está o exemplo completo:
https://gist.github.com/ProGM/9cb9ae1f7c8c2a4bd3873e4df14a6687

Usamos esse código no Oh! Estou ficando mais alto : D

Espero que seja útil!