• 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!

So is this good? Draw vs Gui streamlined mouse pressed

Joh

Member
Hello!
In my game I have pressable both as object and as GUI, I often make use of hand-made shape "draw&press" event scripts (rectangle, sprite, 9-slice) but those always referenced mouse_x/y.
I know the device_to_gui functions can get the right x and y for the GUI but those are usually different from the mouse_x or y thus I thought I should make a duplicate set of scripts using the gui version for any gui code.
Then I wondered if there's anyway to know what event I'm in and found out there is!
Thus I came out with this:
GML:
var _mouse_x = event_number==ev_gui?device_mouse_x_to_gui(0):mouse_x, 
_mouse_y = event_number==ev_gui?device_mouse_y_to_gui(0):mouse_y;
return point_in_rectangle(_mouse_x, _mouse_y, _x, _y, _x2, _y2)
Seems pretty powerful, and allows appropriate click detection on GUI and Draw without any thinking or consideration on my side.
Just wondering if there's any flaw to this, if it's standardly used because this seems like a rather simple solution to a common issue. (not an issue as much as an inconvenience)
 

Joh

Member
it is run as many times as I draw "clickables". UI has a ton of those.
in a fuller context:
GML:
/// @function draw_rect_color(x,y,x2,y2,outline,color)
/// @arg x
/// @arg y
/// @arg x2
/// @arg y2
/// @arg outline
/// @arg color
function draw_rect_color(argument0, argument1, argument2, argument3, argument4, argument5) {

    draw_rectangle_colour(argument0,argument1,argument2,argument3,argument5,argument5,argument5,argument5,argument4)
    var _mouse_x = event_number==ev_gui?device_mouse_x_to_gui(0):mouse_x, _mouse_y = event_number==ev_gui?device_mouse_y_to_gui(0):mouse_y;
    return point_in_rectangle(_mouse_x, _mouse_y, argument0, argument1, argument2, argument3)


}
so this just a script that draws a rectangle that tells you if you're on it.
It is very much a per-use script or approach. Could be run in once in 2 events (draw & draw_gui) or in either, or multiple times. not sure if that answers the question.

I call it for UI elements in my controller Object in draw_gui.
upon further inspection I don't "also" call it from the normal draw but I could.

The charm as I see it is that I can call such scripts from draw and/or draw_gui and it will "work as intented".
Normally you have to adjust your code depending on which event you are in.
 

Nocturne

Friendly Tyrant
Forum Staff
Admin
Tbh, this seems like a fairly good solution, and while it's not very efficient to be calling the same functions repeatedly, in the context of GUI and buttons it's usually never an issue, as there's not going to be much else going on to upset the framerate when working with menus. I would say that using draw_rectangle (or any of the draw shape functions) is not a good idea though, as it breaks texture batches and is really very inefficient. It's always better to draw a sprite (for example, us a 1px sprite and just stretch it to the size required to get the same effect as draw_rectangle). One issue I could forsee is "false input" due to overlapping buttons-coordinates, since you could have a GUI button at one position, and a regular draw button at another in the room, but their positions overlay when converted...

I'd set the two variables at the beginning of the game loop and then check them where necessary instead of running the two ternary lines every time.
Yup! That would be my plan too and would remove the issue of repeating function calls..
 

TheouAegis

Member
But if he's calling both the draw event and the GUI event for his button clicking, then how can he set those variables for both? His code is meant to check which current event it is running from. And then he even says he is running that code from both the draw and GUI events at the same time. so basically he would be checking twice per button if he is over a button. That in itself seems pointless to me. The script itself would be useful if used correctly.
 

samspade

Member
I have a similar version with the difference being you pass in whether or not it is gui (modified to use the OP's code) it would look like this:

GML:
function mouse_in_rectangle(_gui, _x, _y, _x2, _y2) {
    var _mouse_x = _gui ? device_mouse_x_to_gui(0) : mouse_x,
    _mouse_y = _gui ? device_mouse_y_to_gui(0) : mouse_y;
    return point_in_rectangle(_mouse_x, _mouse_y, _x, _y, _x2, _y2)
}
Since it seems very unlikely that you would have the same button 'exist' in both the room and gui at the same time this should be easy to set as a variable.
 

Joh

Member
Thanks everyone,
My first thought was Indeed to set a variable up. I initially thought of making one object have a gui_begin set some "is_gui" variable to true and then one gui_end set it back to false.
Really no downside to it except i'd be "wasting"/using 2 events for that sole purpose. (and issue might arise if started using gui_begin/end eventually).

Oh upon rereading it seems you mean set up the pseudo X/Y instead of a is_gui variable and that makes even more sense. Really does minimize the function calls.

Tbh, this seems like a fairly good solution, and while it's not very efficient to be calling the same functions repeatedly, in the context of GUI and buttons it's usually never an issue, as there's not going to be much else going on to upset the framerate when working with menus. I would say that using draw_rectangle (or any of the draw shape functions) is not a good idea though, as it breaks texture batches and is really very inefficient. It's always better to draw a sprite (for example, us a 1px sprite and just stretch it to the size required to get the same effect as draw_rectangle). One issue I could forsee is "false input" due to overlapping buttons-coordinates, since you could have a GUI button at one position, and a regular draw button at another in the room, but their positions overlay when converted...


Yup! That would be my plan too and would remove the issue of repeating function calls..
On the side note of rectangle inneficience, I usually move to sprites eventually (draw rect is especially for early/placeholder GUI/button/clickables) I once used your rectangle sprite stretch trick, when performance became an issue (10x 10 grid) and its striking how it improve performance. it's unfortunate that the native shapes are not that good.

I was wondering about lines though, is is also worth making a sprite "pseudo-draw_line"?
and would a 9-slice by draw_parts still be faster than a native rectangles? it just seems crazy the at least 9 partial sprite draws could still be faster than a draw_rectangle (when used a lot).

I have a similar version with the difference being you pass in whether or not it is gui (modified to use the OP's code) it would look like this:

GML:
function mouse_in_rectangle(_gui, _x, _y, _x2, _y2) {
    var _mouse_x = _gui ? device_mouse_x_to_gui(0) : mouse_x,
    _mouse_y = _gui ? device_mouse_y_to_gui(0) : mouse_y;
    return point_in_rectangle(_mouse_x, _mouse_y, _x, _y, _x2, _y2)
}
Since it seems very unlikely that you would have the same button 'exist' in both the room and gui at the same time this should be easy to set as a variable.
Great minds think alike! And yes, having a _gui argument is a sound idea too, I just liked the idea of having it implicit .
 

samspade

Member
Great minds think alike! And yes, having a _gui argument is a sound idea too, I just liked the idea of having it implicit .
The problem with doing it your way though is it requires non-draw-code to be in the draw events for it to work. This is generally not a good idea. One big reason is that the draw event fires for every view. So if you ever want to do multiple views you'll be running your code multiple times. And draw events don't run if the object isn't visible.

And you can have it implicit the other way as well. You give the object a gui variable or not, set it in the create event or through using object variables, and then pass that in (or make it a part of the script if you want).

GML:
function mouse_in_rectangle(_x, _y, _x2, _y2) {
    var _mouse_x = is_gui ? device_mouse_x_to_gui(0) : mouse_x,
    _mouse_y = is_gui ? device_mouse_y_to_gui(0) : mouse_y;
    return point_in_rectangle(_mouse_x, _mouse_y, _x, _y, _x2, _y2)
}
If the question is does your idea work, I would say the answer is yes in most cases. If the question is your idea good, I would say the answer is at best it's not bad. But it is inefficient, will only work under certain circumstances, and violates a couple other coding principles as well (such as mixing your draw code and non draw code, doing needless function calls, having a single function that does two very different and unconnected things) and it doesn't get you that much beyond reducing your code to one function instead of two.
 
Last edited:

TheouAegis

Member
Set aside a surface for drawing buttons on, draw the button once, then just draw the surface.

In GMS2 you can also just add the buttons to a sprite layer.
 
Top