Noticias

¡RECUERDA QUE SI ERES UN NUEVO USUARIO, DEBES PRESENTARTE PARA PODER PUBLICAR MENSAJES! | TENEMOS CANAL OFICIAL DE TELEGRAM: t.me/unity3dspain

Temas recientes

Mostrar variables de un scriptableObject en un custom editor

Iniciado por ftejada, Julio 26, 2019, 11:42:21 AM

Tema anterior - Siguiente tema
Julio 26, 2019, 11:42:21 AM Ultima modificación: Julio 26, 2019, 11:43:29 AM por ftejada
Hola a todos!!
 
estoy intentando que se muestren las variables publicas que tengo en una clase que hereda de ScriptableObject en un custom Editor que estoy haciendo
 

[System.Serializable]
public class ClaseA : ScriptableObject
{
public bool showShapes        = true;
}
 
public class MainClass : Monobehaviour
{
//public ClaseA claseA = new ClaseA(); //Tambien probé a poner esto en vez de la linea de abajo pero no solucionaba el problema
public ClaseA claseA;
}
 
[CustomEditor(typeof(MainClass))]
public class MainClassEditor : Editor
{
SerializedProperty claseA = null;
OnEnable()
{
   claseA = serializedObject.FindProperty("claseA");
}
public override void OnInspectorGUI()
{
   //....
   EditorGUILayout.PropertyField(claseA, true);   //¿Supuestamente con true como segundo parametro dibuja las variables que tenga esta property?

   //...
}
}

 
El caso es que no se porqué no se muestran las variables, solo se muestra el campo para asignar/arrastrar el ScriptableObject en cuestion. Si no hay ninguno asignado entiendo que no se muestre nada, pero una vez asignado... no se pq.
 
Cuando quiero mostrar arrays de clases con todas sus variables publicas lo hago con serializedObject.FindProperty(property.GetArrayElementAtIndex(i), true) y me muestra todas sus variables publicas poniendo en true el segundo parametro de la funcion FindProperty(). 
 
Acaso no se pueden mostrar las variables de un scriptableObject mediante FindProperty(property, true);?????
 
He estado buscando por internet y la documentacion durante varias horas pero no he podido encontrar por que me ocurre este problema.
 
Version de Unity 2018.2.0
 
 
 
Gracias por adelantado. Un saludo



   
eature=oembed" width="480">

 


Por si te sirve, si no comenta y buscamos alguna solución, pero el tema de los Scriptable Objects lo tengo un poco oxidado jajajaja

A ver, ese código es un poco como un potaje. Son conceptos diferentes mezclados. Te explico:
 
- Un SO ya es serializable, con lo cual ese [System.Serializable] sobra.
 
- No requieres ni de MonoBehaviour ni del Editor para mostrar los datos
 
En base sería:
 
 
 

   [System.Serializable]
    public class soItem {
          public string title;
        public string desc;
}
[CreateAssetMenu(menuName = "SOComponents/Items")]
    public class soSoyUnSO : ScriptableObject {
   [SerializeField] private List<soItem> _items = new List<soItem>();      
         
      private void OnEnable() {
            Debug.Log("OnEnable");
        }
        private void OnDisable() {
            Debug.Log("OnDisable");
        }          
}

 
El CreateAssetMenu te creará una opción en el menú contextual de proyecto para añadirlo a una carpeta.
 
La class soItem contiene los datos. Es una clase pura.
 
La class soSouyunSO es el SO para mostrarlos.
 
Te puedes crear una función en el SO para añadirlos por code a la lista o desde el editor a mano.
 
 

Julio 26, 2019, 05:24:02 PM #3 Ultima modificación: Julio 26, 2019, 05:29:44 PM por lightbug
Cita de: ftejada date=1564134141El caso es que no se porqué no se muestran las variables, solo se muestra el campo para asignar/arrastrar el ScriptableObject en cuestion. Si no hay ninguno asignado entiendo que no se muestre nada, pero una vez asignado... no se pq.
   


Que se muestren las variables significa que el editor del SCO se visualize en otro editor? por ej en un asset mio (Kinematic 2D) tengo lo siguiente:
 

 
Fijate que el SCO (con sus campos serializables) se muestran en cada editor del componente Character Hybrid Brain, pero en realidad corresponden a un nuevo editor (anidado).
 
Por ej, el primero que aparece ("Input Data") tiene el siguiente código:
 

...
//El campo del objeto, el SCO
EditorGUILayout.PropertyField( inputData );  
            GUILayout.Space(10);
           
      //Si no es nulo dibujarlo
            if( inputData.objectReferenceValue != null )
            {
                GUILayout.BeginVertical( EditorStyles.helpBox );
         
         // inputEditor es de tipo "Editor", si es nulo crealo
                if( inputEditor == null )
            //Crear el editor
                    CreateCachedEditor( inputData.objectReferenceValue , null , ref inputEditor );
               
         //Ejecutar OnInspectorGUI del editor creado (OnInspectorGUI dentro de OnInspectorGUI --> anidado)
                inputEditor.OnInspectorGUI();
                GUILayout.EndVertical();
            }
            else
            {
         
                if( inputEditor != null )
                    inputEditor = null;
               
                EditorGUILayout.HelpBox( "Select a Character Input Data asset" , MessageType.Warning );
            }

 
 
 
Cita de: ftejada date=1564134141Acaso no se pueden mostrar las variables de un scriptableObject mediante FindProperty(property, true);?????
   


Para buscar las variables de un scriptable object vas a tener que generar un serializedObject a partir del objecto (scriptableObject.objectReferenceValue):
 

sObject = new SerializedObject(scriptableObject.ObjectReferenceValue);

 
una vez creado podés buscar las propiedades:
 

SerializedProperty property = sObject.FindProperty("property");

 
 
 
No se si puse los nombres exactamente como son, pero se entiende.
 
 
 
En Resumen:
 


  •    Para acceder a un scriptableObject necesitas crearlo, el serializedObject que normalmente llamas es el correspondiente al monobehaviour, no al scriptableObject que te interesa


  •    Unity utiliza editores anidados casi siempre, fijate el PostProccesingStack, la mayor parte corresponde a mini editores que se van dibujando con OnInspectorGUI, obviamente todos ScriptableObject


  •    Los ScriptableObject son completamente serializables, podés anidar los que quieras, funcionan muy bien para representar SCO abstractos (abstract class ...) donde dibujas sin conocer el tipo derivado final (esto no es posible con clases de C# serializadas, otra vez, el ejemplo del PPStack sirve de ejemplo)


Cita de: lightbug date=1564154642Que se muestren las variables significa que el editor del SCO se visualize en otro editor? por ej en un asset mio (Kinematic 2D) tengo lo siguiente:
   
   
      
   
      Fijate que el SCO (con sus campos serializables) se muestran en cada editor del componente Character Hybrid Brain, pero en realidad corresponden a un nuevo editor (anidado).
   
   
      Por ej, el primero que aparece ("Input Data") tiene el siguiente código:
   
   

...
//El campo del objeto, el SCO
EditorGUILayout.PropertyField( inputData );  
            GUILayout.Space(10);
           
      //Si no es nulo dibujarlo
            if( inputData.objectReferenceValue != null )
            {
                GUILayout.BeginVertical( EditorStyles.helpBox );
         
         // inputEditor es de tipo "Editor", si es nulo crealo
                if( inputEditor == null )
            //Crear el editor
                    CreateCachedEditor( inputData.objectReferenceValue , null , ref inputEditor );
               
         //Ejecutar OnInspectorGUI del editor creado (OnInspectorGUI dentro de OnInspectorGUI --> anidado)
                inputEditor.OnInspectorGUI();
                GUILayout.EndVertical();
            }
            else
            {
         
                if( inputEditor != null )
                    inputEditor = null;
               
                EditorGUILayout.HelpBox( "Select a Character Input Data asset" , MessageType.Warning );
            }

   
       
   
   
      Para buscar las variables de un scriptable object vas a tener que generar un serializedObject a partir del objecto (scriptableObject.objectReferenceValue):
   
   

sObject = new SerializedObject(scriptableObject.ObjectReferenceValue);

   
      una vez creado podés buscar las propiedades:
   
   

SerializedProperty property = sObject.FindProperty("property");

   
       
   
   
      No se si puse los nombres exactamente como son, pero se entiende.
   
   
       
   
   
      En Resumen:
   
   


  •          Para acceder a un scriptableObject necesitas crearlo, el serializedObject que normalmente llamas es el correspondiente al monobehaviour, no al scriptableObject que te interesa
          

  •       

  •          Unity utiliza editores anidados casi siempre, fijate el PostProccesingStack, la mayor parte corresponde a mini editores que se van dibujando con OnInspectorGUI, obviamente todos ScriptableObject
          

  •       

  •          Los ScriptableObject son completamente serializables, podés anidar los que quieras, funcionan muy bien para representar SCO abstractos (abstract class ...) donde dibujas sin conocer el tipo derivado final (esto no es posible con clases de C# serializadas, otra vez, el ejemplo del PPStack sirve de ejemplo)
          

  •    


Gracias a todos por responder. Hay algunas cositas que aun no veo claro...
 
@lightbug inputEditor de donde sale?  qué almacena exactamente? Perdona la torpeza pero no lo termino de entender.
 
@iRobb
 
Cita de: iRobb date=1564138134- Un SO ya es serializable, con lo cual ese [System.Serializable] sobra. 
   


Gracias por la info sobre esto. No terminaba de entender realmente si me servia en un SO. Ya todo claro
 
Por otra parte, se que de la manera que indicas no necesito mostrar ni cambiar los valores de las variables del SO desde un "custom Inspector" por llamarlo de algun modo.
 
Aunque en el ejemplo que puse en codigo simplifique todo para que se entendiese el problema, en realidad tengo muchos SO con muchas opciones que el usuario debe configurar. Por eso necesito que todo se pueda manejar desde un solo sitio "centralizado", en vez de tener que obligar al usuario a buscar los SO, en sus respectivas carpetas del proyecto, cada vez que quiera modificar alguna configuracion.
 
Por eso pensé y creo que la mejor manera es mediante un CunstomInspector que maneje todos los SO y sus variables para poderse mostrar y configurar desde ahí. Si no he entendido lo que querias decirme ruego me disculpes.
 
Saludos

Cita de: ftejada date=1564321939Gracias a todos por responder. Hay algunas cositas que aun no veo claro...
   
   
      @lightbug inputEditor de donde sale?  qué almacena exactamente? Perdona la torpeza pero no lo termino de entender.
   
   
      @iRobb
   
   
      Gracias por la info sobre esto. No terminaba de entender realmente si me servia en un SO. Ya todo claro
   
   
      Por otra parte, se que de la manera que indicas no necesito mostrar ni cambiar los valores de las variables del SO desde un "custom Inspector" por llamarlo de algun modo.
   
   
      Aunque en el ejemplo que puse en codigo simplifique todo para que se entendiese el problema, en realidad tengo muchos SO con muchas opciones que el usuario debe configurar. Por eso necesito que todo se pueda manejar desde un solo sitio "centralizado", en vez de tener que obligar al usuario a buscar los SO, en sus respectivas carpetas del proyecto, cada vez que quiera modificar alguna configuracion.
   
   
      Por eso pensé y creo que la mejor manera es mediante un CunstomInspector que maneje todos los SO y sus variables para poderse mostrar y configurar desde ahí. Si no he entendido lo que querias decirme ruego me disculpes.
   
   
      Saludos
   


Disculpado aunque no hay ningún problema.
 
Y la opción de crear una class pura en cada componente que necesita de configuración, y luego las unificas todas en un solo SO? Sería algo así como:
 

public class componente : MonoBehavour {
public class configComponente {
   dato, dato
}
 
  [SerializeField] private soAll soAll;
  private configComponente configComponente;
     
     void Start() {
      configComponente = soAll.configComponente;
      dato = configComponente.dato;
    }
}
public class soAll : ScriptableObject {
  [SerializeField] private componente.configComponente _configComponente;
  public configComponente configComponente { get => _configComponente }
}

 
 

Cita de: lightbug date=1564154642esto no es posible con clases de C# serializadas, otra vez, el ejemplo del PPStack sirve de ejemplo
   


Efectivamente, ahora mismo eso no es posible con clases C# serializadas, pero la buena noticia es que a partir de Unity 2019.3 lo va a ser gracias a un nuevo atributo llamado SerializeReference. Esto es algo que los que desarrollamos herramientas llevábamos AÑOS esperando que Unity implementase, así que hay cierta expectación con el tema.
 
Más información aquí: https://forum.unity.com/threads/serializereference-attribute.678868/

Julio 30, 2019, 01:52:40 AM #7 Ultima modificación: Julio 30, 2019, 01:59:22 AM por lightbug
Cita de: xeleh date=1564328687Efectivamente, ahora mismo eso no es posible con clases C# serializadas, pero la buena noticia es que a partir de Unity 2019.3 lo va a ser gracias a un nuevo atributo llamado SerializeReference. Esto es algo que los que desarrollamos herramientas llevábamos AÑOS esperando que Unity implementase, así que hay cierta expectación con el tema.
   
   
      Más información aquí: https://forum.unity.com/threads/serializereference-attribute.678868/
   


Buenísimo, buena info.
 
 
 
Cita de: ftejada date=1564321939Gracias a todos por responder. Hay algunas cositas que aun no veo claro...
   
   
      @lightbug inputEditor de donde sale?  qué almacena exactamente? Perdona la torpeza pero no lo termino de entender.
   


Ah perdon, inputEditor es un Editor, al igual que los editores que tenés en los inspectores, vos podés definir un Editor ( inputEditor ) y dibujarlo manualmente ( inputEditor.OnInspectorGUI() ).
 
En mi código está definido así:
 

Editor inputEditor = null;

 
En mi ejemplo tengo un editor por cada tipo de SCO, pero vos podés asignar todo a uno mismo, probablemente vas a tener que redibujarlo cada vez.

Gracias por las respuestas. Y parece que me va quedando algo mas claro todo este asunto... Voy a seguir con ello y si tengo alguna otra duda pregunto. Un saludo a todos.

Etiquetas: