3
\$\begingroup\$

I have a number of sprites that I generate outside of Unity. I'd like to automate the process of importing these sprites into Unity as fully-configured game objects. I'm trying to do this through a Unity editor script, but I'm having some difficulty. When I run my script, my game object is saved as a .prefab as expected. However, the Sprite I'm assigning to my game object's SpriteRenderer component is missing:

Unity screenshot

In my script, I'm assigning my SpriteRenderer's sprite property to a Sprite object that I dynamically create in the script. Here's the relevant excerpt from my editor script:

GameObject gameObject = new GameObject(fileName);

SpriteRenderer spriteRenderer = gameObject.AddComponent<SpriteRenderer>();

// texture size will be replaced during the LoadImage() call
Texture2D texture = new Texture2D(1, 1);
texture.LoadImage(File.ReadAllBytes(Path.Combine(generatedOutputPath, fileName + ".png")));

spriteRenderer.sprite = Sprite.Create(
    texture, 
    new Rect(0.0f, 0.0f, texture.width, texture.height),
    new Vector2(0.0f, 0.0f)
);

PrefabUtility.CreatePrefab("Assets/Prefabs/" + fileName + ".prefab", gameObject);
DestroyImmediate(gameObject);

I can verify through logging that the image path to my .png is correct and that the Texture2D and Sprite objects seem to be instantiated correctly. For example, I can do this:

// logs "580" as expected
Debug.Log(texture.width);

What am I doing wrong? How can I save this game object as a .prefab without losing its sprite information?

\$\endgroup\$
2
  • 3
    \$\begingroup\$ I'm guessing that the problem is that the texture can't be serialized. It's loaded from an arbitrary location and thus doesn't exist in the asset path, so Unity can't create a reference to deserialize later. \$\endgroup\$ May 30, 2017 at 20:24
  • 1
    \$\begingroup\$ Have you tried actually instantiating the prefab to see if it works? Hints here that talk about using PrefabUtility.InstantiatePrefab when later creating the prefab. \$\endgroup\$
    – House
    May 30, 2017 at 21:04

1 Answer 1

1
\$\begingroup\$

Figured it out. I needed to first copy my images into the Assets/Resources directory, and then use Resources.Load<Sprite>("path/to/sprite/here") to load my Sprite instance (instead of loading them from an arbitrary location on the file system). Here's my updated script:

// "files" is a List<string> of file names to load as Sprites.
// first, copy each image to the "Assets/Resources/Sprites" directory
files.ForEach(fileName => {
    File.Copy(
        Path.Combine(generatedOutputPath, fileName + ".png"),
        Path.Combine("Assets/Resources/Sprites", fileName + ".png"),
        true
    );
});

// refresh our AssetsDatabase since we made changes.
AssetDatabase.Refresh();

// for each file, create a new GameObject to hold the loaded Sprite
files.ForEach(fileName => {
    GameObject gameObject = new GameObject(fileName);
    SpriteRenderer spriteRenderer = gameObject.AddComponent<SpriteRenderer>();
    spriteRenderer.sprite = Resources.Load<Sprite>("Sprites/" + fileName);
    PrefabUtility.CreatePrefab("Assets/Prefabs/" + fileName + ".prefab", gameObject);
    DestroyImmediate(gameObject);
});

A big thanks to Draco18s and Byte56 for their comments, which pointed me in the right direction. The example script in this write-up also helped me get my script straightened out.

\$\endgroup\$

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .