Search Unity

Issue with ScriptableObject not executing a function in Editor window.

Discussion in 'Scripting' started by markashburner, May 19, 2019.

  1. markashburner

    markashburner

    Joined:
    Aug 14, 2015
    Posts:
    212
    Hi I have built a scriptable object to randomize an array of colours.

    However in the editor window when I call the function from a button, it does not execute the random colour range.

    This is my scriptable object script.

    Code (CSharp):
    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using UnityEngine;
    4.  
    5. [CreateAssetMenu()]
    6.  
    7. public class ColourRange : ScriptableObject
    8. {
    9.     public Color32[] coloursStartRange = { new Color32(218, 194, 123, 255), new Color32(214, 175, 115, 255), new Color32(231, 166, 68, 255), new Color32(225, 131, 57, 255), new Color32(181, 87, 28, 255), new Color32(140, 51, 19, 255) };
    10.     public Color32[] coloursEndRange = { new Color32(218, 194, 123, 255), new Color32(214, 175, 115, 255), new Color32(231, 166, 68, 255), new Color32(225, 131, 57, 255), new Color32(181, 87, 28, 255), new Color32(140, 51, 19, 255) };
    11.     public Color32[] newColourRange;
    12.  
    13.  
    14.     public void RandomiseColourButton()
    15.     {
    16.         RandomiseColourRange(newColourRange, coloursStartRange, coloursEndRange);
    17.  
    18.     }
    19.  
    20.  
    21.     public Color32[] RandomiseColourRange(Color32[] colourRange, Color32[] startColourRange, Color32[] endColourRange)
    22.     {
    23.         int len = Mathf.Min(colourRange.Length, startColourRange.Length, endColourRange.Length);
    24.         Color32[] returnValue = new Color32[len];
    25.  
    26.         for (int i = 0; i < len; i++)
    27.         {
    28.             colourRange[i] = ProcessOne(startColourRange[i],
    29.             endColourRange[i]);
    30.         }
    31.         return colourRange;
    32.     }
    33.  
    34.     private Color32 ProcessOne(Color32 startColourRange, Color32 endColourRange)
    35.     {
    36.         Debug.Log("Set Colour Range");
    37.         float h1 = 0f;
    38.         float s1 = 0f;
    39.         float v1 = 0f;
    40.         Color.RGBToHSV(startColourRange, out h1, out s1, out v1);
    41.  
    42.         float h2 = 0f;
    43.         float s2 = 0f;
    44.         float v2 = 0f;
    45.         Color.RGBToHSV(endColourRange, out h2, out s2, out v2);
    46.  
    47.         return Color.HSVToRGB(
    48.             Random.Range(h1, h2),
    49.             Random.Range(s1, s2),
    50.             Random.Range(v1, v2)
    51.  
    52.         );
    53.     }
    54. }
    And here is my editor window:

    Code (CSharp):
    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using UnityEngine;
    4. using UnityEditor;
    5.  
    6. [CustomEditor(typeof(ColourRange))]
    7.  
    8. public class ColourRangeEditor : Editor
    9. {
    10.     SerializedProperty coloursStartRange;
    11.     SerializedProperty coloursEndRange;
    12.     SerializedProperty newColourRange;
    13.     ColourRange colourRange;
    14.  
    15.     public void OnEnable()
    16.     {
    17.         colourRange = (ColourRange)target;
    18.  
    19.         coloursStartRange = serializedObject.FindProperty("coloursStartRange");
    20.         coloursEndRange = serializedObject.FindProperty("coloursEndRange");
    21.         newColourRange = serializedObject.FindProperty("newColourRange");
    22.  
    23.     }
    24.  
    25.     public override void OnInspectorGUI()
    26.     {
    27.  
    28.         EditorGUILayout.PropertyField(coloursStartRange, true);
    29.         EditorGUILayout.PropertyField(coloursEndRange, true);
    30.         if (GUILayout.Button("Test Colour Range"))
    31.         {
    32.             colourRange.RandomiseColourButton();
    33.         }
    34.         EditorGUILayout.PropertyField(newColourRange, true);
    35.  
    36.         serializedObject.ApplyModifiedProperties();
    37.  
    38.     }
    39.  
    40. }
    Here is what it looks like in the inspector.



    The test colour range button does not execute? It's because it is a ScriptableObject, I know this because when I change the ColourRange script back to MonoBehaviour, the Test Colour Range button then executes...

    How come the function doesn't work as a ScriptableObject?

    Could someone please help?

    Thanks
     
    Last edited: May 19, 2019
  2. Tortuap

    Tortuap

    Joined:
    Dec 4, 2013
    Posts:
    137
    That's because you need to use SerializedProperty in order to edit values of members of your ScriptableObject, like in this example:

    Code (CSharp):
    1.  
    2.     public override void OnInspectorGUI ()
    3.     {
    4.         EditorGUILayout.PropertyField ( coloursStartRange, true );
    5.         EditorGUILayout.PropertyField ( coloursEndRange, true );
    6.         if ( GUILayout.Button ( "Test Colour Range" ) )
    7.         {
    8.             int count = newColourRange.arraySize;
    9.             for ( int i = 0; i < count; i++ )
    10.             {
    11.                 Color32 colour = colourRange.ProcessOne ( ... );
    12.  
    13.                 SerializedProperty colourSp = newColourRange.GetArrayElementAtIndex ( i );
    14.                 colourSp.FindPropertyRelative ( "r" ).intValue = colour.r;
    15.                 colourSp.FindPropertyRelative ( "g" ).intValue = colour.g;
    16.                 colourSp.FindPropertyRelative ( "b" ).intValue = colour.b;
    17.                 colourSp.FindPropertyRelative ( "a" ).intValue = colour.a;
    18.             }
    19.         }
    20.  
    21.         EditorGUILayout.PropertyField ( newColourRange, true );
    22.  
    23.         serializedObject.ApplyModifiedProperties ();
    24.     }
    25.  
    Otherwise calling ApplyModifiedProperties does nothing.
     
  3. markashburner

    markashburner

    Joined:
    Aug 14, 2015
    Posts:
    212

    Not sure if I understand your example...I tried implementing it and I get lots of errors.

     
  4. Tortuap

    Tortuap

    Joined:
    Dec 4, 2013
    Posts:
    137
    Don't comment 'Color32 colour = ...' but adapt it to call your method ProcessOne the way you need and you'll make it work.

    Just understand that
    • when changing values of colourRange directly, at call of ApplyModifiedProperties, all your changes will be overwritten
    • when using SerializedProperty to edit the SerializedObject representation of colourRange, at call of ApplyModifiedProperties, all changes made through SerializedProperty will be applied
     
  5. markashburner

    markashburner

    Joined:
    Aug 14, 2015
    Posts:
    212
    Ahh I get you...but I am not sure how to convert the Color32 colour into an array:

     
  6. Tortuap

    Tortuap

    Joined:
    Dec 4, 2013
    Posts:
    137
    Code (CSharp):
    1. Colour32 colour = colourRange.ProcessOne ( colourRange.coloursStartRange [i], colourRange.coloursEndRange [i] );
     
  7. markashburner

    markashburner

    Joined:
    Aug 14, 2015
    Posts:
    212
    yeah I tried that and I get this error:

    NullReferenceException: Object reference not set to an instance of an object
     
  8. markashburner

    markashburner

    Joined:
    Aug 14, 2015
    Posts:
    212
    I think it's because ProcessOne converts to HSV? I think.