Author Topic: Local position of UISprite after UIRoot scaling  (Read 7790 times)

nickwale

  • Newbie
  • *
  • Thank You
  • -Given: 0
  • -Receive: 0
  • Posts: 9
    • View Profile
Local position of UISprite after UIRoot scaling
« on: April 14, 2014, 04:48:18 AM »
I have a 2D UI with the scaling style set to FixedSizeOnMobiles and ManualHeight = 640, Minimum Height = 640, and MaximumHeight = 1600. My main target resolutions are iPhone4s, iPhone5 and iPad but I've designed the UI in the 4s resolution.

I've setup a sprite on an initial position in the screen and I've scaled it down to an initial size. What I want to do is create a tween where:
from: dimensions = original width and height && position = center of screen
to: dimensions = initial width and height && position = initial position

I've attached a TweenPosition, a TweenWidth and a TweenHeight on the UISprite and I'm setting the from and to values programatically.

To get the original dimensions I use: sprite.GetAtlasSprite().width and sprite.GetAtlasSprite().height
To get the initial dimensions I use: sprite.width and sprite.height
To get the initial position I use: sprite.transform.localPosition

The problem:

The initial dimensions and position that I get back are always the ones from the 4s resolution and are wrong in the other resolutions (they do not correspond to the values displayed in the editor).

In order to solve the dimensions problem I've used:
sprite.width / UIRoot.GetPixelSizeAdjustment(sprite.gameObject) and sprite.height / UIRoot.GetPixelSizeAdjustment(sprite.gameObject)

as recommend here: http://www.tasharen.com/forum/index.php?topic=5483.0.

How do I get the correct position though?
 
« Last Edit: April 14, 2014, 07:27:33 AM by nickwale »

ArenMook

  • Administrator
  • Hero Member
  • *****
  • Thank You
  • -Given: 337
  • -Receive: 1171
  • Posts: 22,128
  • Toronto, Canada
    • View Profile
Re: Local position of UISprite after UIRoot scaling
« Reply #1 on: April 15, 2014, 09:05:06 AM »
Don't touch position, width and height. Use widget's corners instead. You have localCorners and worldCorners. Pick one that suits you (local corners in your case likely).

nickwale

  • Newbie
  • *
  • Thank You
  • -Given: 0
  • -Receive: 0
  • Posts: 9
    • View Profile
Re: Local position of UISprite after UIRoot scaling
« Reply #2 on: April 15, 2014, 10:14:19 AM »
Are you suggesting something like this for calculating the dimensions?

  1. float width = (sprite.localCorners[2].x - sprite.localCorners[0].x);
  2. float height = (sprite.localCorners[2].y - sprite.localCorners[0].y);
  3.  

Because I've already tried that and it gives me the width and height in the 4s resolution.

As for the position did you mean doing something like this?

  1. float positionX = sprite.localCorners[0].x + (width / 2.0f);
  2. float positionY = sprite.localCorners[0].y + (height / 2.0f);
  3.  

This is going to return 0 at all times. Perhaps I'm missing something obvious.

ArenMook

  • Administrator
  • Hero Member
  • *****
  • Thank You
  • -Given: 337
  • -Receive: 1171
  • Posts: 22,128
  • Toronto, Canada
    • View Profile
Re: Local position of UISprite after UIRoot scaling
« Reply #3 on: April 16, 2014, 09:49:42 AM »
No. First of all, only call localCorners once and cache the result. You are calling it 6 times there, meaning it has to re-calculate the values 5 times more than necessary.
  1. Vector3[] corners = sprite.localCorners;
  2. //corners[0] is bottom-left
  3. //corners[1] is top-left
  4. //corners[2] is top-right
  5. //corners[3] is bottom-right
The position of a sprite is based on its pivot. So if the pivot is top-left, then the position will match corners[1]. If it's bottom-right, it will match corners[3], etc. In your case you don't care what the position of the target widget is. You only care about where you are animating the other widget to -- meaning the actual corners is what you need, not the position. Center of the widget? ((corners[0] + corners[2]) * 0.5f).

nickwale

  • Newbie
  • *
  • Thank You
  • -Given: 0
  • -Receive: 0
  • Posts: 9
    • View Profile
Re: Local position of UISprite after UIRoot scaling
« Reply #4 on: April 16, 2014, 11:05:20 AM »
Yep you're right about caching the corners array (I only wrote it like that to keep the example short). However, I tried your suggestion, i.e.,:

  1. Vector3[] corners = sprite.localCorners;
  2. Debug.Log("Center: " + ((corners[0] + corners[2]) * 0.5f));
  3.  

And I'm still getting (0, 0, 0) in all cases.

ArenMook

  • Administrator
  • Hero Member
  • *****
  • Thank You
  • -Given: 337
  • -Receive: 1171
  • Posts: 22,128
  • Toronto, Canada
    • View Profile
Re: Local position of UISprite after UIRoot scaling
« Reply #5 on: April 16, 2014, 11:17:54 AM »
Is the widget centered and located at position of (0, 0, 0)?

nickwale

  • Newbie
  • *
  • Thank You
  • -Given: 0
  • -Receive: 0
  • Posts: 9
    • View Profile
Re: Local position of UISprite after UIRoot scaling
« Reply #6 on: April 16, 2014, 01:51:49 PM »
No it has a different position. I tried it in a couple of sprites and I always get back (0, 0, 0).

ArenMook

  • Administrator
  • Hero Member
  • *****
  • Thank You
  • -Given: 337
  • -Receive: 1171
  • Posts: 22,128
  • Toronto, Canada
    • View Profile
Re: Local position of UISprite after UIRoot scaling
« Reply #7 on: April 17, 2014, 10:53:10 AM »
That's just not physically possible. Try printing the sprite's name along with just one corner.

nickwale

  • Newbie
  • *
  • Thank You
  • -Given: 0
  • -Receive: 0
  • Posts: 9
    • View Profile
Re: Local position of UISprite after UIRoot scaling
« Reply #8 on: April 22, 2014, 10:02:33 AM »
I tried this:

  1. Object[] sprites = Resources.FindObjectsOfTypeAll(typeof(UISprite));
  2.  
  3. foreach (UISprite sprite in sprites) {
  4.         Vector3[] localCorners = sprite.localCorners;
  5.  
  6.         Debug.Log("Sprite: " + sprite.name + " localCorner[0]: " + localCorners[0] + " localCorner[2]: " + localCorners[2] + " center: " + ((localCorners[0] + localCorners[2]) * 0.5f));
  7. }
  8.  

And this is what I get back:

  1. Sprite: LogoIcon localCorner[0]: (-115.0, -106.0, 0.0) localCorner[2]: (115.0, 106.0, 0.0) center: (0.0, 0.0, 0.0)
  2. Sprite: PlayButton localCorner[0]: (-139.0, -74.0, 0.0) localCorner[2]: (139.0, 74.0, 0.0) center: (0.0, 0.0, 0.0)
  3. Sprite: Title localCorner[0]: (-458.0, -74.0, 0.0) localCorner[2]: (458.0, 74.0, 0.0) center: (0.0, 0.0, 0.0)
  4. Sprite: SettingsButton localCorner[0]: (-67.0, -65.0, 0.0) localCorner[2]: (67.0, 65.0, 0.0) center: (0.0, 0.0, 0.0)
  5.  

nickwale

  • Newbie
  • *
  • Thank You
  • -Given: 0
  • -Receive: 0
  • Posts: 9
    • View Profile
Re: Local position of UISprite after UIRoot scaling
« Reply #9 on: April 22, 2014, 10:15:57 AM »
I've actually tried it in a brand new project with just 2 sprites in an empty scene and I get the same result (center is 0).

ArenMook

  • Administrator
  • Hero Member
  • *****
  • Thank You
  • -Given: 337
  • -Receive: 1171
  • Posts: 22,128
  • Toronto, Canada
    • View Profile
Re: Local position of UISprite after UIRoot scaling
« Reply #10 on: April 23, 2014, 06:47:53 AM »
Oh, durr. Right, localCorners are relative to the widget, not the widget's parent. You need to take widget's transform into consideration here if you want it to be relative to the widget's parent. Transform's position is relative to the parent, for example.

P.S. Have the sprites not been using centered pivot, your center wouldn't be (0, 0, 0).

nickwale

  • Newbie
  • *
  • Thank You
  • -Given: 0
  • -Receive: 0
  • Posts: 9
    • View Profile
Re: Local position of UISprite after UIRoot scaling
« Reply #11 on: April 23, 2014, 10:21:29 AM »
I tried to use the world corners of the sprite and convert them to the coordinate space of the parent:

  1. Transform spriteParent = sprite.transform.parent;
  2. Vector3[] worldCorners = sprite.worldCorners;
  3.  
  4. Vector3 corner0 = spriteParent.InverseTransformPoint(sprite.worldCorners[0]);
  5. Vector3 corner2 = spriteParent.InverseTransformPoint(sprite.worldCorners[2]);
  6.  
  7. Debug.Log("center: " + ((corner0 + corner2) * 0.5f));
  8. Debug.Log("size: " + new Vector2(corner2.x - corner0.x, corner2.y - corner0.y));
  9.  

However, I'm still getting the position and size of the sprite in the 4s resolution (it's wrong on iPad and iPhone 5). Is this what you had in mind?

ArenMook

  • Administrator
  • Hero Member
  • *****
  • Thank You
  • -Given: 337
  • -Receive: 1171
  • Posts: 22,128
  • Toronto, Canada
    • View Profile
Re: Local position of UISprite after UIRoot scaling
« Reply #12 on: April 24, 2014, 01:11:56 AM »
Simply adding the transform.localPosition to the local corners should be enough, but using world corners then transforming them back to local space will work too, sure. Note that you're retrieving the world corners once, then never using the value. Instead you re-retrieve the world corners twice more afterwards.

The values returned will be in NGUI's virtual pixels. Fixed Size means the values will be the same regardless of the device. That's what Fixed Size does -- the height of the screen doesn't change as far as NGUI is concerned.

nickwale

  • Newbie
  • *
  • Thank You
  • -Given: 0
  • -Receive: 0
  • Posts: 9
    • View Profile
Re: Local position of UISprite after UIRoot scaling
« Reply #13 on: April 24, 2014, 03:32:18 AM »
Ah I see, is it possible to get the position and size in real pixels then? The reason that I want these values is that I want to pass them to 3 tweens (TweenPosition, TweenWidth and TweenHeight) and when I pass the values in virtual pixels the result looks wrong in the iPad and iPhone 5 resolutions.

nickwale

  • Newbie
  • *
  • Thank You
  • -Given: 0
  • -Receive: 0
  • Posts: 9
    • View Profile
Re: Local position of UISprite after UIRoot scaling
« Reply #14 on: April 24, 2014, 04:59:09 AM »
OK I found out what the problem was. The sprite's local position, width, and height give me the correct values on every resolution, the problem was that I was querying these values in an Awake function when the sprite was disabled so it's position and scaling hadn't been set yet. Thanks for your help and sorry for the misunderstanding.