Search Unity

GUITexture Screen Size

Discussion in 'Immediate Mode GUI (IMGUI)' started by BlackMantis, Jun 7, 2010.

  1. BlackMantis

    BlackMantis

    Joined:
    Feb 7, 2010
    Posts:
    1,475
    When the screen resolution is changed at game start is the only way to get a guitexture to resize is to script it? Meaning there is no default settings for auto resizing. :D
     
  2. andeeeee

    andeeeee

    Joined:
    Jul 19, 2005
    Posts:
    8,768
    There are no auto-resizing options for the GUI but it usually isn't too difficult to implement in a script. A common technique is to design the GUI for a particular resolution and the use the GUI matrix to rescale it for the screen size. Say you originally designed the GUI for 800x600. You can use the following code at the start of the OnGUI function to scale to the screen size:-
    Code (csharp):
    1.  
    2. var horizRatio = Screen.width / 800;
    3. var vertRatio = Screen.height / 600;
    4.  
    5. GUI.matrix = Matrix4x4.TRS (Vector3(0, 0, 0), Quaternion.identity, Vector3 (horizRatio, vertRatio, 1));
    Whether or not the images, etc, will distort in an aesthetically pleasing way is another matter ;-)
     
    BitGamey and popopeoeoodleop like this.
  3. BlackMantis

    BlackMantis

    Joined:
    Feb 7, 2010
    Posts:
    1,475
    Thanks. I'm still trying to figure it out though. I'm trying to have a guitexture with its ability to change color and scale. That will adjust to screen res. Because the problem i'm having is i have a health and exp bar that is controled by code to scale its pix when damage. But that bar moves out of the screen when res is changed so i'm trying to have it adjust to the res. The thing is i'm not finding anything on how to get a guitexture in a guifunction group or layout area.
    So how would i fix this problem or go an alernate direction? :D
     
  4. andeeeee

    andeeeee

    Joined:
    Jul 19, 2005
    Posts:
    8,768
    You can't render GUIText/GUITexture objects into the compound controls of the GUI/GUILayout class. It's probably best to use GUI.Label to replace GUITexts and GUI.DrawTexture to replace GUITextures.
     
  5. MrDude

    MrDude

    Joined:
    Sep 21, 2006
    Posts:
    2,569
    I like the Matrix idea but if you are interested, I wrote a script a while ago that I have been using all this time that might just help you out...

    Basically, you hard code your desired screen resolution (in my case, I opted for 800x600), then , you define an area where you want something to be placed (one of 9 locations varying combinations of middle, top, bottom, left , right and center).

    Now, what it does is, you give it screen coordinates as if the resolution is always 800x600 but if the screen is actually smaller then it will scale down the area to match. So if you defined the top right corner to use an image and the size you gave that area is 1/4 the size of the screen and you then scale the scene down, the area will always return the top right 1/4 the size of the screen.

    on the other hand, if your resolution gets larger, instead of just stretching the area to fit, the areas you defined are then repositioned and takes up the exact pixel size you defined but oriented according to the borders you set for the area of the screen you were using.

    An example use would be something like this:
    Code (csharp):
    1.  
    2. var TopRight : ScreenArea;
    3. var HealthBar : Texture;
    4.  
    5. function Start()
    6. {
    7. //this would be setup in the inspector...
    8. TopRight.BorderH = 5;
    9. TopRight.BorderV = 5;
    10. TopRight.Size.width = 200; //quarter of the screen
    11. TopRight.Size.height = 150; //quarter of the screen
    12. TopRight.Position = eScreenPosition.TopRight;
    13. }
    14.  
    15. function OnGUI()
    16. {
    17. var pos : Rect = TopArea.Area();
    18. GUI.DrawTexture(pos, HealthBar);
    19. }
    20.  
    So if you scale the scene down to iPhone size, the TopRight.Area() will return Rect(355, 5, 120, 80) but if you scale it up to 1024x768 it will return Rect(819, 5, 200, 150)

    if this might be of use to you I wouldn't mind uploading it when I get home... Just let me know if you would want it or not :)
     
  6. Lostlogic

    Lostlogic

    Joined:
    Sep 6, 2009
    Posts:
    693
    I'd like to see the code if you can upload it. :)
     
  7. MrDude

    MrDude

    Joined:
    Sep 21, 2006
    Posts:
    2,569
    Code (csharp):
    1.  
    2. enum eScreenPos {
    3.     TopLeft             = 0,
    4.     TopCenter           = 1,
    5.     TopRight            = 2,
    6.     MiddleLeft          = 3,
    7.     MiddleCenter        = 4,
    8.     MiddleRight         = 5,
    9.     BottomLeft          = 6,
    10.     BottomCenter        = 7,
    11.     BottomRight         = 8
    12. }
    13.  
    14. class ScreenPosition extends Object
    15. {
    16.     var scorePosition       : eScreenPos        = eScreenPos.TopRight;
    17.     var width               : int = 255;
    18.     var height              : int = 124;
    19.     var borderHor           : int = 0;
    20.     var borderVert          : int = 0;
    21.     private var _area       : Rect;
    22.  
    23.     function GetArea()      : Rect
    24.     {
    25.         return _area;
    26.     }
    27.    
    28.     function DefinedArea()  : Rect
    29.     {
    30.         var posLeft         : int;
    31.         var posTop          : int;
    32.        
    33.         var tempRec         : Rect = CalculateScreenArea(width, height);
    34.         var wPC = tempRec.width;
    35.         var hPC = tempRec.height;
    36.    
    37.         switch(scorePosition)
    38.         {
    39.             case eScreenPos.TopLeft:
    40.                 posLeft     = borderHor;
    41.                 posTop      = borderVert;
    42.                 break;
    43.            
    44.             case eScreenPos.TopCenter:
    45.                 posLeft     = (Screen.width / 2) - (wPC / 2);
    46.                 posTop      = borderVert;
    47.                 break;
    48.            
    49.             case eScreenPos.TopRight:
    50.                 posLeft     = Screen.width - wPC - borderHor;
    51.                 posTop      = borderVert;
    52.                 break;
    53.            
    54.             case eScreenPos.MiddleLeft:
    55.                 posLeft     = borderHor;
    56.                 posTop      = (Screen.height / 2) - (hPC / 2);
    57.                 break;
    58.            
    59.             case eScreenPos.MiddleCenter:
    60.                 posLeft     = (Screen.width / 2) - (wPC / 2);
    61.                 posTop      = (Screen.height / 2) - (hPC / 2);
    62.                 break;
    63.            
    64.             case eScreenPos.MiddleRight:
    65.                 posLeft     = Screen.width - wPC - borderHor;
    66.                 posTop      = (Screen.height / 2) - (hPC / 2);
    67.                 break;
    68.            
    69.             case eScreenPos.BottomLeft:
    70.                 posLeft     = borderHor;
    71.                 posTop      = Screen.height - hPC - borderVert;
    72.                 break;
    73.            
    74.             case eScreenPos.BottomCenter:
    75.                 posLeft     = (Screen.width / 2) - (wPC / 2);
    76.                 posTop      = Screen.height - hPC - borderVert;
    77.                 break;
    78.            
    79.             case eScreenPos.BottomRight:
    80.                 posLeft     = Screen.width - wPC - borderHor;
    81.                 posTop      = Screen.height - hPC - borderVert;
    82.                 break;
    83.         }
    84.        
    85.         _area = Rect ( posLeft,  posTop, wPC, hPC);
    86.         return _area;
    87.     }
    88.  
    89.     function CalculateScreenArea(w : int, h : int) : Rect
    90.     {
    91.         var rec : Rect = new Rect(0,0,w, h);
    92.  
    93.         if (Screen.height < 600)
    94.         {
    95.             rec.width = Mathf.FloorToInt( Screen.width  *  (1.0 / (800.0 / w ) ) );
    96.             rec.height = Mathf.FloorToInt( Screen.height *  (1.0 / (600.0 / h) ) );
    97.         }
    98.    
    99.         return rec;
    100.     }
    101. }
    102.  
    103.  
     
  8. Lostlogic

    Lostlogic

    Joined:
    Sep 6, 2009
    Posts:
    693
    Cool, thanks!

    How would you go about changing the aspect ratio in your output? Would you change some of the hard-coded values in the script?
     
  9. MrDude

    MrDude

    Joined:
    Sep 21, 2006
    Posts:
    2,569
    Just replace the 600 and 800 in the CalculateScreenArea() function to whatever you want to be your target screen resolution.

    Everything else you do is then relative to that. This means that if you define a rectangular area in an aspect ratio like 16:9 but the person using your software then changes to an aspect ratio of 4:3 then your defined area will distort to be more in line with the new aspect ratio...
     
  10. Eric5h5

    Eric5h5

    Volunteer Moderator Moderator

    Joined:
    Jul 19, 2006
    Posts:
    32,401
    If you set the x scale of a GUITexture to, say, .5, then it will be 50% the screen width, no matter what the resolution is. If you set it to .2 then it's 20% of the screen width. Same thing for the height. If you set the x position to .5, then it appears halfway across the screen, same for y position and height.

    However, you still have to do scripting if you care about the aspect ratio appearing correctly. For example, if you have a circle made with a GUITexture like this and scale it so it's perfectly circular on a 16:10 display, it will be distorted on 16:9 or 4:3 unless you compensate for that.

    --Eric
     
  11. Aiursrage2k

    Aiursrage2k

    Joined:
    Nov 1, 2009
    Posts:
    4,835
    I just call my function screenRect which excepts coordinates to be in screen coordinates (0,0 to 1,1) and then will return the actual rect.
    Code (csharp):
    1.  
    2.     public static Rect screenRect(float tx,
    3.                                              float ty,
    4.                                              float tw,
    5.                                              float th)
    6.     {
    7.         float x1 = tx * Screen.width;
    8.         float y1 = ty * Screen.height;
    9.        
    10.         float sw = tw * Screen.width;
    11.         float    sh = th * Screen.height;
    12.        
    13.        
    14.         return new Rect(x1,y1,sw,sh);
    15.     }
     
  12. spaceMan-2.5

    spaceMan-2.5

    Joined:
    Oct 21, 2009
    Posts:
    710
    excuse me, where do i must to put this script.. just into the camera, or in every GUI's related gameobject?... Thanks.
     
  13. andeeeee

    andeeeee

    Joined:
    Jul 19, 2005
    Posts:
    8,768
    Once assigned, the GUI matrix stays the same until you assign it again. If the whole GUI needs to change resolution throughout, then you could just put this code in the Start function of one of your objects. If you need to go back to the default resolution at any time, you must set the matrix before rendering any GUI elements that will use it.
     
  14. spaceMan-2.5

    spaceMan-2.5

    Joined:
    Oct 21, 2009
    Posts:
    710
    ok thanks !..
     
  15. felipi arena

    felipi arena

    Joined:
    Jun 7, 2010
    Posts:
    25
    I set it in the start of one of my objects, but its returning a null reference error. I'm totally noob btw

    What am I doing wrong?

    Before that:
    I've tried to manually multiply screen cords to a resize factors like:
    ResizeX: Screen.width/600;
    ResizeY: Screen.height/800;

    and everytime i draw a gui i multiply the x and y cords by those factors, but the results of those divisions are always 0 or 1 instead of a damn float, so its not resizing anything.

    i hate Gui.
     
  16. andeeeee

    andeeeee

    Joined:
    Jul 19, 2005
    Posts:
    8,768
    You can solve the division problem by using a decimal point in the numbers:-
    Code (csharp):
    1. resizeX = Screen.width / 600.0;
    Without it, the 600 is treated as an integer and since Screen.width is also an integer the compiler will use integer division. As for the null reference, perhaps you can post your code and state which line of code is throwing the error.
     
  17. mmuller

    mmuller

    Joined:
    Nov 23, 2010
    Posts:
    92
    Andeee,

    Does this also scale any fonts accordingly to on iOS/Android devices?

    At the moment I have three sets of fonts which I switch between based on screen resolution but this would be a much better way to do things...

    Regards,

    mm
     
  18. spinaljack

    spinaljack

    Joined:
    Mar 18, 2010
    Posts:
    992
    The GUI.matrix line only works in the OnGUI function, you get the null reference error if you put it in the Start function

    And as far as I can tell the text does scale with the GUI but the results aren't pretty if you go to the extremes
     
  19. andererandre

    andererandre

    Joined:
    Dec 17, 2010
    Posts:
    683
    I doubt it will. The problem is that Unity iOS isn't able to scale fonts at all - no matter what you code. You will always need at least 2 fonts (retina/normal DPI) for each font size you need.

    Oh and I just want to say to everyone: avoid using the scale matrix Unity gave us. It scales the buttons and fonts pretty ugly and rapes the user interface pretty badly. Take some time to write your own wrapper class around the Unity GUI class, it took me some time to get a perfectly scaling interface without any quality losses or aspect ratio problems, but it's worth the effort. You should always maintain the aspect ratio of your interface no matter what the aspect ratio of the screen is - just scale both height and width of your GUI elements relative to the height of the current screen resolution. After that, calculate the new positions of your elements based on both the screen resolution and the size of your GUI.
     
  20. U7Games

    U7Games

    Joined:
    May 21, 2011
    Posts:
    943
    does this works only in builds.? in editor i cant get it work...
     
  21. U7Games

    U7Games

    Joined:
    May 21, 2011
    Posts:
    943
    I can see that if you are using guiTexture, you better arrange your textures on screen with Transform, do no use pixel inset...
     
  22. roamcel

    roamcel

    Joined:
    Sep 15, 2011
    Posts:
    17
    Sadly this doesn't seem to affect my guitextures at all. Perhaps no longer working in unity 3.4? Can't really tell, but after 3 hours wasted I'm giving up on this method.
     
  23. Genie

    Genie

    Joined:
    Sep 12, 2009
    Posts:
    23
    tx for the tips
     
  24. fdfragoso

    fdfragoso

    Joined:
    Nov 15, 2010
    Posts:
    35
    Hi everyone, first of all, very good topic!

    I'm having the follow error here, I couldn't make GUI.matrix works with GUI.TextField, I'm trying to see in the editor window, because I have only one tablet with android to test, but the app will run in any android tablet.

    Follow the code:

    Code (csharp):
    1.  
    2. using UnityEngine;
    3. using System.Collections;
    4.  
    5. public class TextController : MonoBehaviour {
    6.    
    7.     public GUIStyle s_textField;
    8.     public string url = "CHANGE URL HERE";
    9.    
    10.     private int nativeVerticalResolution = 800
    11.         ;
    12.    
    13.     // Use this for initialization
    14.     void Start () {
    15.    
    16.     }
    17.    
    18.     // Update is called once per frame
    19.     void Update () {
    20.    
    21.     }
    22.    
    23.     void OnGUI()
    24.     {
    25.         int horizRatio = Screen.width / 1280;
    26.         int vertRatio = Screen.height / 800;
    27.  
    28.         GUI.matrix = Matrix4x4.TRS (new Vector3(0, 0, 0), Quaternion.identity, new Vector3 (horizRatio, vertRatio, 1));
    29.         //GUI.matrix = Matrix4x4.TRS(new Vector3(0, 0, 0), Quaternion.identity, new Vector3 (Screen.height / nativeVerticalResolution, Screen.height / nativeVerticalResolution, 1));
    30.        
    31.         if (Event.current.type == EventType.KeyDown  (Event.current.keyCode == KeyCode.KeypadEnter || Event.current.keyCode == KeyCode.Return))
    32.         {
    33.             Debug.Log("[ENTER] Typed an URL");
    34.         }
    35.        
    36.         GUI.SetNextControlName("URL");
    37.         url = GUI.TextArea(new Rect(Screen.width - Screen.width/2 - 45f, Screen.height - Screen.height/2 + 35f, 302f, 41f), url, 256, s_textField);
    38.     }
    39. }
    40.  
    41.  
     
  25. Meltdown

    Meltdown

    Joined:
    Oct 13, 2010
    Posts:
    5,822
    I found the best way to do GUI texture sort of stuff is to create a simple 2 triangle plane and attach it to the camera.Once you've got it aligned how you want in the view, no matter the resolution or screen size it always looks good.

    If you need to scale a power bar for instance, by default it scales smaller/larger from middle, thus affecting both ends.
    To resolve this use the CreatePlane.cs script from the Unify wiki and set the anchor value to whatever anchor your scaling requires.

    Not to mention you get away from using the ghastly OnGUI()
     
    Last edited: Feb 15, 2012
  26. bharatbarde

    bharatbarde

    Joined:
    Dec 29, 2011
    Posts:
    13
    I download that CreatePlane.cs placed in a folder as mentioned on the wiki

    please can u tell me how to use it in my script or any other way to fix this

    I am moving GuiTexture using itween it loooks better at 640 x 480 (web build i am using) but getting problem once resolution changed
    I need to work it on 1024 x768 and 16:9 ratio screen resolution

    Gui texture name is "InfernoFont"
    pixel inset (0,0)
    YPosition 0.55
    starting XPosition -0.95

    Intro.js ,
    Code (csharp):
    1. function Start()
    2. {
    3.   var infernoFont = GameObject.Find("InfernoFont");
    4. iTween.MoveTo(infernoFont,{"x":0.23,"time":2,"transition":"linear"});
    5. }
    6.  
     
  27. Riagan

    Riagan

    Joined:
    Feb 11, 2013
    Posts:
    7

    I just wanted to say thanks. This trick saved me a ton of time!

    - Eric
     
  28. Eric5h5

    Eric5h5

    Volunteer Moderator Moderator

    Joined:
    Jul 19, 2006
    Posts:
    32,401
    OnGUI isn't faster by any means. It's immediate mode, so it has to be re-computed every frame, whereas GUIText and Textures are components attached to standard GameObjects that require no code to exist. They're more convenient/faster to use in some cases, and don't require GUI.matrix, since they will already scale to different screen resolutions automatically without code.

    --Eric
     
  29. GodModeTech

    GodModeTech

    Joined:
    Jun 21, 2010
    Posts:
    66
    The problem with getting rid of the pixel inset (for width and height) and using scale is that you cannot avoid that your GUI element will deform. So what I just tried is this. You use the transform position (at the GUITexture) to let the UnityEngine handle the position using screen coordinates as usual, but you control the width and height of the element setting the pixelInset yourself, based on a ratio that you calculate using your base screen height with the current screen height (or you could use width for the calculation). That way you ensure that both width and height of the image are multiplied by the same value and it keeps the same aspect ratio. To me, it seems to work fairly well. Try it and tell me what you think. The code used to update the pixelInset can be put in a monobehaviour in the same gameObject as the GUITexture. (If your screen size is not going to change during the game, you can do the calculus just once at the Start method.) The code is like this:

    Code (csharp):
    1. using UnityEngine;
    2. using System.Collections;
    3.  
    4. public class GUITextureResizer : MonoBehaviour
    5. {
    6.     private GUITexture _guiTextureRef;
    7.    
    8.     public const float BASE_WIDTH = 800;
    9.     public const float BASE_HEIGHT = 600;
    10.    
    11.     private float _baseHeightInverted;
    12.    
    13.     private float _originalPixelInsetWidth;
    14.     private float _originalPixelInsetHeight;
    15.    
    16.     void Awake()
    17.     {
    18.         _guiTextureRef = GetComponent<GUITexture>();
    19.     }
    20.    
    21.     void Start()
    22.     {
    23.         _baseHeightInverted = 1/BASE_HEIGHT;
    24.         _originalPixelInsetWidth = _guiTextureRef.pixelInset.width;
    25.         _originalPixelInsetHeight = _guiTextureRef.pixelInset.height;
    26.     }
    27.    
    28.     void FixedUpdate()
    29.     {  
    30.         float ratio = Screen.height * _baseHeightInverted;     
    31.        
    32.         _guiTextureRef.pixelInset = new Rect(0, 0, _originalPixelInsetWidth * ratio, _originalPixelInsetHeight * ratio);
    33.     }
    34. }
    So, remember, you set your initial pixelInset width and height using the inspector of the GUITexture. The x and y for the pixelInset is set to 0. The scale of the transform is set to 0, 0, 1.

    This is how it works:
    http://www.youtube.com/watch?v=cEwQJpAphak&feature=youtu.be

    I just saw that it does not preserves the distances to right edges, but it still works fairly well for must purposes I guess.
     
    Last edited: Aug 24, 2013