Search Unity

Window resize event

Discussion in 'Scripting' started by soy1bonus, Feb 1, 2010.

  1. soy1bonus

    soy1bonus

    Joined:
    Feb 1, 2010
    Posts:
    1
    Is there any way that unity notifies a C# script if the user resizes a window in the browser (and thus, the rendering area that Unity uses has been modified).

    I want the GUI to resize as well, so I need to know when to update the Rects.

    I though of having a class that stores the last width and height of the screen, and when they change, throw an event, but I was wondering if theres something like that in Unity already.
     
    _TheFuture_ and MilenaRocha like this.
  2. andeeeee

    andeeeee

    Joined:
    Jul 19, 2005
    Posts:
    8,768
    Hi, welcome to the forum!

    Unity doesn't get notified automatically of window size changes. However, if you can detect the change with some browser JavaScript in the page, you can call a function in the Unity player. Check out this manual page about communication between the web player and the browser.
     
  3. mateusbello

    mateusbello

    Joined:
    Jun 2, 2011
    Posts:
    15
    Hi,

    I had the same problem, I was trying to create a level that could be resized and I wanted some box coliders to be my boundaries and for that they should be always placed just outside the Screen.

    This code did the job to me:

    Code (csharp):
    1.  
    2. public class LevelBoundaries : MonoBehaviour
    3. {
    4.     Vector3 initialVectorBottomLeft;
    5.     Vector3 initialVectorTopRight;
    6.  
    7.     Vector3 UpdatedVectorBottomLeft;
    8.     Vector3 UpdatedVectorTopRight;
    9.  
    10.     void Start()
    11.     {
    12.         MainCamera = GameObject.Find("Main Camera");
    13.         initialVectorBottomLeft = MainCamera.camera.ScreenToWorldPoint(new Vector3(0, 0, 30));
    14.         initialVectorTopRight = MainCamera.camera.ScreenToWorldPoint(new Vector3(Screen.width, Screen.height, 30)); // I used 30 as my camera z is -30
    15.    }
    16.  
    17. void Update()
    18.     {
    19.         UpdatedVectorBottomLeft = MainCamera.camera.ScreenToWorldPoint(new Vector3(0, 0, 30));
    20.         UpdatedVectorTopRight = MainCamera.camera.ScreenToWorldPoint(new Vector3(Screen.width, Screen.height, 30));
    21.  
    22.         if ((initialVectorBottomLeft != UpdatedVectorBottomLeft) || (initialVectorTopRight != UpdatedVectorTopRight))
    23.         {
    24.             Debug.Log("Screen Size has changed")'
    25.        }
    26. }
    27.  

    I hope it helps as it took me a while to figure it out.
     
    puttin, relz6609 and jdsl like this.
  4. HarvesteR

    HarvesteR

    Joined:
    May 22, 2009
    Posts:
    531
    Hmm, I've done the same in a set of "screen safe" UI assets... it seems overkill to have to reposition the UI on Update though...

    But doing it only on Start is too little... especially if the game has an option panel to change resolution.

    Anyone know of a better way?

    Cheers
     
    jamestrue likes this.
  5. diablo

    diablo

    Joined:
    Jan 3, 2011
    Posts:
    736
    bump

    This is a pretty basic request, there should be some definitive answer on this. For example, let's take windows standalone... user is using the app and decides to resize the app window; what now? How do I know the resize occurred and how do I respond to it so that I can implement the necessary adjustments at runtime?
     
  6. diablo

    diablo

    Joined:
    Jan 3, 2011
    Posts:
    736
  7. tingham

    tingham

    Joined:
    Nov 1, 2007
    Posts:
    18
    Code (csharp):
    1. using System.Collections.Generic;
    2.  
    3. public class SimpleDetector : Monobehaviour {
    4.   public float lastScreenWidth = 0f;
    5.  
    6.   void Start(){
    7.    lastScreenWidth = Screen.width;
    8.   }
    9.  
    10.   void Update(){
    11.    if( lastScreenWidth != Screen.width ){
    12.      lastScreenWidth = Screen.width;
    13.      StartCoroutine("AdjustScale");
    14.    }
    15.    
    16.   }
    17.  
    18.   IEnumerator AdjustScale(){
    19.    // set up the other scene params.
    20.   }
    21. }
     
    Last edited: Aug 27, 2011
  8. NotYes

    NotYes

    Joined:
    Jul 5, 2012
    Posts:
    6
    another option would be a delegate ...

    Code (csharp):
    1.  
    2. using UnityEngine;
    3. using System.Collections;
    4.  
    5. public delegate void OnScreenSizeChange(Vector2 newScreenSize);
    6.    
    7. public class ScreenManager : MonoBehaviour {
    8.    
    9.     public OnScreenSizeChange onScreenSizeChanged;
    10.  
    11.     Vector2 lastScreenSize;
    12.    
    13.     void Awake() {
    14.         lastScreenSize = new Vector2(Camera.current.GetScreenWidth(), Camera.current.GetScreenHeight());
    15.     }
    16.    
    17.     void Update() {
    18.         Vector2 screenSize = new Vector2(Camera.current.GetScreenWidth(), Camera.current.GetScreenHeight());
    19.        
    20.         if(this.lastScreenSize != screenSize) {
    21.             this.lastScreenSize = screenSize;
    22.             if(OnScreenSizeChanged != null)
    23.                 onScreenSizeChanged(screenSize);
    24.         }
    25.     }
    26. }
    27.  
    is this bad in any way or form?
     
  9. kei_kvaartz

    kei_kvaartz

    Joined:
    Jul 25, 2012
    Posts:
    1
    All the solutions you guys have posted are "correct", in that they will compile and run. I try to avoid any Update() calls I can though. Regardless of whether or not the script has to scale the GUI every update, it still needs to check to see if it needs to, which is almost as bad. It seems like there could be something more elegant and efficient out there.

    Since any screen resizing would ultimately be the result of some sort of mouse clicking or dragging, maybe triggering the scale adjustment via a mouse event in OnGUI() would be less taxing?
     
    Last edited: Feb 18, 2013
    ctchmos likes this.
  10. scone

    scone

    Joined:
    May 21, 2008
    Posts:
    244
    So, it's become clear to me that the web player is the only one that actually can be resized. Why is this? Shouldn't we be able to resize standalone builds just like you can resize the editor window? This would be a nice feature :)
     
  11. graslany

    graslany

    Joined:
    Dec 26, 2012
    Posts:
    10
    @scone : Maybe its restricted by default to spare that kind of questions for developers precisely. I don't know if you can make a standalone resizable though.

    @kei_kvaartz : Checking the screen resolution in every frame seems the only solution to me ; trying to do it using the mouse is not reliable since you can probably change the window size by other means using system keyboard shortcuts. I think you can reduce the Update calls overhead by having a single Update() which calls every component that needs to do something on Update (I found this idea on this forum once). But it depends on Unity's internal architecture and that's probably something we don't want to mess with if we can avoid it.

    On the cost point of view, this test (comparing the windows dimensions to those of the previous frame) seems quite cheap to me. I mean, one frame is drawn every 20ms typically and modern computers can do a lot more things in 20ms than comparing 4 integers so it should be OK.
     
  12. scone

    scone

    Joined:
    May 21, 2008
    Posts:
    244
    AFAIK you can't. I'm sure that this is, in fact the reason, but I wonder if there is some kind of switch in DirectX or OpenGL for a non-resizable window that has some kind of performance boost. Either way, I would argue that extensibility is always better than fixed features, so how about a flag and an onResize event? :)
     
  13. xortrox

    xortrox

    Joined:
    Feb 13, 2011
    Posts:
    22
    jamestrue likes this.
  14. imtrobin

    imtrobin

    Joined:
    Nov 30, 2009
    Posts:
    1,548
    Why can't unity just fire an windowresize or window resolution changed event? It is trival to add and saves us tons of headache and these cpu wasting "hacks".
     
    ctchmos likes this.
  15. REV-FX

    REV-FX

    Joined:
    Oct 24, 2013
    Posts:
    28
    I agree that there still needs to be an OnWindowResized event available especially for resizing GUI elements as the GUI.Layout method rather seems to be a poor implementation using non-relative screen resolution parameters.

    Unity provides resizable standalone applications. Go to your projects Build Settings and press the Player Settings... button. It will then bring up more options within the Inspector panel. Then look at Resolutions and Presentation => Standalone Player Options. There is a checkbox for Resizable Window.
     
    Last edited: Oct 24, 2013
  16. Helical

    Helical

    Joined:
    Mar 2, 2014
    Posts:
    50
    I think the hack to check if Screen.width was changed is the best possible solution CPU wise. It might not be as elegant as a OnScreenResize event, but thats not such a problem. In any case whether OpenGL which has such an event, or Unity will add it to the monobehaviour arsental, In the end, that hack is still going to run on the CPU, there is no way around it.
     
  17. Helical

    Helical

    Joined:
    Mar 2, 2014
    Posts:
    50
    Code (csharp):
    1.  
    2.     int lastWidth;
    3.     int lastHeight;
    4.     bool stay = true;
    5.  
    6.     void Start(){
    7.         calculate_rects();
    8.         StartCoroutine( check_for_resize() );
    9.     }
    10.  
    11.     IEnumerator check_for_resize(){
    12.         lastWidth = Screen.width;
    13.         lastHeight = Screen.height;
    14.  
    15.         while( stay ){
    16.             if( lastWidth != Screen.width || lastHeight != Screen.height ){
    17.                 calculate_rects();
    18.                 lastWidth = Screen.width;
    19.                 lastHeight = Screen.height;
    20.             }
    21.             yield return new WaitForSeconds(0.3f);
    22.         }
    23.     }
    24.  
    25.     void OnDestroy(){
    26.         stay = false;
    27.     }
    I think this code achieves fairly efficient CPU usage, and readable too. calculate_rects() is the function I want to do each time A resize happens, however I dont want to check for a resize event every Update, or even FixedUpdate. So I add a coroutine that checks for a resize of width or height of the screen once every 0.3 seconds. Thats is fairly reasonable. And just to be sure that the coroutine exits if it is unecessary anymore, I change the bool stay to false in the OnDestroy() event. As a result the coroutine that activates calc_rects() if screen was resized every 0.3f seconds. And once the object to which this script attached to is destroyed. The coroutine is guaranteed to exit.

    *Note. If you have multiple instances of this script, then you will have multiple instances of this coroutine running, if you dont want that effect, make it a static singleton of something like that, or just call me and I'll show you how.

    *Note. that OnGUI() will be called twice per frame if you dont do
    Code (csharp):
    1. useGUILayout = false;
    at the start function. If you dont plan to use layouts, then deactivating that bool will activate OnGUI() only once per frame.

    *Note. the last Note doesn't really have anything to do with this thread, but its nice to know, since we care so much about our CPUs, no really, We care about our CPU more then we care about the women that would be angry at us if they read this :)
     
    Last edited: Mar 22, 2014
  18. JackRowa

    JackRowa

    Joined:
    Mar 6, 2015
    Posts:
    2
    i dont know if there is a better option, but here is my solution for now, needs unity's ugui. i used unity's uibehaviour and the event onrecttransformdimentionschange event. i need to add this script to some gameobject using recttransform system.


    Code (CSharp):
    1. using UnityEngine.UI;
    2. using UnityEngine.Events;
    3. using UnityEngine.EventSystems;
    4.  
    5. public delegate void OnWindowResize();
    6.  
    7. public class WindowChange :  UIBehaviour{
    8.  
    9.     public static WindowChange instance = null;
    10.     public OnWindowResize windowResizeEvent;
    11.  
    12.     void Awake() {
    13.         instance = this;
    14.     }
    15.  
    16.     protected override void OnRectTransformDimensionsChange ()
    17.     {
    18.         base.OnRectTransformDimensionsChange ();
    19.         if(windowResizeEvent != null)
    20.             windowResizeEvent();
    21.     }
    22. }
     
  19. BeyondTemptation

    BeyondTemptation

    Joined:
    Dec 18, 2016
    Posts:
    4

    Sorry I am new to programming, I can understand what the code does, but how can we use it in other classes?
     
  20. fangyan67

    fangyan67

    Joined:
    Feb 25, 2014
    Posts:
    4
    Thank you, it's very useful to me.
     
  21. methos5k

    methos5k

    Joined:
    Aug 3, 2015
    Posts:
    8,712
    I wanted to add to this, for any future readers. The OnRectTransformDimensionsChange is useful, and you can add that even in a monobehaviour, on say the canvas.

    However, when I wrote mine, I included a coroutine to wait for end of frame before raising the event. I haven't (re)tested this in a while, but I assume I had a reason for doing it. :)
    I guess, if you find it's not working as expected, give that a try.
     
  22. alvmoral

    alvmoral

    Joined:
    Dec 11, 2018
    Posts:
    4
  23. alvmoral

    alvmoral

    Joined:
    Dec 11, 2018
    Posts:
    4
    Try This

    You can define an EventHandler in a Script:

    1- Create a script with this:

    Code (CSharp):
    1. using UnityEngine;
    2.    
    3. public class WindowManager : MonoBehaviour {
    4.      public delegate void ScreenSizeChangeEventHandler(int Width, int Height);       //  Define a delgate for the event
    5.      public event ScreenSizeChangeEventHandler ScreenSizeChangeEvent;                //  Define the Event
    6.      protected virtual void OnScreenSizeChange(int Width, int Height) {              //  Define Function trigger and protect the event for not null;
    7.          if (ScreenSizeChangeEvent != null) ScreenSizeChangeEvent(Width, Height);
    8.      }
    9.      private Vector2 lastScreenSize;
    10.      public static WindowManager instance = null;                                    //  Singleton for call just one instance
    11.      void Awake() {
    12.          lastScreenSize = new Vector2(Screen.width,Screen.height);
    13.          instance = this;                                                            // Singleton instance
    14.      }
    15.      void Update() {
    16.          Vector2 screenSize = new Vector2(Screen.width, Screen.height);
    17.          if (this.lastScreenSize != screenSize) {
    18.              this.lastScreenSize = screenSize;
    19.              OnScreenSizeChange(Screen.width, Screen.height);                        //  Launch the event when the screen size change
    20.          }
    21.      }
    22. }
    23.  

    2- Associate this script to any basic GameObject : (Main Camera for example)

    3- Now You can consume the event anywhere:


    Code (CSharp):
    1.      private void Start () {
    2.          WindowManager.instance.ScreenSizeChangeEvent += Instance_ScreenSizeChangeEvent;
    3.      }
    4.      private void Instance_ScreenSizeChangeEvent(int Width, int Height) {
    5.          Debug.Log("Screen Size Width = " + Width.ToString() + "  Height = " +  Height.ToString());
    6.      }
    7.  
     
    seokhunShin likes this.
  24. uani

    uani

    Joined:
    Sep 6, 2013
    Posts:
    232
    Hi,

    is now any event fired when the Unity player window resolution changes either due to player window resizing, screen orientation change or full screen resolution changed from Unity engine itself without me having to check it myself every (few) frame(s) ?
     
  25. BahuMan

    BahuMan

    Joined:
    Jan 26, 2014
    Posts:
    4
    I found this page while googling for unity resize events.
    The easiest way I've found so far is to create a script on my top-level UI Canvas, and override the method "OnRectTransformDimensionsChange"
     
    B3Designs, Seltzer and uani like this.
  26. angelonit

    angelonit

    Joined:
    Mar 5, 2013
    Posts:
    40
    Yep worked for me, you can just use this

    Code (CSharp):
    1.    
    2. private void OnRectTransformDimensionsChange()
    3.     {
    4.         //Do the things
    5.     }
    6.  
     
  27. seokhunShin

    seokhunShin

    Joined:
    Jun 10, 2023
    Posts:
    1
    Love you man it works!!
     
  28. adeick8

    adeick8

    Joined:
    Jan 4, 2023
    Posts:
    8
    It looks like the Canvas class is a sealed class. How would you override this method?
     
  29. TheTrueDuck

    TheTrueDuck

    Joined:
    Feb 13, 2020
    Posts:
    1
    It's not an override, it's just a unity callback like OnEnable. All you have to do is create a new canvas and put this script on it! (CanvasScaler and GraphicRaycaster components can be removed)

    Code (CSharp):
    1. using System;
    2. using UnityEngine;
    3.  
    4. public class ScreenDetector : MonoBehaviour
    5. {
    6.     public static event Action<Vector2> OnScreenSizeChanged;
    7.  
    8.     private void OnRectTransformDimensionsChange()
    9.     {
    10.         OnScreenSizeChanged?.Invoke(new Vector2(Screen.width, Screen.height));
    11.  
    12.         Debug.Log($"{Screen.width}x{Screen.height}");
    13.     }
    14. }
    Then in your actual code you can subscribe to the event like this:
    Code (CSharp):
    1. ScreenDetector.OnScreenSizeChanged += SetRectPadding;
     
    unity_Njh9-JLc2ovm6w likes this.