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
    \$\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\$ – Draco18s no longer trusts SE May 30 '17 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\$ – MichaelHouse May 30 '17 at 21:04
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.

| improve this answer | |
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.