Custom Icon on ScriptableObject
Asked Answered
C

6

0

Hey guys, i doing some itens for my game make the development easer, i wish add custom icons to my itens, which are ScriptableObjects, how i can do this? i know the trick of put the icon on Gizmo folder with the same name as the script, but the icons should be different for different itens which have the same script

Conley answered 25/2 at 10:16 Comment(0)
C
0

Hi there @Conley. You can do it without the Gizmos folder. Just select the ScriptableObject script (not the ScriptableObject asset!) and select its icon in the Inspector. That will change that script’s icon as well as all icons of respective ScriptableObject assets!

Additionally, you can visit this thread for more info, it has lots of gold in it: https://forum.unity.com/threads/custom-scriptableobject-icons-thumbnail.256246/

Cuticle answered 6/6, 2023 at 2:41 Comment(4)

Hi, i'm working on a cards game where there are different "roles". Every scriptable object needs to have a custom image. How do i do it?

Invigorate

Im not understanding this?

Roice

This works. However, existing instances of the ScriptableObject were not updated (i.e. it only applied to the ScriptableObject assets I created after changing the icon). Didn't try restarting Unity though, so that may fix that issue.

Diffusive

Can confirm, restarting Unity fixes existing ScriptableObject icons. Tested on 2022.3.12f1.

Psychotechnology
I
0

Hi, i’m working on a cards game where there are different “roles”. Every scriptable object needs to have a custom image. How do i do it?

Invigorate answered 26/9, 2023 at 17:24 Comment(2)

Add an 'image' property. From your game, load it into the UI.

Invigorate

Looks like there's a new API for this in 2021.2! https://docs.unity.cn/2021.2/Documentation/ScriptReference/EditorGUIUtility.SetIconForObject.html

Tunic
T
0

There is a new API for this in 2021.2 that might do what you are looking for. It even tells you how to make it persistent across script reloads :wink:

Edit: Okay so it turns out this is really really jank. As far as I can tell, Unity doesn’t want you to instance these icons. On compile/load, all of the assets will be set to the same icon, even if you properly set each one individually. You have to inspect them by clicking on them individually to get them to update to their true icons. If anyone has a solution to this please let me know :confused:

Tunic answered 3/11, 2021 at 1:32 Comment(1)

Set fractionofjourney yo 0 ya te start. Smooth speed Is a constant? The code was untested but seems fine to me, ill test it tommorrow

Trickster
C
0

Hi.

It’s possible!

Short history:

I downloaded and explore this project:

I noticed that in this project, icons from scriptable objects are displayed in the inspector:
197008-example-0.png

After, i found some editor script, and edited him for my project.

I don’t understand how it works, but it works. =)
197009-primer.png

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEditor;
using System;
using System.Reflection;
using Object = UnityEngine.Object;

[CustomEditor(typeof(item_so),true)]
[CanEditMultipleObjects]
public class ItemSOEditor : Editor
{
    private item_so item { get { return (target as item_so); } }

    public override Texture2D RenderStaticPreview(string assetPath,Object[] subAssets,int width,int height)
    {
        if(item.standart_item_struct.item_icon!=null)
        {
            Type t = GetType("UnityEditor.SpriteUtility");
            if(t!=null)
            {
                MethodInfo method = t.GetMethod("RenderStaticPreview",new Type[] { typeof(Sprite),typeof(Color),typeof(int),typeof(int) });
                if(method!=null)
                {
                    object ret = method.Invoke("RenderStaticPreview",new object[] { item.standart_item_struct.item_icon,Color.white,width,height });
                    if(ret is Texture2D)
                        return ret as Texture2D;
                }
            }
        }
        return base.RenderStaticPreview(assetPath,subAssets,width,height);
    }

    private static Type GetType(string TypeName)
    {
        var type = Type.GetType(TypeName);
        if(type!=null)
            return type;

        if(TypeName.Contains("."))
        {
            var assemblyName = TypeName.Substring(0,TypeName.IndexOf('.'));
            var assembly = Assembly.Load(assemblyName);
            if(assembly==null)
                return null;
            type=assembly.GetType(TypeName);
            if(type!=null)
                return type;
        }

        var currentAssembly = Assembly.GetExecutingAssembly();
        var referencedAssemblies = currentAssembly.GetReferencedAssemblies();
        foreach(var assemblyName in referencedAssemblies)
        {
            var assembly = Assembly.Load(assemblyName);
            if(assembly!=null)
            {
                type=assembly.GetType(TypeName);
                if(type!=null)
                    return type;
            }
        }
        return null;
    }
}
Comprador answered 29/3 at 17:4 Comment(2)

My friend, your solution is exactly what I was looking for, and has worked flawlessly for adding custom icons to ScriptableObject assets.

Kazachok

This almost works perfect except for the fact that really tiny sprites (like 8x8) appear very small. Is there a way to scale it up? Simply changing the width and height does not work

Jackofalltrades
M
0

if your current Unity version doesn’t publicly expose EditorGUIUtility.SetIconForObject

here’s a utility window that makes use of the same API using Reflection:

using System.Reflection;
using UnityEditor;
using UnityEngine;


internal class EditorGUIUtilityInternals : EditorWindow
{
    private MethodInfo setIcon, getIcon, copyIcon;
    private Texture2D icon;
    private Object target;
    private bool hasIcon;
    
    
    [MenuItem("EditorGUIUtility/Internals/SetIconForObject")]
    private static void GetWindow()
    {
        var rect = new Rect(Screen.width/2F, Screen.height/2F, 350F, 130F);
        const string title = "EditorGUIUtility Internals";
        
        GetWindowWithRect<EditorGUIUtilityInternals>(rect, true, title, true).ShowUtility();
    }
    
    
    private void OnEnable()
    {
        const BindingFlags bindings = BindingFlags.NonPublic | BindingFlags.Static;
        var utility = typeof(EditorGUIUtility);
        
        setIcon = utility.GetMethod("SetIconForObject", bindings);
        getIcon = utility.GetMethod("GetIconForObject", bindings);
        copyIcon = typeof(MonoImporter).GetMethod("CopyMonoScriptIconToImporters", bindings);
    }
    
    
    private void OnGUI()
    {
        EditorGUI.BeginChangeCheck();

        target = EditorGUILayout.ObjectField("Target Object", target, typeof(Object), true);

        if (target && EditorGUI.EndChangeCheck()) RefreshHasIcon();
        
        EditorGUILayout.Space(EditorGUIUtility.singleLineHeight);
        
        icon = (Texture2D)EditorGUILayout.ObjectField("Icon", icon, typeof(Texture2D), false);

        EditorGUILayout.BeginHorizontal();
        {
            GUI.enabled = target && icon;
            if (GUILayout.Button("Set Icon For Target"))
                SetOrRemoveIconForObject(icon); // Assign

            GUI.enabled = hasIcon;
            if (GUILayout.Button("Remove Icon From Target"))
                SetOrRemoveIconForObject(); // Unset
        }
        EditorGUILayout.EndHorizontal();
    }
    
    
    private void SetOrRemoveIconForObject(Texture2D texture = null)
    {
        var message = texture == null
            ? $"{target.name}'s Icon is About to be Unbound from"
            : $"{icon.name} is About to be Bound to {target.name}";
        
        if (EditorUtility.DisplayDialog(titleContent.text, message, "Gotcha!", "Nope..."))
        {
            setIcon?.Invoke(null, new[] { target, texture });
            
            var targetPath = AssetDatabase.GetAssetPath(target);
            
            var importer = (MonoImporter)AssetImporter.GetAtPath(targetPath);
            
            _ = copyIcon?.Invoke(null, new[] { importer.GetScript() });
            
            importer.SaveAndReimport();
            
            RefreshHasIcon();
        }
    }
    
    
    private void RefreshHasIcon()
    {
        var tempIcon = (Texture2D)getIcon?.Invoke(null, new[] { target });
        
        hasIcon = tempIcon != null;
    }
}

how to display the utility and a preview of:

how to display the utility and a preview of

Malicious answered 21/6, 2023 at 14:20 Comment(0)
M
0

Use EditorGUIUtility.SetIconForObject is just working. Just do somethin like this:

[CreateAssetMenu(fileName = "NewCustomScriptableObject", menuName = "YourMenu/CustomScriptableObject")]
public class TestSO : ScriptableObject
{
    public int A;

    private void OnEnable()
    {
        Texture2D icon = AssetDatabase.LoadAssetAtPath<Texture2D>("Assets/Games/Gizmos/TestSO Icon.png");
        EditorGUIUtility.SetIconForObject(this, icon);
    }
}

and whenever you create a SO asset then it’ll show up with custom icon.

Monda answered 25/2 at 2:23 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.