Search Unity

SpriteManager - draw lots of sprites in a single draw call!

Discussion in 'iOS and tvOS' started by Brady, Jan 15, 2009.

  1. AbhishekS

    AbhishekS

    Joined:
    Dec 15, 2008
    Posts:
    157
    Hi Guys,

    Im pretty new to the sprite manner 2 my firm has bought the license for the sprite manager 2 me currently using it for our project.

    Its basically 2D game with loads of sprite base animations we are able to load play the animations as per sour requirement. But we are unable to flip the animation so we can show the person moving the other/opposite direction without using a different set images. As soon as we flip the gameobject its disappears from the scene.

    Normally I prefer flipping of Texture(UV) coordinated when we are using single image rather than rotating the game object, if I want to display the image pointing in other direction.

    Can anyone help me out to rotate/flip the game object or flip the UV coordinates to point the character in the opposite direction than the actually direction??

    w8ing for your reply.....

    Thanks.
     
  2. Brady

    Brady

    Joined:
    Sep 25, 2008
    Posts:
    2,474
    What is happening is the shader you are using is culling the "back" of the sprite. So when you reverse its scale, causing it to face the other way, suddenly the camera is looking at the "back" side of the sprite, which the shader culls. To fix this, use a shader that has back culling disabled. You can use the shader which comes with SM2 by adding the following line just below the line that says "Lighting Off":
    Code (csharp):
    1.  
    2. Cull Off
    3.  
    That should fix you right up.
     
  3. AbhishekS

    AbhishekS

    Joined:
    Dec 15, 2008
    Posts:
    157
    Thanks a lot its working fine now.
     
  4. Dark-Table

    Dark-Table

    Joined:
    Nov 25, 2008
    Posts:
    315
  5. Brady

    Brady

    Joined:
    Sep 25, 2008
    Posts:
    2,474
    Awesome! That's a really great looking project you've got there. Thanks for sharing.
     
  6. RobbieDingo

    RobbieDingo

    Joined:
    Jun 2, 2008
    Posts:
    484
    @silentchujo

    ...bloody hell, that's cool (part one I mean, not tried part 2 yet, but I just might have to now).
     
  7. Michael-Ryan

    Michael-Ryan

    Joined:
    Apr 10, 2009
    Posts:
    184
    The following may be a bug in the current version of SpriteManager (the original, not necessarily SM2).

    The "spriteDrawOrder" ArraryList has a comment that defines it as "an array of indices of sprite objects stored in the order they are to be drawn", yet in the code, it appears to contain both "int" variables and Sprite objects.

    In EnlargeArrays(), a Sprite is added to the ArrayList, and in SortDrawOrder, elements are cast to Sprite inside the loops.

    In MoveToFront(), MoveToBack(), MoveInFrontOf(), and MoveBehind(), the IndexOf() call is passing a Sprite object, but then later in these methods, an "int" is being assigned to the ArrayList.

    Finally, in SpriteDrawLayerComparer(), it's dealing with Sprites again.

    -----

    Am I missing something here, or is this a bug? I haven't actually used any of these methods as of yet, and therefore haven't encountered any issues, but I suspect there will be InvalidCastExceptions encountered in SortDrawOrder when it attempts to cast an "int" to a Sprite.
     
  8. Brady

    Brady

    Joined:
    Sep 25, 2008
    Posts:
    2,474
    I think you're on to something. It's been a while since I've messed with SM1 code and fortunately, SM2 relies on Unity's depth sorting, so it doesn't require any manual setting of the draw order. But I believe that it basically needs the ".index" part dropped in those sorting routines. I'm not where I can do a quick test of that at the moment, but if you happen to test it and it behaves properly, let me know. But I'm pretty sure it's just supposed to be re-assigning the reference to the specific sprite back to the draw order list.

    Thanks for pointing this out!
     
  9. BrandonE

    BrandonE

    Joined:
    Feb 22, 2010
    Posts:
    6
    I am having some issues with sprite manager one using setanimcompletedelegate. I have 9 frames and when you press the arrow key it plays the entire animation but only repeats the last 6. I know my code is probably super hard to read but ill post it. All of my bools default to false. As of right now. it actually goes through the animation but does not recycle the last 6 frames. It just stops on the final frame when im holding the button.
    Code (csharp):
    1.  
    2. if (Input.GetAxis("Horizontal") < -0.01)
    3.         {
    4.             if (reverseAccelerating)
    5.             {
    6.                 b.PlayAnim("reversing");
    7.                 return;
    8.                
    9.             }
    10.             if (startingreverse)
    11.             {
    12.                
    13.                 return;
    14.             }
    15.             startingreverse = true;
    16.             accelerating = false;
    17.             b.SetAnimCompleteDelegate(startReverseAnim);
    18.             b.PlayAnim("startingreverse");
    19.            
    20.            
    21.         }
    22.  
    Code (csharp):
    1.  
    2.   void startReverseAnim()
    3.     {
    4.         reverseAccelerating = true;
    5.         b.PlayAnim("reversing");
    6.     }
    7.  
     
  10. Brady

    Brady

    Joined:
    Sep 25, 2008
    Posts:
    2,474
    I can't think of a reason why it should only repeat 6 frames of an animation, but given the code, I do foresee a possible problem: be sure to take into account the fact that when PlayAnim() is called, the animation will start over again. So for instance, if you told it to play a given animation when a button is held down, meaning PlayAnim() gets called so long as that button is held, then the animation will constantly be re-starting, leading to the appearance of never getting past the first frame.

    I know that's not exactly the behavior you described that you are receiving, but I suspect something of a similar nature may be the problem.
     
  11. AbhishekS

    AbhishekS

    Joined:
    Dec 15, 2008
    Posts:
    157
    Some new Queries regarding sprite manager 2

    1) Can We pause the Animation at a particular frame say frame number 5 out of 20 frames of animation.

    2) How two increase of decrease speed of animation? we tried to do this but it was causing a crash as soon as we changed the speed of the animation.

    3) Now How efficient is the Sprite Manager 2, when we have approx 300 images of 240x140 resolutions for single character??? Which contains 8 animations min. of 25 frames(its obvious that it wont fit in single atlas of 1024x1024).
    So any ideas how to handle them with min. memory usage?
    Note: i cannot scale down the images to fit it in single atlas as its going to scale the character as well.
     
  12. Dreamora

    Dreamora

    Joined:
    Apr 5, 2008
    Posts:
    26,601
    I fear for pre 3GS your targets are pretty unrealistic

    300 frames, ok (on an 8 way pseudo iso at least) but not at your framesize. (uncompressed thats nearly 2x the VRAM you have available at all pre 3gs)
    Also each atlas means another drawcall, nothing there to avoid that.

    You should really reconsider the design there, as it looks by far too much desktop focused.

    please keep in mind, this is a phone, not a pc, it does not have hundreds of mb of RAM and VRAM to hold such data it will just crash should go go only 1 byte above the available RAM / VRAM (no page file or alike to compensate for this kind of developer error as on the desktop)
     
  13. AbhishekS

    AbhishekS

    Joined:
    Dec 15, 2008
    Posts:
    157
    I know we are making this for iPhone not desktop. its the clients base project we have already informed this to the clients about it.

    but i wanted to know if there is any other way to get it done.
     
  14. Dreamora

    Dreamora

    Joined:
    Apr 5, 2008
    Posts:
    26,601
    With hardware compression (pvr) you can at least fit it into the VRAM

    but the drawcall problem will remain, each new atlas means a new drawcall, there is nothing that can be done about that.
     
  15. AbhishekS

    AbhishekS

    Joined:
    Dec 15, 2008
    Posts:
    157
    The thing is I will be requiring nearly 8 atlas for a single character only and there are only 2 character like that in the whole level + 4 BG(1 single atlas) 6 UI related GUI textures, that's my whole scene/level. + 2-3 special effects for attack

    The game is kind of simple Street Fighter.
    with 2 char. fighting each other with some special moves.
     
  16. Brady

    Brady

    Joined:
    Sep 25, 2008
    Posts:
    2,474
    Yes, you can pause at any time. If you need to know the specific frame, you can enable a per-frame delegate to be called each frame, at which point if you have a reference to the animation itself, you can check the current frame using GetCurPosition(). You can see the SM2 scripting reference for more details.

    You can use SetFramerate(). If that's what you already tried, can you confirm it caused a crash? I hadn't had any reports of that so far.

    Efficiency in terms of memory usage isn't really something SM2 can affect. You could try unloading textures currently not in use, but there will be a lag when you go to load them again, so I would advise trying to stick to a design that would allow all needed textures to be loaded and available in memory at load time.

    The only other issue is that if you have to use a second, third, etc, atlas, you'll need another sprite object. When you need to switch to an animation that exists on another atlas, you'll just disable the current sprite and enable the other one. I have it on my ToDo list to add a higher level sprite class that can automatically wrap this functionality.
     
  17. AbhishekS

    AbhishekS

    Joined:
    Dec 15, 2008
    Posts:
    157
    Hi,

    Im not having the functions which you have mentioned GetCurPosition() SetFramerate()
    from where can i find the latest sprite manager code???
     
  18. Brady

    Brady

    Joined:
    Sep 25, 2008
    Posts:
    2,474
    I'll PM you.
     
  19. Oudaiesty

    Oudaiesty

    Joined:
    Feb 21, 2010
    Posts:
    1
    I was wondering lets say I have a rather large sprite, would it be possible to make an animation about 12 frames long and still stay under the max texture size?

    meaning what if I split the animation up amongst several different materials? would that work or would that make a mess? Cause I want to stay under 1024 but Atm its looking rather difficult. I know resizing would be an option but then I have to re-compensate for the background differences. (the background no longer being the size I need it to be to take up the resolution for an iphone)

    What could I do?
     
  20. Brady

    Brady

    Joined:
    Sep 25, 2008
    Posts:
    2,474
    You could split it up among multiple materials, or for that matter, just use one material and change out the texture. The only problem is you wouldn't be able to use that SpriteManager for much else since other sprites using it would have their textures changed along with it.

    But if you only use that manager for the stuff that uses the textures you're changing, and as long as they all need the same texture at the same time, it should work.
     
  21. Phua

    Phua

    Joined:
    Jun 29, 2010
    Posts:
    4
    I'm new to Unity3d and use SM1 to create the sprite, but the image in the sprite look very dim, so I try to use the directional light to make it brighter but there is no effect on it and still the same as dim as before. I wondering why, could anybody advice me on this issue?
     
  22. Brady

    Brady

    Joined:
    Sep 25, 2008
    Posts:
    2,474
    It may be the shader you are using. Try using the built-in blended particle shader. That one normally works pretty well. See the setup in the example project attached to the first post of this thread.
     
  23. Phua

    Phua

    Joined:
    Jun 29, 2010
    Posts:
    4
    Thanks for your reply:) Yeah, it works after I set the shader by using particles. However, it seem like the sprite does not have any effect on the lighting even I have increase the intensity, range and angle. Is it the SM1 does not support directional, point and spot light?
     
  24. Brady

    Brady

    Joined:
    Sep 25, 2008
    Posts:
    2,474
    That is because the particle shader you're using is not lit. If you want lighting to have an effect, you need to use a lit shader, and also may need to add a line in LateUpdate() somewhere where you have the SpriteManager object recalculate the mesh's normals. Use:

    mesh.RecalculateNormals();
     
  25. Phua

    Phua

    Joined:
    Jun 29, 2010
    Posts:
    4
    The lighting effect on the sprite works after follow your instructions:) Thanks for the guide:D
     
  26. fmarkus

    fmarkus

    Joined:
    May 22, 2010
    Posts:
    181
    Hi!
    Can you describe exactly what shader you used, type of light and so on do have light work on your sprites? I can't get it to work :(
    Thanks!
     
  27. Phua

    Phua

    Joined:
    Jun 29, 2010
    Posts:
    4
    1) Select material that you have created, then go to shader->Particles and set as VertexLit Blended.

    2)Edit the SpriteManager.cs by looking for LateUpdate() function then under "if (vertCountChanged)" statement add

    mesh.RecalculateNormals();

    3) Create a Directional Light then try to adjust the intensity and you will see the effect when you run the game.

    (Note: Setting the material as "VertexLit Blended" shader, when you playing around the directional light intensity, you only will get effect like making the image look dim by setting to lower intensity but you will not get any effect to make the image look brighter than original color, mean that up to a certain intensity range no matter how you set a larger value for intensity, you will still get the color which remain the same and exactly look like how the original image look.)
     
  28. Galaxy613

    Galaxy613

    Joined:
    Oct 3, 2010
    Posts:
    1
    I just want to clarify something... to use mulitple sprites, you have to put them all into one very large image file and somehow keep track of the positions of each sprite you want to draw? Or do people create multiple sprite managers for different catergories of sprites they want to draw? What with Unity 3.0's better batching of draw calls and what not, SM1 from a newbie standpoint seems a little overcomplicated. :-S

    *edit* Aand I necro'd. -.- A 3 months old thread, prehaps I should just scrap using SM1 because no one uses it anymore apparently.
     
    Last edited: Oct 4, 2010
  29. dock

    dock

    Joined:
    Jan 2, 2008
    Posts:
    605
    I'm trying to build an old project using SM1 in Unity 3.0, and I'm getting this error:
    "Assets/Plugins/Sprite Scripts/Support/ISpriteMesh.cs(19,29): error CS0106: The modifier `abstract' is not valid for this item"

    Is there any easy fix to this?
     
  30. Waigo

    Waigo

    Joined:
    Jul 12, 2009
    Posts:
    49
    Hi Brady,
    Is there any way to set the current sprite to a specific frame?
    Just like the GoToAndStop() function in Flash Script.

    We've try to use the SetCurFrame() function of PackedSprite, but doesn't work.
     
  31. Brady

    Brady

    Joined:
    Sep 25, 2008
    Posts:
    2,474
    Sorry about the late reply here, but the forum's subscription notification seems all screwed up. Generally, you want to keep as much as possible in the same atlas/material since otherwise, you'll incur an additional draw call. But yes, SM1 is more complicated than it needs to be now, and SM2 is much more suited to the new dynamic batching and greatly eases the process of creating sprite animations and atlases.


    It sounds like you're using an old version of SM2 actually. You'll want to get the latest on the updates page for Unity 3.0 support. The page is at www.anbsoft.com/updates


    SetCurFrame() will set the current frame, but if an animation is playing, it will continue on from that point. So you want to pause the animation at the same time (the next call). Or if you always want to only show single frames, you can set the animation to have a framerate of 0, and then use the versions of PlayAnim() or DoAnim() which accept as their second argument the index of the desired frame you wish to start on.
     
  32. fyrlandt

    fyrlandt

    Joined:
    Aug 20, 2009
    Posts:
    80
    I'm currently testing this out right now but I cant seem to make the animation play properly. It seems that it only plays 1 frame/1 sprite from the texture atlas and just stops.
     
  33. edlvox

    edlvox

    Joined:
    Nov 24, 2009
    Posts:
    8
    Hi, just wondering if there is any news with: GetAnimDuration in SM.. :D tnx!
     
  34. Brady

    Brady

    Joined:
    Sep 25, 2008
    Posts:
    2,474
    There isn't a GetAnimDuration() in SM1, but there is a GetLength() method in SM2 that gives an animation's length in seconds, if that's what you're interested in.
     
  35. MaDDoX

    MaDDoX

    Joined:
    Nov 10, 2009
    Posts:
    764
    Brady, I'm a registered SM2 user (sorry if the forum would be a better place to post this) and although I really love SM2, I found a serious shortcoming in it. Its generated atlases doesn't work as a source for Unity's particle animator. From what I understand, particle animator always reads the sequence of frames in "western reading" style, ie. left-to-right, top-to-bottom. Since SM2 atlases places sprites in seemingly random positions, it's not suitable. I have to go to Photoshop and manually tile and re-place the sprites in order, or just do it straight in Photoshop, which kinda defeats the purpose.

    Supposing that placement has a specific logic that optimizes the execution of the animation or something, could you at least add an option to SM2 to generate a western-reading atlas from a sequence of frames? It could go around the regular SM2 workflow, all we'd need would be the image anyways.

    Apologies in advance if this has already been addressed in some other fashion. Cheers!
     
  36. Brady

    Brady

    Joined:
    Sep 25, 2008
    Posts:
    2,474
    Actually, SM2's non-western atlas packing is one of its greatest advantages as it typically saves a very significant amount of texture memory and allows you to usually fit lots more onto a single atlas. If your sprites are all symmetric, then it wouldn't matter so much, but that is normally not the case. But the atlas generation is intended for use with SM2 sprites. It was not designed with the intention of being used for the particle system.

    I'll keep the idea of an option to build left-to-right in mind though. Thanks!
     
  37. hooligan

    hooligan

    Joined:
    Nov 26, 2010
    Posts:
    40
    I'm using SM! and have a quick question about removing a sprite.

    If Im using the linked sprite manager to i just remove a sprite by calling

    GameObject player;
    Sprite playerSprite;

    spriteManager.RemoveSprite(playerSprite);
    Destroy(player);

    I've been trying this an keep getting reference errors?

    NullReferenceException: Object reference not set to an instance of an object
    Sprite.Transform () (at Assets/Scripts/Sprite.cs:239)
    Sprite.SetSizeXY (Single width, Single height) (at Assets/Scripts/Sprite.cs:199)
    SpriteManager.RemoveSprite (.Sprite sprite) (at Assets/Scripts/SpriteManager.cs:500)
     
  38. Brady

    Brady

    Joined:
    Sep 25, 2008
    Posts:
    2,474
    As far as I recall, yes. It's been a long while since I messed with SM1, so forgive me for not being totally sure now. But from the stack trace, it looks like somehow the object is being destroyed or set to null before it is removed. It should be, as in your example, removed first, then destroyed, in that order.
     
  39. hooligan

    hooligan

    Joined:
    Nov 26, 2010
    Posts:
    40
    Thanks for the response Brady I appreciate it. I'll look into it and see what I can find. As far as I can tell I'm doing it like I did in the above post. Weird.
     
  40. hooligan

    hooligan

    Joined:
    Nov 26, 2010
    Posts:
    40
    Quick question more unity specific but I think it could be the problem.

    I have a few objects inside a parent object that I am moving. Now when I destroy the sprites I loop through an arraylist of the sprites in that object but I only destroy the parent object. This should destroy the child objects too right?
     
  41. hooligan

    hooligan

    Joined:
    Nov 26, 2010
    Posts:
    40
    Nevermind, I found the problem with your help :) thanks for SM1 its a life saver.

    PS ill try get SM2 sometime :)
     
  42. bbvrdev

    bbvrdev

    Joined:
    Aug 11, 2009
    Posts:
    221
    I've got a quick question about SM2 syntax. I've been using SM2 happily in JS on many projects over the last year, but now I've had to refactor my project entirely into C#, and suddenly some pretty basic behavior doesn't seem to be working. Can anyone see what I'm doing wrong? This exact code works perfectly in JS, except that I added the "new" keyword as I was getting an error without it.

    Code (csharp):
    1.  
    2.        void FadeAndDie (){
    3.    
    4.         if (FadeDuration > 0)
    5.             thisSprite.SetColor(new Color(1,1,1,FadeDuration));
    6.         else
    7.             Destroy(transform.root.gameObject);
    8.     }
    9.  
    10.     void Update (){
    11.    
    12.         if (rigidbody.velocity.magnitude < 0.05f) {
    13.             FadeAndDie();
    14.             FadeDuration -= Time.deltaTime;
    15.         }
    16.    
    17.     }
    18.  
     
  43. Brady

    Brady

    Joined:
    Sep 25, 2008
    Posts:
    2,474
    The thing that jumps out at me first is that your color constants ("1") don't have an "f" after them. Anytime a floating point value is expected (and is not 0), in C# it needs to have a following "f" to make it explicitly floating point.
     
  44. bbvrdev

    bbvrdev

    Joined:
    Aug 11, 2009
    Posts:
    221
    Thanks Brady, I should have thought of that! Unfortunately, it didn't solve my problem..:) I also double checked that FadeDuration is a float, which it is. Watching the object, it seems like the fade duration doesn't go down at all, it just drops immediately to zero.
     
  45. Brady

    Brady

    Joined:
    Sep 25, 2008
    Posts:
    2,474
    Are you certain it is getting set to an initial value (of 1 or more, presumably) before this bit runs?
     
  46. bbvrdev

    bbvrdev

    Joined:
    Aug 11, 2009
    Posts:
    221
    Yep it is. It seems I was wrong about the fade duration, it does decrease, but the object doesn't seem to fade until it reaches zero and is destroyed.
     
  47. Brady

    Brady

    Joined:
    Sep 25, 2008
    Posts:
    2,474
    Check your shader. If it isn't a transparent (alpha), vertex-colored shader, it won't work. Also, cut-out shaders won't do it either as they don't fade.
     
  48. bbvrdev

    bbvrdev

    Joined:
    Aug 11, 2009
    Posts:
    221
    Thanks for sticking with me, Brady. My shader is indeed Transparent/VertexLit. Like I said, other than the syntax, nothing's changed since I switched from JS. I've just tried creating a public color and changing the alpha via FadeDuration, then applying it with SetColor, but while the color itself changes, the sprite doesn't.
     
  49. Brady

    Brady

    Joined:
    Sep 25, 2008
    Posts:
    2,474
    Actually, I don't think vertex lit will work. You need vertex colored. Try some of the other built-in transparent shaders as I'm pretty sure at least one of them is vertex colored.
     
  50. bbvrdev

    bbvrdev

    Joined:
    Aug 11, 2009
    Posts:
    221
    That did it! Thanks :)