GML Advanced resolution manager (very mobile friendly)

Mehdi

Member
hi @gkri
Thank you for your amazing tutorial.

But a question here:
On my phone, when I test your examples, by rotating the device, screen rotates accordingly from portrait to landscape. However it doesn't seem to work when the device is rotated on to portrait flipped mode. I mean when I set my phone in portrait flipped state (upside down), no orientation change seems to happen.

(I tested all combinations of orientation in android setting but still no change)
 

gkri

Member
hi @gkri
Thank you for your amazing tutorial.

But a question here:
On my phone, when I test your examples, by rotating the device, screen rotates accordingly from portrait to landscape. However it doesn't seem to work when the device is rotated on to portrait flipped mode. I mean when I set my phone in portrait flipped state (upside down), no orientation change seems to happen.

(I tested all combinations of orientation in android setting but still no change)
Something I learnt when I was writing this code, is that some android devices have the flipped portrait orientation locked out of their behavior. Check the thread I quote bellow.

some phones are set not to flip portrait. probably you are using samsung. anyway it must be about mobile device.
 
Last edited:

Mehdi

Member
Something I learnt when I was writing this code, is that some android devices have the flipped portrait orientation locked out of their behavior. Check the thread I quote bellow.
You're right. No other commercial games on my phone seem to rotate in flipped portrait mode as well. And therefore no problem is there with your code. The problem exists in the phones.
 

gkri

Member
You're right. No other commercial games on my phone seem to rotate in flipped portrait mode as well. And therefore no problem is there with your code. The problem exists in the phones.
I suppose they lock that orientation for a reason. Also, I am always wondering why I cannot use my phone horizontal while I am at the home screen...

By the way, if you plan to make a game that supports both orientations, make sure to watch this video by @Pixelated_Pope:

 

gkri

Member
This is a minor but necessary update. Compatible with GMS2.3.7.403 and later. The latest version of the scripts are backwards compatible and they won't break your projects. Just remove the old version before importing the new one.

Now all arguments except the _design_value in the set_resolution are optional meaning that:

set_resolution(640);

is the same as:

set_resolution(640, false, false, false);

The set_gui_size script has been impoved. Both arguments are optional now. If both arguments omitted then the GUI layers size will be the same as the game's resolution. If either argument omitted then it will be calculated to fit the current aspect ratio of the game's resolution.

 

Mehdi

Member
I've already used your amazing script in one of my projects (previous version of your code). If I don't update that with the latest script, am I going to face problems or not?
 

gkri

Member
I've already used your amazing script in one of my projects (previous version of your code). If I don't update that with the latest script, am I going to face problems or not?
It is a minor update that takes advantage of the optional function arguments that introduced at GMS2.3.7.403
Updating the scripts will not break your project, but just in case always keep back up or source control (updating or not).

If you want your next game to have dynamic orientation, then the updated set_gui_size script will be very handy. Brief example:

While being with landscape orientation, if you use:

Code:
set_gui_size(gui_size); // the gui_size is now the 1st arg, the 2nd is omitted and calculated by the script
then by switching to portrait you can set it as:

Code:
set_gui_size(,gui_size);  // the gui_size is now the 2nd arg, the 1st is omitted and calculated by the script
And after that you can reposition your UI elements accordingly.
 

Mehdi

Member
HI @gkri
Thank you once more for your amazing script.
Just another question: Is that enough to just use "set_camera" once in the first room? Or shall we use it in every subsequent room too?
 

gkri

Member
HI @gkri
Thank you once more for your amazing script.
Just another question: Is that enough to just use "set_camera" once in the first room? Or shall we use it in every subsequent room too?
set_camera should be executed once, in every room. For the first init room is not necessary, it won't harm if runs there too. That makes the init consistent object (in my examples), a perfect candidate to execute set_camera in room start event.

And thank you for your kind words! :D

PS Please note that the set_camera is a very minimal, but working solution that is not suited for all use cases. In cases that you need, thus, you implement more complex functionalities, it might be a good idea to have a dedicated camera object and execute all camera related code in that object.
 

Mehdi

Member
Aha, ... I'm beginning to find out what's he problem of my project.
For the sake of a true parallax system, I have implemented a 3d camera in my 2d side-scroller. (using perspective projection). And I think using perspective projection causes your camera view manipulation functions to lose functionality.

 

gkri

Member
Aha, ... I'm beginning to find out what's he problem of my project.
For the sake of a true parallax system, I have implemented a 3d camera in my 2d side-scroller. (using perspective projection). And I think using perspective projection causes your camera view manipulation functions to lose functionality.

Very beautiful project and graphics! Congrats! I cannot see any issue from that video though...
 

Mehdi

Member
Very beautiful project and graphics! Congrats! I cannot see any issue from that video though...
Thank you šŸ˜
No issue at all. But it's getting view dimention from the function :
Code:
matrix_build_projection_perspective
Therefore if I even dont use your function: set_camera nothing bad happens. Because 3d projection makes ordinary 2d camera useless.

No problem at all and thank you.
 

gkri

Member
Could you please describe your issue with more details? I find no issues when I maximize the window on my pc.
 

Mehdi

Member
Hello @gkri
I'm working on a puzzle project which has 720*1280 portrait resolution. The game has a single, fixed-sized room with no views at all.(It doesn't need views) When I use your script, if I set the DESIGN_WIDTH as the criterion, the game on my device would have an empty space down below. And if I set the DESIGN HEIGHT as the criterion, a part of the room falls outside the view. What should I do.
Note: My device display resolution is 1080*2400.
Thanks in advance. šŸ™
 

gkri

Member
My guess is that the issue is in your designs. Stick with the DESIGN_WIDTH and be smart and creative on how to fill the empty space. (See as example the pic with the buildings and the sky - sorry not on my pc to repost it or link it here)

If my guess is wrong, then I'll need more details, like your complete arguments list you use in the set_resolution, how you handle camera and some screenshots.

EDIT: I managed to quote it. Click on the quote bellow and see the related spoiler and text:

See that picture of a design example
 
Last edited:

gnysek

Member
I've got a boring morning, and while checking tutorials forum I've hit this topic, and noticed that code in first post got looot of repetitions or very similar code, so I've decided to try a little optimization as an exercise for my brain, in accompany to morning coffee:

GML:
global.ideal_width = 0;
global.ideal_height = 0;

///Written by George Kritikos (Harpwood studio) - Based on code written by Pixelated_Pope
///@License MIT License https://opensource.org/licenses/MIT
///@func set_resolution(design_value, is_design_vertical, is_orientation_vertical, resize_all_rooms, [scale], overide_other_value [optional])
///@arg {Real} _design_value                  width or height of ideal resolution
///@arg {Bool} _is_design_value_vertical      When true, the design_value is condidered as height; when false, as width
///@arg {Bool} _is_orientation_vertical       When true, the screen orientation is considered as portrait; when false, as landscape
///@arg {Bool} _resize_all_rooms              When true: Rooms (except room index 0), will be resized to resulting value
///@arg {Real} _scale                         (Optional) Scale the game window to better fit the monitor. Will ommited on any non windows and non macos builds
///@arg {Real} _overide_other_value           (Optional) Overides the value other than the design_value arg for a custom aspect ratio. Will ommited like scale arg
function set_resolution(_design_value = 1280, _is_design_value_vertical = true, _is_orientation_vertical = false, _resize_all_rooms = false, _scale = 1, _overide_other_value = undefined) {
    _scale ??= 1;

    //detect os_type only if is GMS2 IDE approprate
    var _os_type = os_type == os_windows ? os_windows : os_macosx;

    // The design value is either the design width or height. Every calculation in build with Test -> VM get a temporary scaling
    var _desing_width    = os_type == _os_type ? _design_value * _scale : _design_value;
    var _desing_height   = os_type == _os_type ? _design_value * _scale : _design_value;

    var _real_width, _real_height, _aspect_ratio, _ideal_width, _ideal_height;
   
    var _h = os_type == _os_type ? (display_get_height())  * _scale : display_get_width();
    var _w = os_type == _os_type ? (display_get_width())   * _scale : display_get_height();
   
    _real_width   = _is_orientation_vertical ? _h : _w;
    _real_height  = _is_orientation_vertical ? _w : _h;
    _aspect_ratio = _real_width >= _real_height ? _real_height / _real_width : _real_width / _real_height;
    _ideal_height = _desing_height;
    _ideal_width  = _desing_width;
   
    if (_is_orientation_vertical != _is_design_value_vertical) {
        _aspect_ratio = 1/_aspect_ratio; // division is multiplication by reciprocal
    }
   
    if _is_design_value_vertical {
        //The design value is reffering to vertical so we calculate the horizontal
        _ideal_height = _desing_height;
        if os_type == _os_type then _ideal_width = _overide_other_value == undefined ? round(_ideal_height * _aspect_ratio) : _overide_other_value * _scale;
        else _ideal_width = round(_ideal_height * _aspect_ratio);
    } else {
        //and vice versa
        _ideal_width = _desing_width;
        if os_type == _os_type then _ideal_height = _overide_other_value == undefined ? round(_ideal_width * _aspect_ratio) : _overide_other_value * _scale;
        else _ideal_height = round(_ideal_width * _aspect_ratio);
    }

    //make the results more pixel perfect friendly
    if _ideal_width & 1 then _ideal_width++;
    if _ideal_height & 1 then _ideal_height++;

    if _resize_all_rooms {
        //apply resolution results to all rooms?
        for (var i = 0; i < room_last; i++)
        {
            if (i == room) continue; // in GMS 2.3+ initial room may have random number, so skip initial/first room
           
            if room_exists(i)
            {
                room_set_width(i, _ideal_width);
                room_set_height(i, _ideal_height);
            }
        }
    }

    application_surface_enable(false);  // false as default behaviour
    window_set_size(_ideal_width, _ideal_height);
    surface_resize(application_surface, _real_width, _real_height);

    //remove the temporary scaling if building with Test -> VM and apply results in global vars for further use
    global.ideal_width = os_type == _os_type ? _ideal_width / _scale : _ideal_width;
    global.ideal_height = os_type == _os_type ? _ideal_height / _scale : _ideal_height;
}
It might be still possible to optimise it even more. It's also compatible with Feather, and fixes a bug in case that first room id isn't 0 (which is possible in GM for few versions now, as assets aren't sorted ingame same as in asset tree).
 

gkri

Member
I've got a boring morning, and while checking tutorials forum I've hit this topic, and noticed that code in first post got looot of repetitions or very similar code, so I've decided to try a little optimization as an exercise for my brain, in accompany to morning coffee:

GML:
global.ideal_width = 0;
global.ideal_height = 0;

///Written by George Kritikos (Harpwood studio) - Based on code written by Pixelated_Pope
///@License MIT License https://opensource.org/licenses/MIT
///@func set_resolution(design_value, is_design_vertical, is_orientation_vertical, resize_all_rooms, [scale], overide_other_value [optional])
///@arg {Real} _design_value                  width or height of ideal resolution
///@arg {Bool} _is_design_value_vertical      When true, the design_value is condidered as height; when false, as width
///@arg {Bool} _is_orientation_vertical       When true, the screen orientation is considered as portrait; when false, as landscape
///@arg {Bool} _resize_all_rooms              When true: Rooms (except room index 0), will be resized to resulting value
///@arg {Real} _scale                         (Optional) Scale the game window to better fit the monitor. Will ommited on any non windows and non macos builds
///@arg {Real} _overide_other_value           (Optional) Overides the value other than the design_value arg for a custom aspect ratio. Will ommited like scale arg
function set_resolution(_design_value = 1280, _is_design_value_vertical = true, _is_orientation_vertical = false, _resize_all_rooms = false, _scale = 1, _overide_other_value = undefined) {
    _scale ??= 1;

    //detect os_type only if is GMS2 IDE approprate
    var _os_type = os_type == os_windows ? os_windows : os_macosx;

    // The design value is either the design width or height. Every calculation in build with Test -> VM get a temporary scaling
    var _desing_width    = os_type == _os_type ? _design_value * _scale : _design_value;
    var _desing_height   = os_type == _os_type ? _design_value * _scale : _design_value;

    var _real_width, _real_height, _aspect_ratio, _ideal_width, _ideal_height;
   
    var _h = os_type == _os_type ? (display_get_height())  * _scale : display_get_width();
    var _w = os_type == _os_type ? (display_get_width())   * _scale : display_get_height();
   
    _real_width   = _is_orientation_vertical ? _h : _w;
    _real_height  = _is_orientation_vertical ? _w : _h;
    _aspect_ratio = _real_width >= _real_height ? _real_height / _real_width : _real_width / _real_height;
    _ideal_height = _desing_height;
    _ideal_width  = _desing_width;
   
    if (_is_orientation_vertical != _is_design_value_vertical) {
        _aspect_ratio = 1/_aspect_ratio; // division is multiplication by reciprocal
    }
   
    if _is_design_value_vertical {
        //The design value is reffering to vertical so we calculate the horizontal
        _ideal_height = _desing_height;
        if os_type == _os_type then _ideal_width = _overide_other_value == undefined ? round(_ideal_height * _aspect_ratio) : _overide_other_value * _scale;
        else _ideal_width = round(_ideal_height * _aspect_ratio);
    } else {
        //and vice versa
        _ideal_width = _desing_width;
        if os_type == _os_type then _ideal_height = _overide_other_value == undefined ? round(_ideal_width * _aspect_ratio) : _overide_other_value * _scale;
        else _ideal_height = round(_ideal_width * _aspect_ratio);
    }

    //make the results more pixel perfect friendly
    if _ideal_width & 1 then _ideal_width++;
    if _ideal_height & 1 then _ideal_height++;

    if _resize_all_rooms {
        //apply resolution results to all rooms?
        for (var i = 0; i < room_last; i++)
        {
            if (i == room) continue; // in GMS 2.3+ initial room may have random number, so skip initial/first room
           
            if room_exists(i)
            {
                room_set_width(i, _ideal_width);
                room_set_height(i, _ideal_height);
            }
        }
    }

    application_surface_enable(false);  // false as default behaviour
    window_set_size(_ideal_width, _ideal_height);
    surface_resize(application_surface, _real_width, _real_height);

    //remove the temporary scaling if building with Test -> VM and apply results in global vars for further use
    global.ideal_width = os_type == _os_type ? _ideal_width / _scale : _ideal_width;
    global.ideal_height = os_type == _os_type ? _ideal_height / _scale : _ideal_height;
}
It might be still possible to optimise it even more. It's also compatible with Feather, and fixes a bug in case that first room id isn't 0 (which is possible in GM for few versions now, as assets aren't sorted ingame same as in asset tree).
I did a fast reading on my mobile and looks brilliant! I will update the itch page when I 'll be on my home with stable internet connection in October (sorry, only limited mobile data until then).

Thabk you for your contribution!
 
Last edited:

gnysek

Member
Try with:
GML:
if (surface_exists(application_surface)) {
    surface_resize(application_surface, _real_width, _real_height);
}
When game is minimized or there's screensaver, it's possible that there's no surface created at all to save memory. You can find out more in manual, in section about surfaces.
 
Top