Tasharen Entertainment Forum

Support => NGUI 3 Support => Topic started by: electrodruid on January 22, 2013, 07:01:06 AM

Title: UIStretch, screen width and maintaining aspect ratio
Post by: electrodruid on January 22, 2013, 07:01:06 AM
I've searched around, and although I think people have asked similar questions, I don't think they've asked this one (or if they have, I haven't understood things well enough to realise that was what the conversation was about).

Say I've got a Sprite. I want to use a Stretch to scale it so that its width is (say) 25% of the screen width, and however high it needs to be to maintain its aspect ratio. How do I do that?
Title: Re: UIStretch, screen width and maintaining aspect ratio
Post by: ArenMook on January 22, 2013, 08:48:13 AM
Use UIStretch on it. X = 0.25, Y = 1.0
Title: Re: UIStretch, screen width and maintaining aspect ratio
Post by: electrodruid on January 22, 2013, 09:13:18 AM
That doesn't work for me. When I set the numbers to X=0.25, Y=1, the sprite becomes the height of the whole screen unless I choose Horizontal as the Style. And if I do that, my sprite doesn't maintain its aspect ratio - it always appears the same height even thought its width changes depending on the resolution.
Title: Re: UIStretch, screen width and maintaining aspect ratio
Post by: ArenMook on January 22, 2013, 10:06:49 AM
Oh sorry, missed the aspect ratio part. You'll want to write your own script for that. Width = Screen.width * 0.25. Height = Width * (Screen.height / Screen.width).
Title: Re: UIStretch, screen width and maintaining aspect ratio
Post by: electrodruid on January 23, 2013, 12:50:27 PM
That wasn't quite what I was looking for (using the screen aspect ratio just turned my widget square), but it got me close enough to write the script that does the job. The trick is to use the "original" aspect ratio of the widget to use in the scaling calculation - so a sprite made from a 100*200 pixel texture will always be twice as high as it is wide regardless of how the sprite is scaled. Unfortunately, the only way I can see to calculate that value is to call MakePixelPerfect() on the widget, get its cachedTransform.localScale and then do the scaling we actually want. It feels a bit inefficient and error-prone to me, but it's the only way I can see to get the information I need. Unless you know of another way?

Anyway, here's my script if anyone is interested:
  1. using UnityEngine;
  2.  
  3. [ExecuteInEditMode]
  4. [AddComponentMenu("NGUI/MyExtensions/Aspect Stretch")]
  5. public class UIAspectStretch : MonoBehaviour
  6. {
  7.         public enum Style
  8.         {
  9.                 None,
  10.                 BasedOnWidth,
  11.                 BasedOnHeight,
  12.                 BasedOnLongest,
  13.                 BasedOnShortest
  14.         }
  15.  
  16.         public Camera uiCamera = null;
  17.         public UIWidget widgetContainer = null;
  18.         public UIPanel panelContainer = null;
  19.         public Style style = Style.None;
  20.         public Vector2 relativeSize = Vector2.one;
  21.  
  22.         Transform mTrans;
  23.         UIRoot mRoot;
  24.         Animation mAnim;
  25.         Vector2 mOriginalWidgetSize = Vector2.one;
  26.  
  27.         void Awake () { mAnim = animation; }
  28.  
  29.         void Start ()
  30.         {
  31.                 if (uiCamera == null) uiCamera = NGUITools.FindCameraForLayer(gameObject.layer);
  32.                 mRoot = NGUITools.FindInParents<UIRoot>(gameObject);
  33.         }
  34.  
  35.         void Update ()
  36.         {
  37.                 if (mAnim != null && mAnim.isPlaying) return;
  38.  
  39.                 if (style != Style.None)
  40.                 {
  41.                         // We need to get the widget we'll be scaling
  42.                         UIWidget widget = GetComponentInChildren<UIWidget>();
  43.                        
  44.                         if(widget)
  45.                         {
  46.                                 if (mTrans == null) mTrans = transform;
  47.                                
  48.                                 // Get the widget's original size, from which we can calculate its desired aspect ratio.
  49.                                 // This is expensive and messy, but I don't see any other way :(
  50.                                 if(mOriginalWidgetSize == Vector2.one)
  51.                                 {
  52.                                         widget.MakePixelPerfect();
  53.                                         mOriginalWidgetSize = widget.cachedTransform.localScale;
  54.                                 }
  55.                                
  56.                                 // Get the rect that represents the area we want to stretch relative to
  57.                                 Rect rect = new Rect();
  58.        
  59.                                 if (panelContainer != null)
  60.                                 {
  61.                                         if (panelContainer.clipping == UIDrawCall.Clipping.None)
  62.                                         {
  63.                                                 // Panel has no clipping -- just use the screen's dimensions
  64.                                                 rect.xMin = -Screen.width * 0.5f;
  65.                                                 rect.yMin = -Screen.height * 0.5f;
  66.                                                 rect.xMax = -rect.xMin;
  67.                                                 rect.yMax = -rect.yMin;
  68.                                         }
  69.                                         else
  70.                                         {
  71.                                                 // Panel has clipping -- use it as the rect
  72.                                                 Vector4 pos = panelContainer.clipRange;
  73.                                                 rect.x = pos.x - (pos.z * 0.5f);
  74.                                                 rect.y = pos.y - (pos.w * 0.5f);
  75.                                                 rect.width = pos.z;
  76.                                                 rect.height = pos.w;
  77.                                         }
  78.                                 }
  79.                                 else if (widgetContainer != null)
  80.                                 {
  81.                                         // Widget is used -- use its bounds as the container's bounds
  82.                                         Transform t = widgetContainer.cachedTransform;
  83.                                         Vector3 ls = t.localScale;
  84.                                         Vector3 lp = t.localPosition;
  85.        
  86.                                         Vector3 size = widgetContainer.relativeSize;
  87.                                         Vector3 offset = widgetContainer.pivotOffset;
  88.                                         offset.y -= 1f;
  89.        
  90.                                         offset.x *= (widgetContainer.relativeSize.x * ls.x);
  91.                                         offset.y *= (widgetContainer.relativeSize.y * ls.y);
  92.        
  93.                                         rect.x = lp.x + offset.x;
  94.                                         rect.y = lp.y + offset.y;
  95.        
  96.                                         rect.width = size.x * ls.x;
  97.                                         rect.height = size.y * ls.y;
  98.                                 }
  99.                                 else if (uiCamera != null)
  100.                                 {
  101.                                         rect = uiCamera.pixelRect;
  102.                                 }
  103.                                 else return;
  104.                                
  105.                                 float rectWidth  = rect.width;
  106.                                 float rectHeight = rect.height;
  107.                                
  108.                                 if (mRoot != null && !mRoot.automatic && rectHeight > 1f)
  109.                                 {
  110.                                         float scale = mRoot.manualHeight / rectHeight;
  111.                                         rectWidth *= scale;
  112.                                         rectHeight *= scale;
  113.                                 }
  114.        
  115.                                 Vector3 localScale = mTrans.localScale;
  116.                                
  117.                                 // Apply the stretch style. This is what differentiates UIAspectStretch from UIStretch
  118.                                 Style myStyle = style;
  119.                                
  120.                                 if(myStyle == Style.BasedOnLongest)
  121.                                 {
  122.                                         myStyle = (rectWidth > rectHeight) ? Style.BasedOnWidth : Style.BasedOnHeight;
  123.                                 }
  124.                                 else if (myStyle == Style.BasedOnShortest)
  125.                                 {
  126.                                         myStyle = (rectWidth < rectHeight) ? Style.BasedOnWidth : Style.BasedOnHeight;
  127.                                 }
  128.  
  129.                                 if(myStyle == Style.BasedOnWidth)
  130.                                 {
  131.                                         localScale.x = relativeSize.x * rectWidth;
  132.                                         localScale.y = localScale.x * (mOriginalWidgetSize.y / mOriginalWidgetSize.x);
  133.                                 }
  134.                                 else if (myStyle == Style.BasedOnHeight)
  135.                                 {
  136.                                         localScale.y = relativeSize.y * rectHeight;
  137.                                         localScale.x = localScale.y * (mOriginalWidgetSize.x / mOriginalWidgetSize.y);
  138.                                 }
  139.                        
  140.                                 if (mTrans.localScale != localScale) mTrans.localScale = localScale;
  141.                         }
  142.                 }
  143.         }
  144. }