Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.

Can I replace a sprite in an editor script?

Discussion in 'Immediate Mode GUI (IMGUI)' started by highlyinteractive, Jan 23, 2018.

  1. highlyinteractive

    highlyinteractive

    Joined:
    Sep 6, 2012
    Posts:
    116
    I'm trying to create an editor script that lets me swap the sprite in an image. My end goal is to have a UI prefab that I can quickly change the properties of (background image, text colour, icon, language etc) with a single enum dropdown.

    Currently I'm just trying to swap out the sprite. Is this possible?

    Here's my attempt so far:
    Code (CSharp):
    1. [CustomEditor(typeof(TextBox))]
    2. public class TextBoxEditor : Editor
    3. {
    4.     SerializedProperty m_Colour;
    5.  
    6.     public void OnEnable ()
    7.     {
    8.         m_Colour = serializedObject.FindProperty("Colour");
    9.     }
    10.  
    11.     public override void OnInspectorGUI ()
    12.     {
    13.         TextBox textBox = (TextBox)target;
    14.  
    15.         EditorGUILayout.PropertyField(m_Colour, new GUIContent("Box Colour"));
    16.         serializedObject.ApplyModifiedProperties();
    17.  
    18.         if (GUI.changed)
    19.         {
    20.             string guid = AssetDatabase.FindAssets("box_red")[0]; //hard coded sprite name for now
    21.             string guri = AssetDatabase.GUIDToAssetPath(guid);
    22.             Sprite spr = (Sprite)AssetDatabase.LoadAssetAtPath(guri, typeof(Sprite));
    23.  
    24.             textBox.SetSprite(spr); //sets sprite in main class - Image.sprite = spr;
    25.  
    26.             SceneView.RepaintAll();
    27.         }
    28.     }
    29. }
    I think I'm misunderstanding something because the Sprite is ending up null.

    Help or advice appreciated
     
    IvanIvanovP3 likes this.
  2. TonyLi

    TonyLi

    Joined:
    Apr 10, 2012
    Posts:
    12,561
    Are you checking that AssetDatabase.FindAssets and AssetDatabase.LoadAssetAtPath aren't returning null?

    Also, call serializedObject.Update() before EditorGUILayout.PropertyField. Otherwise serializedObject isn't guaranteed to be an accurate serialized representation of your object.
     
  3. highlyinteractive

    highlyinteractive

    Joined:
    Sep 6, 2012
    Posts:
    116
    I am - they're returning the correct values
     
  4. TonyLi

    TonyLi

    Joined:
    Apr 10, 2012
    Posts:
    12,561
    Then you may need to set it dirty. Make sure to read the important notes in that link, too.
     
  5. maax511

    maax511

    Joined:
    Jan 21, 2021
    Posts:
    6
    I recently faced the same issue. I have been creating an editor tool to authomatize creation of prefabs. They have different types and configuration and the goal was to create window, drop some info including name, shortcut, background images etc., hit "Create" and it will create prefab variant from given reference, pack images in atlas and set appropriate Sprites to appropriate Images in that prefab. It all works fine but only one kind of that prefabs always end up with blank background. I tried Debug.Log this and neither element (prefab, image component on child element of prefab, Sprite loaded from given path, Sprite property of the Image component) is null. I tried debug this using breakpoints and it started to work, but as soon as you disable the breakpoints it starts creating prefabs with the blank background again. maybe you have some suggestions what is wrong. I am trying to fix it for the second day and stil have no idea what's going on. To me it looks like Unity bug, but it's very hard to explain what exactly gone wrong.
    Here is some code

    SingleOfferWindow.cs

    Code (CSharp):
    1. prefab = CreatePrefabVariant(single_base_path, $"{offerPath}/{offerName}{dialog_prefab_name}");
    2.              img = prefab.transform.Find("Content/Background").GetComponent<Image>();
    3.              SetProperty(img, "m_Sprite", AssetDatabase.LoadAssetAtPath<Sprite>($"{dialogCompressedImagesPath}/{pack_bg_name}.png"));
    4.              SetAddressableGroup(prefab, $"All/{offerName}Dialog", "RemoteProductsDialogs");
    OfferWindow.cs (SingleOffer inherits from this class)
    Code (CSharp):
    1.  protected void SetProperty(Object go, string propertyName, object obj) {
    2.          SerializedObject so = new SerializedObject(go);
    3.          var property = so.FindProperty(propertyName);
    4.          if (property == null) {
    5.              FFLogger.LogError($"Cannot find property {propertyName} in object: {go.name}");
    6.              return;
    7.          }
    8.          so.Update();
    9.          property.SetValue(obj);
    10.          EditorUtility.SetDirty(go);
    11.          so.ApplyModifiedProperties();
    12.      }
    13. public static void SetValue(this SerializedProperty p, object value)
    14.      {
    15.        switch (p.propertyType)
    16.        {
    17.          case SerializedPropertyType.Generic:
    18.            Debug.LogWarning((object) "Get/Set of Generic SerializedProperty not supported");
    19.            break;
    20.          case SerializedPropertyType.Integer:
    21.            p.intValue = (int) value;
    22.            break;
    23.          case SerializedPropertyType.Boolean:
    24.            p.boolValue = (bool) value;
    25.            break;
    26.          case SerializedPropertyType.Float:
    27.            p.floatValue = (float) value;
    28.            break;
    29.          case SerializedPropertyType.String:
    30.            p.stringValue = (string) value;
    31.            break;
    32.          case SerializedPropertyType.Color:
    33.            p.colorValue = (Color) value;
    34.            break;
    35.          case SerializedPropertyType.ObjectReference:
    36.            p.objectReferenceValue = value as UnityEngine.Object;
    37.            break;
    38.          case SerializedPropertyType.LayerMask:
    39.            p.intValue = (int) value;
    40.            break;
    41.          case SerializedPropertyType.Enum:
    42.            p.enumValueIndex = (int) value;
    43.            break;
    44.          case SerializedPropertyType.Vector2:
    45.            p.vector2Value = (Vector2) value;
    46.            break;
    47.          case SerializedPropertyType.Vector3:
    48.            p.vector3Value = (Vector3) value;
    49.            break;
    50.          case SerializedPropertyType.Vector4:
    51.            p.vector4Value = (Vector4) value;
    52.            break;
    53.          case SerializedPropertyType.Rect:
    54.            p.rectValue = (Rect) value;
    55.            break;
    56.          case SerializedPropertyType.ArraySize:
    57.            p.intValue = (int) value;
    58.            break;
    59.          case SerializedPropertyType.Character:
    60.            p.stringValue = (string) value;
    61.            break;
    62.          case SerializedPropertyType.AnimationCurve:
    63.            p.animationCurveValue = value as AnimationCurve;
    64.            break;
    65.          case SerializedPropertyType.Bounds:
    66.            p.boundsValue = (Bounds) value;
    67.            break;
    68.          case SerializedPropertyType.Gradient:
    69.            Debug.LogWarning((object) "Get/Set of Gradient SerializedProperty not supported");
    70.            break;
    71.          case SerializedPropertyType.Quaternion:
    72.            p.quaternionValue = (Quaternion) value;
    73.            break;
    74.        }
    75.      }