- Home /
How to create custom asset icons for ScriptableObject instances
I have an item database consisting of several ScriptableObjects of type Item
. These items have a public Sprite icon;
field, and the behavior I want is for the icon for each asset to reflect the contents of the icon Sprite.
Currently, I am using EditorGUIUtility.SetIconForObject(asset, icon.texture);
to accomplish this, but I am running into some strange issues with this that I can't pinpoint the cause of.
Here is my current script:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEditor;
namespace InventorySystem
{
[InitializeOnLoad]
public class InventorySystemEditorUtils
{
static InventorySystemEditorUtils()
{
List<Item> items = FindAssetsByType<Item>();
items.ForEach(item =>
{
Item obj = AssetDatabase.LoadAssetAtPath<Item>(AssetDatabase.GetAssetPath(item));
UpdateAssetIcon(obj, item.icon);
});
}
public static List<T> FindAssetsByType<T>() where T : Object
{
List<T> assets = new List<T>();
string[] guids = AssetDatabase.FindAssets(string.Format("t:{0}", typeof(T)));
for (int i = 0; i < guids.Length; i++)
{
string assetPath = AssetDatabase.GUIDToAssetPath(guids[i]);
T asset = AssetDatabase.LoadAssetAtPath<T>(assetPath);
if (asset != null)
{
assets.Add(asset);
}
}
return assets;
}
public static void UpdateAssetIcon(Object asset, Sprite icon)
{
if (icon && icon.texture)
{
EditorGUIUtility.SetIconForObject(asset, icon.texture);
}
}
}
}
Desired behavior: On load, take each Item and replace its asset icon with the appropriate item icon.
Actual behavior: On load, the icon for each item is set to whichever one was processed last.
Any idea what's going on here?
Answer by oscarAbraham · Nov 03, 2021 at 09:08 PM
You can't. The icon is set on the MonoScript, so it's shared between all instances of the same class.
You can try using RenderStaticPreview, but it has some quirks, like it doesn't show for thumbnails in the object picker. The quirks change sometimes with the Unity Editor version. It could work for you, at least partially, depending on your use case.
Yup, I was able to confirm this now. EditorGUIUtility.SetIconForObject() is applicable only for GameObjects and MonoScript - also custom icons for GameObjects are saved in the scene (so not compatible with AssetDatabase assets).
Meanwhile, Editor.RenderStaticPreview() worked just fine with the example code provided in the docs (however, no icon preview in the Inspector or Select dialog; only in the Project window). Thanks @oscarAbraham
Answer by iohouse · Nov 03, 2021 at 06:22 AM
Try moving the [InitializeOnLoad] attribute to the static constructor.
From the manual "Static constructors with this attribute are called when scripts in the project are recompiled" (when Unity loads, and when your scripts are recompiled). https://docs.unity3d.com/ScriptReference/InitializeOnLoadAttribute.html
Thanks for your quick input!
The [InitializeOnLoad]
attribute is only valid on class definitions. You are correct, however, that this will tell Unity to call the static constructor for the class when scripts are recompiled.
The "when" of the behavior is not the issue here, but more so the "what". EditorGUIUtility.SetIconForObject
seems to be statically setting the icon for the class overall, even though I am passing in an instance.
Yeah, misplaced, it's been a while since I used this attribute and relied on the docs. Heh, I wasn't sure from your post if the code was actually verified to at least be executing.
Have you tried using AssetDatabase.GetCachedIcon() to verify the setting?
If I have some time I'll experiment with the code to see if I get a different result than what you're seeing.
Your answer
Follow this Question
Related Questions
Converting XML-files into assets 1 Answer
Could not load copied asset via AssetDatabase.LoadAssetAtPath 4 Answers
Editor GUI object field stops working 0 Answers
Prevent changes in ScriptableObject type Asset in Editor. Dont save it. 0 Answers
Error using ImportAssetOptions.ForceSynchronousImport 2 Answers