[SOLVED] Want to DrawGui to window without using a viewport

MrChoke

Member
Here is what I want to do. I want to draw game stats and other GUI stuff at the top of the window, and on the right side of it. While my "main view" takes up most of the window below and to the left of these GUI areas.

All I know how to do so far is make the window render parts of the room using cmaera and views. So I can set up three views, a main, a GUI top and a GUI right. But the GUi area is still viewing into an area of the room. But I don't need this. I am drawing GUI elements not anything in the room. This approach makes me make the room bigger too which throws off how the main camera and view are working.

Another thing I tried but it failed was manually resizing the window. So let's say my main view port into the room is 768x768. I forced the window width and height to be 900x820 let's say to try to window area I can the draw gui too. But what a window resize does is center the view port in the middle. I can't directly contorl where that goes in the window.

Can someone help me with this??

Thanks.
 
Here's how I would do it. Create a surface the size of your game window, draw your game to that surface, then draw the surface and the GUI as separate units within the same "view".
 

samspade

Member
GMS 'won't' let you resize a single viewport. It will always scale it up. So solutions would be:
  • Have two viewports - not recommended.
  • BattleRifle's suggestion - probably how I would do it.
  • draw the gui elements however you want in the gui, draw the game as normal, but offset the character so it is centered in the new reduced view. This is probably the easiest way, but you'll need to remember that your game window is actually the size of the 'screen' not the size of what you see which could matter for things like activating or deactivating instances, shaders and surfaces for the game world, and so on.
 

MrChoke

Member
Here's how I would do it. Create a surface the size of your game window, draw your game to that surface, then draw the surface and the GUI as separate units within the same "view".
Ok, so the application surface, use that as normal right? Meaning one viewport looking at the room as normal on the application surface.

Then create a 2nd surface, tell all of my draw GUI to draw directly to that surface? That should work as long as I can give a width and height large enough to make the winow now hold my two GUI draw areas. Right?
 
Ok, so the application surface, use that as normal right? Meaning one viewport looking at the room as normal on the application surface.

Then create a 2nd surface, tell all of my draw GUI to draw directly to that surface? Is that what you mean? That will work as long as I can give a width and height large enough to make the winow now hold my two GUI draw areas. Right?
Not quite. Create a surface for the game world and draw the GUI normally, right next to it. Picture this :

You have a 1000x1000 window. You want the game portion to be in the bottom left corner, sized 900x900. You create a surface that is 900x900 and draw it at 0,100. You now have the top and right side of the window to draw your GUI elements. You don't need any different events, they can all be in one Draw event (regular or GUI, it doesn't matter. Just make sure it's sized according to your entire needs, both game and GUI elements)
 

MrChoke

Member
Not quite. Create a surface for the game world and draw the GUI normally, right next to it. Picture this :

You have a 1000x1000 window. You want the game portion to be in the bottom left corner, sized 900x900. You create a surface that is 900x900 and draw it at 0,100. You now have the top and right side of the window to draw your GUI elements. You don't need any different events, they can all be in one Draw event (regular or GUI, it doesn't matter. Just make sure it's sized according to your entire needs, both game and GUI elements)
How do you draw a surface (0, 100)? It's always (0,0) I read. I also don't know how to make the game do its automatic drawing, like the tiles to a new surface. So nothing will draw to the application surface except my GUI? This seems hard to do...

UPDATE:
I found draw_surface() which allows me to draw to where on the screen I want. My problem is still that I cannot get the the window to size greater than the viewport. Even tohugh I draw to the right of the view, in drawGui, it's off screen. I need the window to size properly.
 
Last edited:

samspade

Member
As previously stated, you cannot draw a viewport smaller than the window size with a single viewport. GML will not let you, it will always scale it. You need to disable the automatic drawing of the application surface and draw it (or likely part of it in your case) yourself. See this chain for more information: https://forum.yoyogames.com/index.php?threads/camera-and-view-port-size.54277/#post-330288.

You can read the whole thing, but the part that matters is close to the bottom. What you want is something close to this, modified to work for you:

Code:
///create event
application_surface_draw_enable(false);

window_set_size(600, 600);
surface_resize(application_surface, 500, 500);

window_center();

///post draw event (you can also do the gui layer but you'll need to account for how the gui is scaled as well then)
draw_surface_ext(application_surface, 50, 50, 1, 1, 0, c_white, 1);
You'll need to change all the values and you probably don't need the window set size, and window center.
 

MrChoke

Member
Thanks for the replies. I am sure with a lot of effort I can probably get your suggestions of turning off the application surface to work. But for me right now it is too much effort and I am too new to try to manually draw sprites tile maps, objects, etc....

HERE IS WHAT I DID GET TO WORK:

I went back to the 3 view ports, one for the main camera, one for the top GUI, one for the right GUI. And I set the camera for both GUIs to the upper-left corner of the room. I did not increase the size of the room to accomodate GUI areas. Of course that means this upper-left area of the room renders on both GUI views ports but it won't once I clear the GUI areas to a background color and draw what I want. Is this ideal? I highly doubt it. I don't know the internals of GM but probably the viewed areas of the room are drawn and then I overlay them with a big draw_rectangle for each GUI area. For now, it looks like it works though
 

samspade

Member
Option 2 in my list is definitely the hardest to do. I'd personally say Option 3 is easier, as the only thing you really have to consider with it is 'clicking' on the world behind the gui. But you can prevent that by checking whether the mouse clicked there first. Which is a lot easier than managing three view ports.

Option 1 is probably the second easiest, and it seems like you already got it working but there is at least one important thing to keep in mind: the draw events fire once for every single view. So every draw event in your game is running three times now. This isn't a big problem so long as you keep code that isn't related to drawing outside of your draw events. Any code that does things like increment a value for example will be run three times per step.
 

MrChoke

Member
[SOLVED]
I am calling this solved for what I want to do. Yes I am still using 3 view ports which I know is a lot of draw events. However I solved the problem where the GUI view ports would render whatever the camera was pointing at in the room and then I overlay that with draw gui. The key is using "view_surface_id[]" and creating a new surface for each GUI area. Thast way the view looks at my surface not the room. And because all 3 view port are still active, the window is sized correctly and I can see both GUI areas!

My code:
//RIGHT GUI
if !surface_exists(guiRight_surf)
{
guiRight_surf = surface_create(GUI_R_DIM_SX, GUI_R_DIM_SY);
view_surface_id[1] = guiRight_surf;
}

surface_set_target(guiRight_surf);
draw_clear_alpha(c_black,0);
draw_set_color(c_black)
draw_rectangle(0, 0, GUI_R_DIM_SX, GUI_R_DIM_SY, false);
surface_reset_target();
draw_surface(guiRight_surf, GUI_R_SX, GUI_R_SY);


//TOP GUI
if !surface_exists(guiTop_surf)
{
guiTop_surf = surface_create(GUI_T_DIM_SX, GUI_T_DIM_SY);
view_surface_id[2] = guiTop_surf;
}

surface_set_target(guiTop_surf);
draw_clear_alpha(c_black,0);
draw_set_color(c_green)
draw_rectangle(0, 0, GUI_T_DIM_SX, GUI_T_DIM_SY, false);
surface_reset_target();
draw_surface(guiTop_surf, GUI_T_SX, GUI_T_SY);
 

TheouAegis

Member
But for me right now it is too much effort and I am too new to try to manually draw sprites tile maps, objects, etc....
You don't need to manually draw anything with the method where you disable the application surface. Disabling the application surface isn't disabling drawing TO the application surface, it's disabling the drawing OF the application surface. Your game is still going to draw normally. Do note there are two distinct functions:
application_surface_enable() is a boolean function which disables drawing TO the application surface;
application_surface_draw_enable() is a boolean function which disables drawing OF the application surface.

It's a very important distinction.

Also note you can render the GUI elements in the Pre-Draw or Post-Draw events if you want the HUD or a border around the game instead of over it. (think Super Gameboy)
 
Top