Sunday, January 8, 2017

Animation Copies!

Dear Unity Engine,

You can't copy one animator onto a new sprite sheet? Really? ... Which the utmost respect, what the hell is wrong with you?

So, this is something I've been facing (and avoiding) for the last month or two: I have a ton of identical sprite sheets for different skin colors, hair colors, hair styles, different clothes. Each one has several different animations (idle, walk, cast spell, stab, thrust, shoot bow, die/hurt), and each one of those have four directions they could be facing, not to mention different sprite sheets for men, women, and children. So, assuming two hairstyles in four colors, five skin colors, two possible outfits... we're already looking at 2240 animations, not counting the children's walk cycle and hair and such (2 * 4 * 5 * 2 * 7 * 2 * 2).

2240 is not a nice number. Even though it only takes me about thirty seconds to set up each animation's Animator, that's still nearly 19 hours of animation prep. No. Uh uh. I refuse.

So every few days, I've been thinking that maybe, if I could just figure out how to phrase this problem in google, I could get a magic shortcut from some clever person who's come before me. Duplicating animations / animators is a waste of time, since the new animators point to the old animations, and it takes nearly as long to reset them all. Using an Animator Override still requires you to define each animation for each item. I needed a way to define it once and move on.

... So, it turns out that Unity doesn't support 2d Animator duplication (which is a huge oversight, in my opinion). BUT, there is a hacky workaround: a script on each animated character that replaces the default sprite with the correct one. ... Which is a bit of a memory/CPU hog and probably shouldn't be used for smartphone games, but it works.

I modified this code from a Unity conference video on workarounds for common 2d problems. Just in case anyone's struggling with the same thing.


using UnityEngine;
using System.Collections.Generic;

public class ReskinAnimation : MonoBehaviour {

public string spriteSheetName;
SpriteRenderer spriteRenderer;
Dictionary<string, Sprite> sprites;

void Start() {
sprites = new Dictionary<string, Sprite>();
this.spriteRenderer = this.GetComponent<SpriteRenderer>();
Sprite[] spriteList = Resources.LoadAll<Sprite>("Humans/" + spriteSheetName);

foreach(Sprite sprite in spriteList) {
this.sprites.Add(sprite.name, sprite);
}
}

void LateUpdate() {
string spriteName = spriteRenderer.sprite.name;

Sprite newSprite = null;
if (sprites.ContainsKey(spriteName)) {
newSprite = sprites[spriteName];
} else {
Debug.Log("Sprite not found: " + spriteName);
}


if (newSprite != null) {
spriteRenderer.sprite = newSprite;
}
}
}


No comments:

Post a Comment