Replace Texture sheet with scripting?

Hi, I would like to replace a stylesheet that has all the textures for my character, with a simular texture, but with diffrent clothes.

What would be ideal is to replace the “Livingfor.it Main - Sheet” texture with another one, that would change all the sprites. If you have other solutions of solving this, that would be very helpfull too.

Btw, im new to Unity. Thanks in advance!


So, to start with the most basic possible use case, you can easily replace a sprite like this:

public SpriteRenderer sr;
public Sprite newSprite;
void Start() {
sr.sprite = newSprite;
}

Drag your SpriteRenderer (from the GameObject) into the sr slot in the inspector, drag your desired sprite into newSprite, and bam.

Obviously, you’re going to want a little bit more advanced application, and we’re going to get into data design here. You’re probably going to want:

  1. The ability to access a matching sprite. (e.g. to replace left arm with the new left arm)
  2. The ability to access different sprite sets as a group. (e.g. these are Bob’s parts, these are Frank’s parts)
  3. The ability to easily add new sets (new character unlocked!)

Let’s start with #1. The best way to do this will probably be to use the name of the sprite, which you can access (in the above code) with newSprite.name, or more usefully, sr.sprite.name. You can use this to find the sprite of the new set that has the matching name.

#2 can easily be done if your sprites are coming from a spritesheet per set (as the posted image suggests), or if not, then you can put the sprites in a folder in Resources.

#3, likewise, is easy if you put them in Resources.

Let’s split this into two parts: 1) Figuring out which sprite you want for a given SpriteRenderer, and 2) retrieving that sprite. Also 3) assigning it back, which (maybe counterintuitively) should be thought of as part of 1.

#1 + #3 are pretty easy - use the name of the sprite that’s already there! And we can use this to loop through all the SpriteRenderers in our hierarchy:

private SpriteRenderer[] allRenderers;
public string newSpriteSetName = "Bob";
void Start() {
allRenderers = GetComponentsInChildren<SpriteRenderer>();
for (int r=0;r<allRenderers.Length;r++) {
string thisPartName = allRenderers[r].sprite.name;
Sprite newSprite = RetrieveSprite(newSpriteSetName, thisPartName);
if (newSprite != null) allRenderers[r].sprite = newSprite;
}
}

public void RetrieveSprite(string setName, string partName) {

A neat feature of this code is that you only need to override sprites you want to override. Maybe Bob has his own watch, but Frank just uses the default. Maybe your default pants work fine for Joe and Steve, but Frank has his own style. If this script doesn’t find a replacement sprite under a given name, it’ll leave the default one there.

Now we just need to write RetrieveSprite. This implementation is going to vary based on how your sprites are to be set up. I’m going to assume that you have a texture sheet as shown for each character, and that you’ve separated it into sprites in the Sprite Editor. With the strategy I’m laying out, it’s important that all your sprites use the same names (capitalization, etc matter!) to identify each part.

You can use this to get an array of all the sprites in a given sprite sheet, assuming your sheet is located in the root of a Resources folder, and named to match your setName (which comes from newSpriteSetName in the above code):

Sprite[] thisSet = Resources.LoadAll<Sprite>(setName);

From there, you can loop through and check each sprite’s .name against your desired partName; if they match, return that sprite.

Optimization: This won’t be the fastest way to go about this. If you want to be faster, then BEFORE your main loop (through the SpriteRenderers), call Resources.LoadAll and then loop through those, adding each one to a dictionary with its name as the key. Then reuse that same dictionary for each replaced sprite, which will be much faster.