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

SM2 - 2D made easy and efficient!

Discussion in 'iOS and tvOS' started by Brady, Nov 4, 2009.

  1. Brady

    Brady

    Joined:
    Sep 25, 2008
    Posts:
    2,474
    It sounds like it might be the result of a floating point precision or rounding issue. SM2 keeps track of fractional seconds passed since the previous frame, and over time, I can see that possibly adding up. Though in all my tests, identical animations play in synch indefinitely. I'll give this some more thought and see if I can think of why this would be occurring and how to prevent it. If you could send me a sample that demonstrates this privately, that might help as well.

    Thanks!
     
  2. bibbinator

    bibbinator

    Joined:
    Nov 20, 2009
    Posts:
    507
    When using SM2 am I able to still get the MonoBehavior mouse events? If not, how do I interact with the SM2 sprites?

    EDIT: After playing around I realized there was no collider attached. So I attached a mesh collider and now it is getting mouse events.

    If I need to do pixel hit testing though, is there a way for SM2 to do it? If not, are the UV coordinates available for the current animation frame so I could do it myself?

    Thanks!
     
  3. Brady

    Brady

    Joined:
    Sep 25, 2008
    Posts:
    2,474
    SM2 does not perform any per-pixel hit testing, but you can obtain the current UVs by calling the sprite's GetUVs() method, which returns a Rect that contains the UV coordinates of each of the 4 vertices which comprise the sprite quad.
     
  4. aerende

    aerende

    Joined:
    Apr 27, 2009
    Posts:
    316
    I've got animations working fine with Sprite Manager 2, but I can't figure out how to add sprites with Sprite Manager 2.

    Sprite Manager 1 allowed me to add sprites using code like:

    Code (csharp):
    1. static var LSP : LinkedSpriteManager;
    2. SMGO = GameObject.Find("SpriteManagerGameObject");
    3. LSP = SMGO.GetComponent("LinkedSpriteManager");
    4.  
    5.        s = LSP.AddSprite(instantGO,  // The game object to associate the sprite to
    6.                          70.0,        // The width  of the sprite
    7.                         130.0,        // The height of the sprite
    8.                           0,        // Left pixel
    9.                         128,        // Bottom pixel
    10.                          50,        // Width in pixels from Left pixel
    11.                         128,        // Height in pixels
    12. //                      400,        // Left pixel
    13. //                      256,        // Bottom pixel
    14. //                       50,        // Width in pixels from Left pixel
    15. //                      128,        // Height in pixels
    16.                         false);     // Billboarded?
    17.  
    How can I add sprites with SpriteManager 2?
     
  5. Brady

    Brady

    Joined:
    Sep 25, 2008
    Posts:
    2,474
    There are 3 main ways to add sprites:

    1) Using the editor.
    2) By instantiating sprite prefabs.
    3) By using code to add the Sprite script to a GameObject and then set it up in-code.

    If you need to add sprites at runtime, I'd recommend #2. Setup the sprites you want to instantiate in the editor, save them to a prefab, then it's as simple as:

    Code (csharp):
    1.  
    2. Instantiate(spritePrefab, position, Quaternion.identity);
    3.  
     
  6. mudloop

    mudloop

    Joined:
    May 3, 2009
    Posts:
    1,107
    If I understand correctly, there's a memory leak problem when using prefabs. So instead of using prefabs, create deactivated gameobjects in your scene and instantiate those.
    I'm not 100% sure if this memory problem still exists though.
     
  7. tau

    tau

    Joined:
    Dec 15, 2008
    Posts:
    113
    Brady,

    Sorry, I could not send you a sample project with the timing issue due to the lack of time, I'm still a bit swamped. I did find another issue related with activating/deactivating objects containing packed sprites attached to them.

    I'm using SM2 in my custom GUI and I have 2 main screens: MainMenu and HelpScreen. Those are empty root game objects for all the buttons (packed sprites) below them.

    Schema:
    Code (csharp):
    1.  
    2. |
    3. |-HelpScreen
    4. |  |-> Next button
    5. |  |-> Prev button
    6. |  |-> Close button
    7. |
    8. |-MainMenu
    9.    |-> Start
    10.    |-> Help
    11.  
    MainMenu is active and HelpScreen is non-active - it's all set initially in the editor by hand.

    After the game starts in the editor, a user clicks on a Help button, and a script calls MainMenu.gameObject.SetActiveRecursively(false), all is fine, then it calls HelpScreen.gameObject.SetActiveRecursively(true) and I get an exception for every button/GameObject containing a PackedSprite attached to HelpScreen.

    This is the exception I'm getting:
    Code (csharp):
    1.  
    2. NullReferenceException
    3. SpriteBase.SetSizeXY (Single w, Single h)   (at Assets\Sprite Scripts\Support\SpriteBase.cs:1454)
    4. SpriteBase.SetSize (Single width, Single height)   (at Assets\Sprite Scripts\Support\SpriteBase.cs:1412)
    5. SpriteBase.CalcSize ()   (at Assets\Sprite Scripts\Support\SpriteBase.cs:1398)
    6. SpriteBase.SetCamera (UnityEngine.Camera c)   (at Assets\Sprite Scripts\Support\SpriteBase.cs:1595)
    7.  
    The line is in SpriteBase v1.0 RC5 (11-9-2009):
    Code (csharp):
    1.  
    2. mesh.vertices = vertices;
    3.  
    I think the mesh variable is NULL at the time it's calling SetSizeXY() on a sprite during a call to gameObject.SetActiveRecursively(true). I suspect that the script somehow activated first/prior the Mesh component, thus mesh is NULL, I could be wrong.
     
  8. Brady

    Brady

    Joined:
    Sep 25, 2008
    Posts:
    2,474
    Yes, that sounds like a very plausible hypothesis. I'll look into this right away.

    Also, I'd love to see a sample of the timing issue whenever you get the time.

    Thanks!
     
  9. aerende

    aerende

    Joined:
    Apr 27, 2009
    Posts:
    316
    So to use #3 to add sprites do I:

    1) Add Sprite.cs to a game object = SpriteGameObject.
    2) Add the Texture that I want to the Sprite script in SpriteGameObject.
    3) Add the following code:

    Code (csharp):
    1.        
    2. var SBGO  : GameObject;
    3. var SB    : SpriteBase;
    4.  
    5. SBGO = GameObject.Find("SpriteGameObject");
    6.        
    7. SB   = SBGO.GetComponent("Sprite");
    4) The part I can't figure out is how to add the Sprite to SB.
    With SM1 there was the AddSprite function, but I can't find anything similar for SM2.
     
  10. tau

    tau

    Joined:
    Dec 15, 2008
    Posts:
    113
    To further help you, I found an interesting thing:
    Button.Awake() (where button is a gameobject with a packedsprite script component) is called before the PacketSprite.Awake(), thus PacketSprite.Init() is not yet called to create a new Mesh object. It's a real bummer. If I move the code from Button.Awake() to Button.Start(), it works, but it brings other issues thru out the project...

    I'll try to assemble a sample timing issue project, in fact, I can recreate the timing issue in editor and on the device, just need some free time :)
     
  11. Brady

    Brady

    Joined:
    Sep 25, 2008
    Posts:
    2,474
    aerende:
    Yes, you have it pretty much correct. The thing to remember is that SM2, despite its name, does not have a "manager" script to which you must add a sprite. Rather, SB, in your example, holds a reference to the sprite itself. So rather than having to "add" the sprite to SB, it turns out that SB *is* the sprite.

    But I think the thing you're after is how to setup the sprite once its been created. On that note, I could have sworn I had a Setup() method for the Sprite class that accomplished this, but I must have taken it out some time ago, so I'll PM you with one here in a bit. For the anyone else who might need it right away, PM me, otherwise it'll be in the next release (coming soon).

    tau:
    I'm not clear as to which Awake() is getting called first. Are you saying there is another script attached to this GameObject that is having its Awake() called before that of the sprite? If the sprite's Awake() is getting called, then Init() should be called by Awake(). So something is going amiss.
     
  12. tau

    tau

    Joined:
    Dec 15, 2008
    Posts:
    113
    The GameObject that is a Button has 2 script components attached:
    1) guiButton (mine origin)
    2) PackedScript (SM2 origin).

    The guiButton script is taking care of the button logic like changing states and sprite animation on click, etc; the PackedSprite role is obvious.

    As it turns out, guiButton.Awake() is called before PackedSprite.Awake().
    guiButton.Awake() finds PackedSprite component and sets default camera to make sure the sprite dimensions are calculated properly, but because the PackedSprite.Init() is not yet invoked to create a Mech, the exception is thrown when calling SetCamera(camera) inside the guiButton.Awake().

    My thought: this setup is very specific, but quite common; I suspect this is a mid priority item to improve sprite initialization and avoid the exception. I can work around it by placing SetCamera() in guiButton.Start(), but it brings other issues.
    I guess, you may not worry about this issue (if you think it's an issue), it's just a heads up for similar situations. (I basically found a workaround while chatting with you :) )
     
  13. Brady

    Brady

    Joined:
    Sep 25, 2008
    Posts:
    2,474
    Ahh, okay, now I understand. This isn't really an SM2 issue though, but rather a Unity design pattern issue. Since Unity doesn't guarantee the order in which Awake() will be called on various components (or GameObjects, for that matter), Awake() should only handle initialization that is internal to that script, and all other initialization should be done in Start(). Unfortunately, there's no way around this since there's no way for an SM2 script to force itself to run ahead of other components that I'm aware of.

    If you only need the code in Awake() to set the camera, you'll be glad to know the next release will expose the camera property to the editor so you can bind the sprite to the camera of your choice at edit time. Until the next release, however, you can simply make the camera member public and be able to do this at design time in the editor.
     
  14. tau

    tau

    Joined:
    Dec 15, 2008
    Posts:
    113
    Correct, I bet Unity is using List/Dictionary internally to hold the components and those collections do not guarantee the enumeration order.

    I actually prototyped this and it does not play well if the PackedSprite is inside a prefab, especially if the sprite is a child prefab to another prefab... I think Unity has an issue with referencing scene objects inside a prefab, it likes more to reference another prefab inside one.
    I could be wrong on this one, but I could not make a prefab sticking to a scene camera and had to call SetCamera() after instantiating a prefab which has a huge performance hit because of GetComponent() and typeof(). If you found a solution to this, that would be awesome! I recommend to test it with prefabs.
     
  15. Brady

    Brady

    Joined:
    Sep 25, 2008
    Posts:
    2,474
    Yes, it won't work to store scene references in prefabs. But I thought your case used a sprite that was already in the scene but disabled. If, on the other hand, it is getting instantiated at runtime, then yes, you'll definitely need to call SetCamera() at runtime.
     
  16. steven.olsen66

    steven.olsen66

    Joined:
    Feb 2, 2010
    Posts:
    2
    Works so very well. Helps with a lot of my own 2d animation. :D
     
  17. Evan-Greenwood

    Evan-Greenwood

    Joined:
    Aug 6, 2008
    Posts:
    98
    Hi, just bought and downloaded this.

    I don't understand. Why does it use normal mesh renderers unlike SpriteManager1?

    Is this only meant to be used on iPhone? Because without that batching I will be getting hundreds of drawcalls. ???

    Please explain how this helps me? I know there is that whole animation thing, but I had made my own in SpriteManager1 and I was hoping to see performance improvement. Is there something I'm not understanding?
     
  18. Evan-Greenwood

    Evan-Greenwood

    Joined:
    Aug 6, 2008
    Posts:
    98
    Okay... Sorry about my last post. It will help me with my iPhone projects, and once I get the Sprite editor working that might help a bit.

    But aren't hundreds of drawcalls going to hit a graphics card even in Windows or Mac?

    I do like the fact that I can select things in the editor now, but I'm wary of the performance non-iPhone, unless I'm not understanding drawcalls?

    Is there any z-sorting? Doesn't batching on the iPhone go mental with z-sorting? I remember it being unreliable.
     
  19. Brady

    Brady

    Joined:
    Sep 25, 2008
    Posts:
    2,474
    Unity handles Z-sorting, and it works fine with iPhone's dynamic batching.

    As for batching on "regular" Unity, we are told that batching will be incorporated with desktop Unity, and if that does not occur soon, I will see about working up a way to combine the sprites into a single mesh ala SM1. The reason this was not done in SM2, however, is because you lose a significant amount of flexibility and usability when you do that (for instance, I soon plan to add the ability to use multiple textures per sprite for large animation sets, which could not be done when all sprites share a single mesh). Also, combining all sprites into a single mesh can entail a significant performance overhead compared to batching. If you do large-scale comparative benchmarks on an iPhone between SM1 and SM2, you'll see a significant increase in performance due to the latter's use of batching as opposed to a combined mesh. Plus, on Unity desktop, a higher number of low-poly (2 triangles) draw calls is FAR less of an issue than on iPhone (where 25-30 draw calls can lead to unplayable framerates).

    But even though a couple hundred low-poly draw calls may not be a big deal on a desktop machine, batching should be added soon. And if it is not, I'll see what I can do to use a combined mesh with minimal sacrifice of usability and features. If you're just looking for a performance boost for Unity desktop and aren't interested in the animation tools, send me an e-mail.
     
  20. Evan-Greenwood

    Evan-Greenwood

    Joined:
    Aug 6, 2008
    Posts:
    98
    Thanks! that answers my questions.

    I'll have a look at the z-sorting in Unity iPhone again. It may have been something to do with my shader.

    I'll probably stick to SpriteManager1 for my desktop/browser game for the moment, it's set up and working already (and there is barely any animation, just a lot of sprites) and switch over if the batching comes about.
     
  21. freshcut

    freshcut

    Joined:
    Nov 17, 2008
    Posts:
    71
    just wanted to show my interest for the GUI kit you mentioned earlier Brady.
    Keep up the good work :)
     
  22. aerende

    aerende

    Joined:
    Apr 27, 2009
    Posts:
    316
    I have a few questions:

    1) When one of my animations runs in Unity iPhone, it appears to shrink vertically and then stretch vertically. The animation looks fine in SM2's SpriteTimeline. The frames for the animation start off narrow and tall and then the later frames are short and wide. All the other animations I run work fine. Do you what could be causing this? If I run the animation in Pixel Perfect it looks fine of course, but I'd rather not have to use an orthographic camera.

    2) What is the best approach to have multiple sprites rotating independantly with SM2? Should I make a GameObject per Sprite and rotate the GO's transform? I saw an earlier response to a similar question in this thread which described using SM2's offset property. To use this approach would one slowly change the offset to get the Sprite to rotate? In SM1 to offset a sprite one used

    Code (csharp):
    1. Sprite.offset = Vector3(x, y, z);
    Does this approach still work in SM2?
     
  23. Brady

    Brady

    Joined:
    Sep 25, 2008
    Posts:
    2,474
    freshcut:
    Thanks! It is still in my plans, but will probably be a separate add-on.

    aerende:
    1) It sounds like you need to enable "Auto Resize" (the checkbox just under Pixel Perfect). That should do it.

    2) I would just rotate the GameObjects. That's sort of what SM2 is designed to do, so you could, for example, attach a rigidbody (and probably a joint to keep it oriented toward the camera) to the GameObject and just let it go - the sprite will automatically rotate with it. It's actually the same as if you were using a 3D mesh - since in fact, you are.

    The offset works the same as in SM1, and its purpose is basically just if for some reason you want the GameObject to be displaced in 3D space a certain amount. 99% of the time, you won't need to use it. In fact, I'm thinking about removing it as you could achieve similar functionality just by placing the sprite's GameObject as a child to another GameObject and offset it that way.
     
  24. aerende

    aerende

    Joined:
    Apr 27, 2009
    Posts:
    316
    I don't know if this has been asked before but what I'd like to do is to create a bunch of sprites from items on a texture in the same way that the animations are created from a bunch of variable size frames using the Sprite TimeLine. Is that possible to do?

    I.E. I have 20 images of different sizes. I'd like to drag and drop those images into say SpriteTimeline, and SM2 creates a texture packed with these images and knows where each one is. So then to make Sprite #1, I essentially select frame1, Sprite #2, I select frame 2, etc. In this way I don't have to specify the Lower Left Pixel and the Pixel Dimensions of each of the images.

    Is this possible? It appears that SM2 comes close to already being able to do this, since it already does it for animations, I just don't see an easy way to do it for individual sprites.
     
  25. Brady

    Brady

    Joined:
    Sep 25, 2008
    Posts:
    2,474
    I guess I'm not 100% sure how this differs from what it already does. If you're referring to the ability to assign the static image to a non-animating sprite, using a PackedSprite, you just drag the texture you want onto the "static texture" member in the inspector.
     
  26. codepunk

    codepunk

    Joined:
    Dec 10, 2008
    Posts:
    68
    Not sure if I just tag my question onto this post or start a new topic, but here goes.

    I'm trying to pick a sprite using the mouse and/or touch input. I'm doing the normal Camera.main.ScreenPointToRay followed by Physics.Raycast. It works just fine for the gameobjects which aren't using SM2 (e.g. a regular cube) but I can never get it to hit a GameObject that uses SM2. Any ideas anyone?
     
  27. Brady

    Brady

    Joined:
    Sep 25, 2008
    Posts:
    2,474
    Be sure you've added a collider component to your sprite's GameObject. The built-in objects such as "cube" and "sphere" come with a collider already on them. A regular GameObject does not. The raycast has to have something to collide with.
     
  28. codepunk

    codepunk

    Joined:
    Dec 10, 2008
    Posts:
    68
    I have box colliders on all of them. I'm really at a loss here. Been looking at this for hours.
     
  29. Brady

    Brady

    Joined:
    Sep 25, 2008
    Posts:
    2,474
    Make sure you aren't using any layer masks, or if you are, that the objects in question are in the proper layer. There's no reason why a GameObject with an SM2 component should not register in a raycast. It's used for that kind of thing all the time, so I know it works. There's got to be something else going on.

    If you like, e-mail me directly with a sample project and I'd be happy to help you figure out what's going on.
     
  30. aerende

    aerende

    Joined:
    Apr 27, 2009
    Posts:
    316
    Can you explain a bit more about how this would work?

    Currently I import the 20 PNG files into a texture. Then I create 20 prefabs using that texture where each contains Sprite.cs, and in Sprite.cs in each of the prefabs I specify Lower Left Pixel and Pixel Dimensions separately for each of the 20 PNGs. Now in a script I can instantiate each of the prefabs, and translate and rotate each as I choose.

    If I wanted to do something similar using the approach with the animations, would I drag and drop the 20 PNG files into Sprite Timeline? I did that and I created a texture atlas, but how do I select each of the images in the texture so that I can translate and rotate them as I choose?

    1) Since each of the 20 PNGs is a frame in an animation, how do I select individual frames and move them independantly?

    2) Or once I have created the texture atlas, and drag the texture into the "static texture member of a PackedSprite in the inspector, how do I select each image in the texture?
     
  31. Brady

    Brady

    Joined:
    Sep 25, 2008
    Posts:
    2,474
    Are you needing to select individual frames at different times for a single sprite? If so, see the "posed" sample in the demo script that comes with SM2. Basically, you just have several single-frame animations, and when you want to go to a specific frame, you just call PlayAnim() and tell it the animation you want. The animation doesn't actually have to be an animation - it can be a single frame.

    If, however, you're wanting lots of different single-frame sprites, but the sprites themselves don't change once created, just use PackedSprite instead of Sprite, drag the texture you want onto the "static texture" member in the inspector, and save it to a prefab.

    Or maybe I'm not understanding what you're wanting to do.
     
  32. cmh322

    cmh322

    Joined:
    Apr 3, 2009
    Posts:
    70
    SM2 is awesome, definitely recommend it.
     
  33. aerende

    aerende

    Joined:
    Apr 27, 2009
    Posts:
    316
    I want lots of different single frame sprites where the images on the sprites don't change. So my question is: Once I have created the texture and dragged it onto the static texture and then save it to a prefab, how do I select the individual sprites so that I change their transforms and send them in different directions?
     
  34. Brady

    Brady

    Joined:
    Sep 25, 2008
    Posts:
    2,474
    You translate/rotate sprites just by translating/rotating the GameObject. Same as if you were using a 3D mesh (since essentially, you are).

    So you would instantiate the prefabs, and once you have a handle to the instantiated GameObject, just move it around like you would any other GameObject.

    Let me know if that answers your question.
     
  35. aerende

    aerende

    Joined:
    Apr 27, 2009
    Posts:
    316
    What I want to do is save myself the process of typing in the Lower Left and Pixel Dimension location information of the images in the texture, when each image in the texture is used for a separate sprite.

    For animations I don't have to indicate where each frame is in the texture, SM2 knows the Lower Left and Pixel Dimension location information of each frame and grabs each frame sequentially.

    I'd like to be able to do the same thing with individual images that are used for individual sprites, meaning not have to specify the Lower Left and Pixel Dimension location information but use a similar trick of SM2 where I say, select image #3 for this PackedSprite. Is that possible?
     
  36. Brady

    Brady

    Joined:
    Sep 25, 2008
    Posts:
    2,474
    More or less, yes. You can 'say' you want this or that image by having separate sprites, each with the image you want set as the static texture, and then store these in prefabs. When you want a sprite of X type, you instantiate X prefab.

    Another way is to use the method I mentioned that is demonstrated in the demo script for the "posed" sprite - you put all the frames you want to use into a single sprite by setting up several single-frame animations. Then when you want that sprite to display a given image, you just call PlayAnim("whatever") which sets it to that frame.

    In the next release, there will also be the ability to jump to a specific frame of an animation - so you could then also put all your images into a single animation, then just jump to specific frames. Personally, I would go for the either the "posed" method above, or the multiple-prefab method, as they would probably be the most user-friendly for what it sounds like you're wanting to do.
     
  37. aerende

    aerende

    Joined:
    Apr 27, 2009
    Posts:
    316
    Your second approach sounds close to what I want and your future feature sounds like exactly what I want. Currentl I can drag and drop each image into a separate single frame animation and create the texture. Then I could have multiple sprites each with the same texture and animations but each only playing a different single frame animation, correct?

    I've already gone with your first approach, and made 20 prefabs. But with this approach I had to specify the Lower Left Pixel and Pixel dimensions for each prefab.
     
  38. Brady

    Brady

    Joined:
    Sep 25, 2008
    Posts:
    2,474
    Correct.

    Then you must be using the Sprite class instead of PackedSprite. As I suggested earlier, use PackedSprite instead and all you have to do is drag the texture of your choice onto the "static texture" slot in the inspector. Then compile your atlas(es), and voila.

    The only real reason to ever use "Sprite" as opposed to "PackedSprite" is if you already have a texture atlas laid out that you want to use and you don't want to mess with atlas generation.
     
  39. aerende

    aerende

    Joined:
    Apr 27, 2009
    Posts:
    316
    With this approach how do I select the different images in the texture without typing in the Left Pixel and Pixel Dimensions information?
     
  40. Brady

    Brady

    Joined:
    Sep 25, 2008
    Posts:
    2,474
    PackedSprite doesn't even have "left pixel" or "pixel dimensions" properties. You just drag the texture on to "static texture", generate the atlas, and that's it. So if your sprite's images don't change once created, you just instantiate the one with the static image you want. No selection required.

    If you want to be able to change them at runtime, then use the other method (single-frame animations).
     
  41. aerende

    aerende

    Joined:
    Apr 27, 2009
    Posts:
    316
    I've got an animation question:

    1) When I preview my animations in Sprite Timeline they look fine but when I play the animations they are stretched by about 20 % horizontally. I have AutoResize enabled as you suggested. Any ideas why the animations would be stretched and what I can do to fix it?

    I have the width and height both set to 1 and the scale set to 6 for x, y and z.
     
  42. Brady

    Brady

    Joined:
    Sep 25, 2008
    Posts:
    2,474
    It sounds like you may not have the initial aspect ratio of your sprite set. For example, if you set its size to 1,1, but the sprite's static texture itself is half as wide as it is tall, then if you have "auto resize" turned on, all succeeding frames will be stretched by a factor of 2 since the original aspect ratio was 1:2, but the specified "physical" dimensions are 1:1 (1x1 units). This is because auto resize calculates the proper dimensions of succeeding frames based on the ratio used for the static frame.

    You can manually set the width/height so that the aspect ratio matches the original texture, or you can easily let SM2 set it for you by turning on pixel perfect, then turning it off again. Once it is set this way, the aspect ratio will match the original image. If the sprite isn't of the desired scale, then you can either rescale it using the transform's scale, or just multiply the width/height by a factor that will get the sprite to the scale you're looking for.

    Once the width/height are set such that they match the aspect ratio of the original static texture, that should do it.
     
  43. aerende

    aerende

    Joined:
    Apr 27, 2009
    Posts:
    316
    I'm a little confused. By "aspect ratio" do you mean the Transform Scale or the Packed Sprite's width and height? The animation starts with a frame that is say 10 wide and 20 tall and the last frame in the animation is 30 wide by 10 tall. So

    1) What should I set the X,Y scales to?

    2) What should I set the Packed Sprite's width and height to?


    As a side note, I tried using Pixel Perfect and the animation now appears to look correct. But I didn't notice Pixel Perfect changing the scale. And the Packed Sprite's width and height are set to zero, when Pixel Perfect is turned on and then off. Should Pixel Perfect have modified the Packed Sprite's width and height?
     
  44. Brady

    Brady

    Joined:
    Sep 25, 2008
    Posts:
    2,474
    The transform scale will just "warp" the sprite in each respective axis, just like it would for any 3D mesh. Unless there is some other reason you want the scale to be something other than 1,1,1, you're probably beset off to start at 1,1,1, and set the width/height to something that makes sense for your specific application.

    As I mentioned before, the width/height setting is based on the static texture. You don't need to take any other frames into account - just the static texture. Get that setup so that it looks right, then enable Auto Resize, and all the other frames will be sized proportionately.

    So if your sprite's static texture is 10 pixels wide and 20 pixels tall, that's an aspect ratio of 1:2. So you should set the width to half of whatever you set the height. So if you want the sprite to be 1 world unit tall, set its width to 0.5.

    If it isn't exactly 1:2, then it may be easier to let Pixel Perfect set the width/height for you. When I say that Pixel Perfect might modify the scale, I don't mean the transform scale. I mean, for example, you may want the sprite to be scaled larger or smaller than pixel-perfect. So let's say Pixel Perfect sets the width to 1 and the height to 2, but in your game you want it to be 10 units tall, then you'd want to either use the transform scale to scale the sprite up to the size you want, or just manually adjust the width/height (in this case, it would be width=5, height=10). Either way is fine.

    One thing, however: when you check PixelPerfect, you may need to press Play briefly. The reason for this is for pixel perfect to be calculated, it has to get the camera's viewport pixel dimensions, and when not in play mode, Unity has a peculiar way (I call it a bug) of not reporting the correct viewport size for a camera.

    Also make sure you've compiled the atlas before doing this as PixelPerfect also needs to know the UVs it will use on the atlas to perform its calculation.

    But when you uncheck PixelPerfect, it shouldn't set the width/height to 0. It should be left at whatever value it was.
     
  45. Disaster

    Disaster

    Joined:
    Oct 31, 2009
    Posts:
    43
    This isn't entirely a SM2 question, but I'd appreciate some thoughts non the less. I want to use a sprite as my main player object, and I'm trying to decide the best way to go about it.

    At first I tried using a CharacterController along with the 2d Platform controller from the tutorial project. It works fine if you disable to rotation, but I'm struggling to figure out how to get it to play different animations.

    It seems to me that it might be easier to create a custom character controller script since modifying the existing Unity one might be more hassle than its worth when attempting to swap between animations.

    Does anyone have any experience with using SM2 and some kind of controller? What works best? Obviously physics are essential, although I don't want physics to effect my player as much as they do with using a RigidBody.
     
  46. Brady

    Brady

    Joined:
    Sep 25, 2008
    Posts:
    2,474
    For things like switch between run, jump, etc, animations, here's one way to do it (all using SidescrollControl.js as the basis):

    For jumping, inside the "if ( jump )" block, add:
    Code (csharp):
    1.  
    2. mySprite.PlayAnim("Jump");
    3.  
    Where "mySprite" is a reference to your character's Sprite/PackedSprite object, and "Jump" is the name of your jump animation (NOTE: it is recommended to use the animation index or animation reference instead of the name to avoid the performance overhead of string comparison.)

    Likewise, under the last "if ( character.isGrounded )" check, add a line re-setting your "standing" or "walk" animation, based on the "moveTouchPad's" x position.

    To control the facing direction of the character, modify the 'if' block at line 52 like so:
    Code (csharp):
    1.  
    2. // Apply movement from move joystick
    3. if ( moveTouchPad.position.x > 0 )
    4. {
    5.     movement = Vector3.right * forwardSpeed * moveTouchPad.position.x;
    6.     mySprite.gameObject.transform.localScale.x = 1;
    7. }
    8. else
    9. {
    10.     movement = Vector3.right * backwardSpeed * moveTouchPad.position.x;
    11.     mySprite.gameObject.transform.localScale.x = -1;
    12. }
    13.  
    It would be more efficient to create a boolean flag which will keep track of when the direction is changed, but this will give you a good idea of where to put the needed code.

    I hope that helps! :)
     
  47. Disaster

    Disaster

    Joined:
    Oct 31, 2009
    Posts:
    43
    Thanks Brady, this does help quite a bit actually!

    In regards to the mySprite reference, could you perhaps clarify how I go about getting a reference to a PackedSprite class placed on an object?

    Everything I do seems to throw a compiler error :(
     
  48. Brady

    Brady

    Joined:
    Sep 25, 2008
    Posts:
    2,474
    There are several ways to do it. If the script in question is attached to the same GameObject as contains the PackedSprite/Sprite component, then you can get the reference in Start() using GetComponent().

    Or another easy way is to declare a public reference like so:
    Code (csharp):
    1.  
    2. public PackedSprite mySprite;  // C# (within class body)
    3. var mySprite : PackedSprite;  // JS
    4.  
    Then in the editor, drag the GameObject containing the PackedSprite component onto the "My Sprite" member in the inspector, thereby establishing the link.
     
  49. Disaster

    Disaster

    Joined:
    Oct 31, 2009
    Posts:
    43
    Thanks for the reply Brady, I really appreciate it as it wasn't entirely related to SM2 :D

    Out of interest, what is this SideScroller.js you mentioned? Did you mean PlatformerController featured in the 2D tutorial?
     
  50. Brady

    Brady

    Joined:
    Sep 25, 2008
    Posts:
    2,474
    You should find it as part of the iPhone standard assets. If you create a new project and include the iPhone standard assets, you should get it there under "scripts".