Search Unity

  1. Megacity Metro Demo now available. Download now.
    Dismiss Notice
  2. Unity support for visionOS is now available. Learn more in our blog post.
    Dismiss Notice

Changing Animation Sprites

Discussion in '2D' started by Danimita92, Nov 26, 2013.

  1. Danimita92

    Danimita92

    Joined:
    Jan 25, 2010
    Posts:
    32
    Hi everyone!

    I have a quick question regarding sprite animation in Unity's new 2D features.

    Say I have a character's sprite sheet with different animations (idle, walk, jump, etc.) and I have a similar sprite sheet (same character, different armor) with the same ammount of frames and animations. The only thing that changes is the texture.

    I have seen that to make 2D animations you have to drag the sprite's frames into the animation timeline, but what if I have loads of different characters with the same animations? Would I have to create new animations in the editor for each one of the different versions of the same character?

    Thanks for your time!
     
    rakkarage likes this.
  2. Danimita92

    Danimita92

    Joined:
    Jan 25, 2010
    Posts:
    32
    Nobody knows? Is it impossible to do this in Unity's sprites system?

    How about with animation events? Would it be expensive performance-wise to change sprites via animation events and code?
     
  3. guykogus

    guykogus

    Joined:
    Aug 12, 2013
    Posts:
    5
    You could programmatically create the animations by adding curves and setting the values to the appropriately named sprites, loading each texture one at a time. Probably not a good way to go about doing this.

    If you're redrawing each animation depending on the character's armour, you may then want to have a separate animation per armour, and trigger those animations based on the current armour.

    Hope that helps :\
     
  4. keely

    keely

    Joined:
    Sep 9, 2010
    Posts:
    967
    We don't offer nice built-in workflow in 4.3 for this.

    There are different ways to achieve this "manually", but it requires some scripting on your part.

    We are researching how to make a nice built-in workflow, but I can't really say anything more specific at this point.
     
  5. Danimita92

    Danimita92

    Joined:
    Jan 25, 2010
    Posts:
    32
    Oh, well. Thanks for the reply.

    To achieve it manually, what would be the most efficient way? With animation events that change sprites for others in an array, perhaps?
     
  6. cpavanelli

    cpavanelli

    Joined:
    Apr 11, 2013
    Posts:
    6
    Hi, I know you posted a while ago, but I will share what I have done when I faced the same problem.

    I was going to use sprite sheets to animate my characters, but in order to my character be customizable, I had to:

    1. slice the character in body parts

    2. Created animations using the parts

    3. On the code (start method), loaded the specific png(sprite) from resources folder and set it to the sprite gameobject. (only in cases that it need to be different, like an armor instead of the regular body).


    Also, I'm not sure this works if your animation is changing sprites (like handClosed to handOpen).
     
  7. Akika

    Akika

    Joined:
    Sep 18, 2013
    Posts:
    2
    Could you please at least give us some ideas about that "scripting on our part".. I have 50+ different characters with 40+ base animations in my game, and it pains me just to think about making 2000+ animations, 50+ animator graphs. I will appreciate any help here. If a full scale tutorial is time-costly, could you please just point out some basics. Thanks in advance.
     
    eaglethrust and rakkarage like this.
  8. jjarmis

    jjarmis

    Joined:
    Feb 25, 2014
    Posts:
    2
    I have the same need and have yet to figure out a good workaround. If anyone has figured this out without making thousands of animators, I would love to see some sample code.

    - Thank you -
     
    rakkarage likes this.
  9. Loius

    Loius

    Joined:
    Aug 16, 2012
    Posts:
    546
  10. jjarmis

    jjarmis

    Joined:
    Feb 25, 2014
    Posts:
    2
    That looks cool. Two things.

    I cant find it in the asset store.

    From what I've seen in the video, it doesn't solve the original issue. Which is to change from one sprite sheet to another using the same animation files during run time. That way if we have say 500 different sheets with a different character on each, and all the same frames, we only have to setup one animation set instead of 500.
     
  11. Loius

    Loius

    Joined:
    Aug 16, 2012
    Posts:
    546
    It hadn't gotten through Unity's vetting process yet - It's available now, though; more info in this thread.

    The SpriteSheet component actually stores animations (it's completely separate from Mecanim). Once you have a SpriteSheet with its animations set up, you can swap in a new texture in a duplicate object. So you could have, say, a blue enemy, then recolor it and save as a new texture - you could plug that new texture in to populated SpriteSheet and have a working sheet without having to rebuild the animations.

    The sheet does still have to acquire its sprites in the Editor; my code-fu has not found a way to find sprites at runtime yet. But you can make a bunch of duplicate SpriteSheets with different textures. The only thing that's important is that the sprites be in the same order.
     
    Last edited: Mar 1, 2014
  12. Akika

    Akika

    Joined:
    Sep 18, 2013
    Posts:
    2
    Ok, to all people, who want 50+ similar animations of 50+ characters,and want it right now, without waiting some "nice workflows" to come.
    Give up on mecanim. I did. Just used SpriteManager (http://wiki.unity3d.com/index.php?title=SpriteManager). It's free, powerfull and opensource. I've added some stuff, like sharing spritesheet regions and advanced z-ordering, and it became even more sexy. And it took me just one day to rewrite all my animation mechanisms, so that project is alive and kicking.
     
  13. enhawk

    enhawk

    Joined:
    Aug 22, 2013
    Posts:
    833
    Having same problem, this feature is badly needed for the next version of Unity!
     
  14. v-line

    v-line

    Joined:
    Feb 13, 2013
    Posts:
    10
    I'm going to implement armor in my project.
    The best solution I've got is to create separate objects for each part of a character and make a separate animator for each part.
    If a character changed his helmet, the appropriate object with its own animator should replace the default head object.
    However will take some time to manually create animators.
     
  15. marceloSpiezzi

    marceloSpiezzi

    Joined:
    Nov 12, 2012
    Posts:
    6
    I've been searching a lot about this too, found the answer here (at 20:00)

     
  16. StarManta

    StarManta

    Joined:
    Oct 23, 2006
    Posts:
    8,773
    Correct me if I'm wrong, but it doesn't look like that technique will work on sprite animations.
     
    Luis0413, viseztrance and Menion-Leah like this.
  17. Yagef

    Yagef

    Joined:
    Jul 2, 2014
    Posts:
    1
    I used this method for my project and it worked perfectly. Very useful lection
     
    Last edited: Jul 2, 2014
  18. zgamesoft

    zgamesoft

    Joined:
    Jun 3, 2013
    Posts:
    1
  19. Most_Incredible

    Most_Incredible

    Joined:
    Jan 25, 2012
    Posts:
    36
    Hi,
    Do we have any better workflow in the latest Unity version on this.Kindly throw some light on this.
    Thanks
     
  20. AlexBM

    AlexBM

    Joined:
    Mar 26, 2015
    Posts:
    16
    I think I found quite simple solution for that. Not super-efficient, but still it may save you a lot of time as it's very easy to implement.

    The main idea is to use current sprite name in animation as a key to lookup in Dictionary of sprites with different skins. In terms of code is something like that

    Code (CSharp):
    1.  
    2. void LateUpdate()
    3. {
    4.  // heavyArmorSkin is a Dictionary with skinned sprites
    5.  BodySprite.sprite = heavyArmorSkin[BodySprite.sprite];
    6. }
    7.  
    So basically, each Update Animator changes a sprite according it's internal state, and you use this sprite name as a key for the actual sprite of your skin and replace it.
     
  21. MerlinsMaster

    MerlinsMaster

    Joined:
    Jan 15, 2015
    Posts:
    33
    Hey, man. Any chance you could show your entire script? It would be great to see it in context.
     
  22. DarkCooker

    DarkCooker

    Joined:
    Jan 7, 2015
    Posts:
    119
    Hi How's the performance in game?
    From profiler, I see the LateUpdate eats up 2% CPU usage and 21.1KB GC alloc.
    Not sure if you have try it in production environment, thank you.
     
  23. churi24

    churi24

    Joined:
    Sep 17, 2013
    Posts:
    98
    Maybe this code could help you.. I don't know if performance in your case is a must, but this work.
    If you name the sprite as Warrior, the substrings will have this form... Warrior_0, Warrior_1, ... , Warrior_n
    so I take the index with this line renderer.sprite.name.Substring(8) and then I replace the sprite. With this you dont need to made separated animations.

    Code (CSharp):
    1. public class ReskinAnimator : MonoBehaviour
    2. {
    3.     public Sprite[] subSprites;
    4.    
    5.     void LateUpdate()
    6.     {
    7.         foreach (var renderer in GetComponentsInChildren<SpriteRenderer>())
    8.         {
    9.             renderer.sprite = subSprites[int.Parse(renderer.sprite.name.Substring(8))];
    10.         }
    11.     }
    12. }
     
    Zelek and Most_Incredible like this.
  24. retry_entry

    retry_entry

    Joined:
    Nov 7, 2016
    Posts:
    1
    Hi guys. Please tell me where I am wrong... Cause I have found a solution and using it to a great success...
    Ramaging through sprites in LateUpdate kinda... Ehm... What is this really?
    I use shader and pick swapped texture with main texture UVs...
    U can check it here - https://github.com/RetryEntry/UnityAnimatorChangeSprite
    Give stars please or tell me why it sucks... :/
     
  25. danrayson

    danrayson

    Joined:
    Mar 3, 2013
    Posts:
    10
    This is exactly the answer, fantastic!! Production env not tested...

    I used this code:

    Code (CSharp):
    1.     private void SetTheCorrectSpriteForThisObject()
    2.     {
    3.         string path = "Graphics/Characters/" + Statistics.Race + "/" + Statistics.Class;
    4.         Sprite[] allSubSprites = Resources.LoadAll<Sprite>(path);
    5.      
    6.  
    7.         overrideSprite = allSubSprites.FirstOrDefault(s => s.name.Equals(SpriteRenderer.sprite.name));
    8.         if (overrideSprite)
    9.         {
    10.             SpriteRenderer.sprite = overrideSprite;
    11.         }
    12.     }
    And made sure I had sprites whos sub-sprites where called the same names, e.g. Idle1, Idle2, etc. That's it
     
  26. GoblinGameWorks

    GoblinGameWorks

    Joined:
    Sep 14, 2019
    Posts:
    13
    So if your new sprite sheet has more sprites like other dangling accessories or an extra arm etc. I don't believe this method will work... or at least I haven't found the workaround yet. In my case i have 5 faces that I need to add to the sprite sheet.

    I animated a very long and complicated sequence, a sprite sheet with 7 sprites which were all connected as bones but without a face on the character and thought I could maybe add the face later (think I got confused by a YT video I watched).

    Well problem is the head moves so much and trying to get the face to stay in the right place while the character is moving is challenging (not impossible) but it seems so inefficient to do it manually like that. I thought for sure there's a better way.

    Copying the transform or "childing" the faces to the sprite game object doesn't work because the animated sprite's transform's rotation never changes, however the head bone rotates and changes position like crazy.

    I wish I would have foreseen this issue and simply included all the faces on top of each other when creating the sprite initially and while creating the bones I could have made each face use the head bone as its sole "influencer" then simply turn the faces on and off from the inspector during the animation this way the faces rotate and follow the head bone regardless where it is in the scene.

    example: character is happily walking smiling then starts to lose balance and begins to stumble so face changes to fearful, regains balance face changes to sigh of relief, then face changes to a more joyful face than at the start.
     
    eaglethrust likes this.
  27. castor76

    castor76

    Joined:
    Dec 5, 2011
    Posts:
    2,517
    Tagging along here... to my dismay, accessing sprite.name causes GC allocation everytime! Anyone with bright idea how to avoid this?
     
  28. StarManta

    StarManta

    Joined:
    Oct 23, 2006
    Posts:
    8,773
    Why do you need to frequently access sprite.name?
     
  29. castor76

    castor76

    Joined:
    Dec 5, 2011
    Posts:
    2,517
    I am also doing what others doing here, basically.. I am using the current sprite's name to override it with other one so I can swap sprites on demand. I could ofcourse create animations for each different sprites and then make animation controller override, but It's just way too many animation assets and controllers are needed to be made which I want to avoid. So like others here before, I want to override the current sprite on Sprite Renderer to replace it with other Sprite with similar naming convention.
     
  30. StarManta

    StarManta

    Joined:
    Oct 23, 2006
    Posts:
    8,773
    You could do a dictionary lookup using the first sprite as the key. You'd get the GC only one for each sprite.
    Code (csharp):
    1. private Dictionary<Sprite, Sprite> spriteReplacementLookup = new Dictionary<Sprite, Sprite>();
    2. public Sprite GetReplacementSprite(Sprite orig, string replacementFolderPath) {
    3.    if (spriteReplacementLookup.ContainsKey(orig) ) return spriteReplacementLookup[orig];
    4.    Sprite loadedSprite = Resources.Load<Sprite>(replacementFolderPath + "/" + orig.name); // Or however it is you load your replacement sprites
    5.    spriteReplacementLookup.Add(orig, loadedSprite);
    6.    return loadedSprite;
    7. }
    (typed into forum text box & untested)
     
  31. castor76

    castor76

    Joined:
    Dec 5, 2011
    Posts:
    2,517
    Problem with this approach, is that when your sprites are in atlas, it seems like Unity Animator when it updates the sprite on the Sprite Renderer, it gets off from the AtlasManager, of some sort, and then it's instance is different every time it updates the Sprite Renderer. ( even if the Sprite is the same one, for every frame, it gets the sprite off from atlas and they are different instances ... ) So using sprite as key is not going to work, I am afraid.

    ( and to me , why Unity does this to the Sprites if it is using atlas is beyond me.. would it not cause some gc issue? )
     
  32. StarManta

    StarManta

    Joined:
    Oct 23, 2006
    Posts:
    8,773
    Really? That seems like a bug...
     
  33. castor76

    castor76

    Joined:
    Dec 5, 2011
    Posts:
    2,517
    It does sounds a bit weird, but if you take a look at the doc on Sprite Atlas, it says it clones sprite and returns it every time it is being asked for one. I could ofcourse query all sprites and then cache it myself for my own usage so that there is no more clones being created, but I have no control on how Unity Animator is fetching the sprites from so I think it is why sprite's instance is changing all the time. I think Unity Animator is not caching anything. I think it is just asking SpriteAtlas to get a sprite and then oh well... SpriteAtlas gives back cloned version every time.
     
  34. slkjdfv

    slkjdfv

    Joined:
    Oct 23, 2010
    Posts:
    435
    I had a similar issue when making my 2.5D game, my character is split up into different sprites and I made a custom sprite animation class cause Unity's system didn't support my needs. It's not fancy and could be more optimized but It works. I can send it to you if you'd like.
     
  35. KokodokoGames

    KokodokoGames

    Joined:
    May 20, 2014
    Posts:
    40
    Just wondering, has this been addressed in Unity 2020? How can we easily assign other sprites to existing animation clips, without creating new clips and override animators for each possible sprite that we might want to use? I just need the sprite images to remain variable. (for example, by making it a public variable of a prefab that you can set in the editor).
     
  36. MauricioEF

    MauricioEF

    Joined:
    Sep 4, 2020
    Posts:
    10
    Hi ! Still not answer for this?
     
  37. Ted_Wikman

    Ted_Wikman

    Unity Technologies

    Joined:
    Oct 7, 2019
    Posts:
    906
  38. MauricioEF

    MauricioEF

    Joined:
    Sep 4, 2020
    Posts:
    10
    Hi, thanks for replying. I reviewed the information of the 2d Animation package, but I still can't understand how can I handle multiple animations when moving, attacking, etc. I See that the examples only show a single animation, but not how to handle an animation controller to do more than one animations
     
  39. Ted_Wikman

    Ted_Wikman

    Unity Technologies

    Joined:
    Oct 7, 2019
    Posts:
    906
    If you look closer, you will see that the example contains two clips:
    - Idle
    - Attack
    The structure, as described in the documentation is as follows:
    1 Sprite Library Asset per Character type
    1 Category per Animation/Clip
    1 Label per frame

    If you create a knight and an orc, both having an idle and an attack clip, the structure would look like this:

    Knight Sprite Library Asset
    - Category: Idle
    - Label: 0
    - Label: 1
    - Label: 2
    - Label: 3​
    - Category: Attack
    - Label: 0
    - Label: 1
    - Label: 2
    - Label: 3​

    Orc Sprite Library Asset
    - Category: Idle
    - Label: 0
    - Label: 1
    - Label: 2
    - Label: 3​
    - Category: Attack
    - Label: 0
    - Label: 1
    - Label: 2
    - Label: 3​

    In the scene, you can create a new GameObject with the following components attached to it:
    - Sprite Library Component
    - Sprite Renderer
    - Sprite Resolver
    Then assign either the Knight or Orc Sprite Library Asset in the Sprite Library Components Library slot.

    When creating the idle clip, you start recording and on the first frame you set the Sprite Resolver's Category to Idle and the label to 0. On the second frame, you keep the Category set on Idle but change the Label to 1, and so on. To create the attack clip, you do the same, but set the Category to Attack instead of Idle.

    To swap between Knight and Orc, simply assign the Orc or Knight Sprite Library Asset in the Sprite Library Components Library slot.

    Hopefully this will make the process clearer.