• Hey Guest! Ever feel like entering a Game Jam, but the time limit is always too much pressure? We get it... You lead a hectic life and dedicating 3 whole days to make a game just doesn't work for you! So, why not enter the GMC SLOW JAM? Take your time! Kick back and make your game over 4 months! Interested? Then just click here!

Legacy GM Problems with view scaling

S

Smooth Operator

Guest
I've looked in a handful of places for how to scale pixel art perfectly a la Hyper Light Drifter, as in, while retaining a low resolution, scaling the pixels up without inconsistent pixel widths, and quantizing the use of pixels on screen so that there are no in-between pixel movements. Just like Hyper Light Drifter, I'll be using 480p resolution (640 x 480) and need the pixel art to look clean. So far I've used a couple fixes:

  • Using floor() on the position of camera and object movements so that there are no sub-pixel movements
  • Using the following functions to enforce a resolution:
    • surface_resize(application_surface,640,480);
    • display_set_gui_size(640,480);
  • Using this script; I'm not entirely sure about the individual components, but it solved the rest of my issues except one
    • Code:
      [*]// Please note, all room VIEW and PORT need to be the same size.
      [*]
      
      [*]-----
      [*]Create Event:
      [*]-----
      [*]
      
      [*]application_surface_draw_enable(false);
      [*]surface_resize(application_surface, view_wview, view_hview);
      [*]
      
      [*]global.gameScale = 4;
      [*]global.gameFullscreen = 0; 
      [*]if (global.gameFullscreen = 0) {
      [*]   window_set_size(view_wview*global.gameScale, view_hview*global.gameScale);
      [*]   alarm[0] = 1;
      [*]   } else {
      [*]   window_set_fullscreen(true);
      [*]   }
      [*]
      
      [*]-----
      [*]ALARM[0]
      [*]-----
      [*]/// Center Window View
      [*]window_center();
      [*]
      
      [*]-----
      [*]Post Draw
      [*]-----
      [*]/// Game Scaling Script
      [*]
      
      [*]draw_surface_ext(application_surface,(window_get_width()/2)-((view_wview*global.gameScale)/2),(window_get_height()/2)-((view_hview*global.gameScale)/2) ,global.gameScale,global.gameScale,0,c_white,1)
My problem is that, after I've applied these fixes, for some reason, my cursor (and probably other interactions in the game) acts as if I've simply magnified the view (because that's probably all I did) but the position in relation to other objects stays the same. So for instance, if I were to bring my cursor to the middle-left or middle-right, since it appears to be scaled up double, the in-game cursor goes all the way to the left or right of the screen, same as up or down. So visually, everything's scaled up by double, but my cursor's sensitivity is quadrupled.

Any help with this issue would be appreciated. Thanks for your time.
 
S

Smooth Operator

Guest
OK, I don't mean to sound like... a jerk... or something... but did you read the problem I'm having? It works perfectly fine, and I'm using practically everything in the relevant part of your article, but it's not lining up correctly with my cursor.

Here is a screenshot:


That red circle on the left is where my cursor is. The arrow is where my GUI object thinks the cursor is with this function:

Code:
draw_sprite_ext(
        sprCrosshair,
        0,
        mouse_x,
        mouse_y,
        1,
        1,
        angle+180,
        -1,
        1);
in a Draw event.

The black circle underneath is where my GUI thinks my cursor using the D&D Draw Ellipse at mouse_x and mouse_y in a Draw GUI event. So none of it really seems to be working out correctly, and I'm confused as to what could cause this, or where in the functions I listed that would make this happen.
 
C

Corablue

Guest
I could be wrong, but there was a topic similar to this earlier today. Try replacing mouse_x and mouse_y with device_mouse_raw_x(0) and device_mouse_raw_y(0).
 

RangerX

Member
In your code up there I don't see you resizing your GUI layer, it probably stays 640x480. That might cause a problem with your cursor's position when the game is scaled up.
 
S

Smooth Operator

Guest
I tried the device_mouse_raw_x and y, and it still has the scaling problem, though the black sphere doesn't move as erratically.

RangerX, you're correct in that my GUI is still 640x480, in fact I forced it to do that with display_set_gui_size(640,480), which may be why it acted so erratically.

So I tried to set my GUI size to my monitor size, but that didn't work either. It looks like no matter what I do, my GUI is set to squash down the resolution. The only way it works is if I draw the black circle in a Draw event, not Draw GUI, which probably means my problem is due in part to GUI scaling. Even then, in the Draw event, if I use coordinates relative to mouse_x and mouse_y, there is a small offset in the +X direction for some reason. I figured to use display_set_gui_maximise(global.gameScale,global.gameScale,window_get_x(),window_get_y()); and it scaled the arrows correctly when changing the scale, but I have an additional problem.

I'm too tired and frustrated to articulate it very well, so I guess I'll just brute force my explanation with more screenshots.

At global.gameScale=1, this is the range of motion of my cursor when the cursors are at each corner of the screen. The middle one is where the cursor rests when hovering over my character. These are overlapping screenshots.



As you can see, the circle is squished horizontally.

After resizing the GUI with the maximize function (I upped the scale for visibility) the arrows seemed to fall in line:



but when my character moves across the screen, the arrows start behaving DIFFERENTLY, and since the GUI is separate from the Player object, I think it might have to do with that the GUI object itself moves in relation to the window? Or perhaps the view?



After my character moves down, the GUI's display moves down as well, centering on a point lower than before. Though the cursor's rotation is in relation to the Player, both it and the pink circle are supposed to draw exactly on the mouse's coordinates, but there's a strange offset arbitrarily far away from the cursor in the +X direction.

Also, if I attempt to draw a line between the Player and the cursor, then it draws relative to where the crosshair thinks it's pointing from, not from my Player. So if I were to offset the cursor and then do the four-corner test like I did above, it would center on where all the cursors are pointing away from, not from the actual sprite of the character

I've got no idea, and I browsed through the Windows and Views functions listed looking for something to help me out. This is totally bizarre, and I'm getting super frustrated since I have little time to actually work on this.
 
Last edited by a moderator:
S

Smooth Operator

Guest
OK.

I looked through about everything I could find and can't find a solution as to why I can't get my cursor sprite in a Draw GUI event to follow the cursor. So I science'd it, recording how the cursor lined up with my display_mouse_get_*() functions, and I found the coefficient of 1/2.25 (.4 repeating) to be good for keeping my cursor in line with my mouse. Don't ask me what it means, I've ripped my hair out trying to figure that out. It appears to work at any scaling, so that's good...

Anyway I only have a couple weeks to finish this project for a game jam, so thanks for your input. I'll leave my code here in case anyone else can figure out the mystery that is my life.

objCamera
Code:
//Create
var width=640;
var height=480;
var camspeed=-1;

if (instance_exists(objPlayer))
    view_object[view_current]=objPlayer;
   
view_hborder[view_current]=width;
view_vborder[view_current]=height;

view_wview[view_current]=width;
view_hview[view_current]=height;

view_wport[view_current]=view_wview[view_current];
view_hport[view_current]=view_hview[view_current];

view_xport[view_current]=0;
view_yport[view_current]=0;

view_hspeed[view_current]=camspeed;
view_vspeed[view_current]=camspeed;

view_enabled=true;
view_visible[view_current]=true;

window_set_size(view_wport[view_current],view_hport[view_current]);
if (global.gameFullscreen==false)
    window_set_size(view_wview*global.gameScale, view_hview*global.gameScale);
else
    window_set_fullscreen(true);

application_surface_draw_enable(false);
surface_resize(application_surface, view_wview, view_hview);

/*
var base_w = 1920;
var base_h = 1080;
var max_w = display_get_width();
var max_h = display_get_height();
var aspect = display_get_width() / display_get_height();
if (max_w < max_h)
    {
    // portait
    var VIEW_WIDTH = min(base_w, max_w);
    var VIEW_HEIGHT = VIEW_WIDTH / aspect;
    }
else
    {
    // landscape
    var VIEW_HEIGHT = min(base_h, max_h);
    var VIEW_WIDTH = VIEW_HEIGHT * aspect;
    }

view_wview[0] = floor(VIEW_WIDTH);
view_hview[0] = floor(VIEW_HEIGHT);
view_wport[0] = max_w;
view_hport[0] = max_h;

surface_resize(application_surface, view_wview[0], view_hview[0]);
*/

//Post-Draw
draw_surface_ext(application_surface,
                (window_get_width()/2)-((view_wview*global.gameScale/2)),
                (window_get_height()/2)-((view_hview*global.gameScale/2)),
                 global.gameScale,
                 global.gameScale,
                 0,
                 c_white,
                 1);
objGUI
Code:
// Create
var baseWindowWidth  = 640;
var baseWindowHeight = 480;
var aspectRatio = display_get_width() / display_get_height();

windowWidth = baseWindowHeight * aspectRatio;
windowHeight = baseWindowHeight;

display_set_gui_maximise(
    (display_get_width()  / windowWidth),
    (display_get_height() / windowHeight),
     0,
     0);
Code:
//Draw GUI
rawX=mouse_x-objPlayer.x;
rawY=mouse_y-objPlayer.y;

angle=radtodeg(arctan2((rawX),(rawY)));

/*draw_sprite(
        sprCrosshair,
        2,
        display_mouse_get_x()/2.25,
        display_mouse_get_y()/2.25);*/

if (objPlayer.speed>=0 && objPlayer.speed < 2)
    draw_sprite_ext(
        sprCrosshair,
        0,
        display_mouse_get_x()/2.25,
        display_mouse_get_y()/2.25,
        1,
        1,
        angle+180,
        -1,
        1);
else if (objPlayer.speed>=2 && objPlayer.speed < 3)
    draw_sprite_ext(
        sprCrosshair,
        1,
        display_mouse_get_x()/2.25,
        display_mouse_get_y()/2.25,
        1,
        1,
        angle+180,
        -1,
        1);
else if (objPlayer.speed>=3)
    draw_sprite_ext(
        sprCrosshair,
        2,
        display_mouse_get_x()/2.25,
        display_mouse_get_y()/2.25,
        1,
        1,
        angle+180,
        -1,
        1);
 
T

thecatisburried

Guest
I have the same issue and found it drawn correctly by being in fullscreen. If I'm in window mode it has that weird issue.
 

RangerX

Member
It shouldn't be complicated like this. THERE IS a simple way to draw exactly where you cursor is according the GUI layer.
Its just that there's a couple of things we need to keep in mind:

- GUI layer is on top of everything and yes its relative to the window size.
- Mouse position need to both be figured out correctly in relation with screen size vs GUI layer size AND ALSO drawn the right position


Now, if for whatever reason this becomes and headache. Why use the GUI layer? Make it simple and draw your GUI elements on the application surface just like the rest. This might remove some assle apparently.
 
Top