GMS 2.3+ Menus with Submenus #2 - Selections

Slyddar

Member
GM Version: Studio 2.3+
Target Platform: Windows
Download: n/a
Links: video below

Summary:
In this GML tutorial we expend on the previous menu tutorial, and show how to change the values of the submenus. Whether they are integers, or text based selections, we look at how to store all our settings into one useful ds map variable, meaning it's easy to access from other parts of your code.

 
Last edited:

zurbinjo

Member
This is SO great! Fantastic tutorial, the logic you are using for the menu is clean, sharp and on point and your explanations are flawless and perfect. If only I'd have seen this tutorial before I coded my own super chaotic spaghetti code menu. Well, for my next game, I'll watch this tutorial again.

Thanks for sharing!

How would you include save slots into this menu? Let's say "Load" is an option in this menu and in the load-submenu there should be saveslots which show information about the current savestate. Is it possible to fit them into this menu logic?
 

Slyddar

Member
Is it possible to fit them into this menu logic?
Anything is possible, it's just a matter of how :)

Well, for my next game, I'll watch this tutorial again.
The next episode will show how to add mouse support, so subscribe to get notified when it drops.

How would you include save slots into this menu? Let's say "Load" is an option in this menu and in the load-submenu there should be saveslots which show information about the current savestate. Is it possible to fit them into this menu logic?
Maybe I'll do a tutorial on that as well in the future. Basically you would add a new macro and sub menu for LOAD, with value of 1, pushing SETTINGS to 2, and with the save slots being the menu entries, like such : (Also update the step event now that we've changed the macro values)
Code:
menu[LOAD][0] = ["Slot 1 : ", "save1"];
menu[LOAD][1] = ["Slot 2 : ", "save2"];
menu[LOAD][2] = ["Slot 3 : ", "save3"];
menu[LOAD][3] = ["Slot 4 : ", "save4"];
menu[LOAD][4] = ["Slot 5 : ", "save5"];
menu[LOAD][5] = "Back";

The key of "save1" would be used in the settings ds_map like such :
Code:
ds_map_add(set, "save1", [0, ["02/02/21 - 11:32:00"]]);
ds_map_add(set, "save2", [0, ["Empty"]]);
ds_map_add(set, "save3", [0, ["Empty"]]);
ds_map_add(set, "save4", [0, ["Empty"]]);
ds_map_add(set, "save5", [0, ["Empty"]]);

Where no save will have the string "Empty" and a save would have the save description. We keep the array structure, so it still gets drawn and displayed correctly without having to make any changes. Your step event case would look something like this for LOAD :
Code:
        case LOAD:
            switch(index) {
                case 0:
                case 1:
                case 2:
                case 3:
                case 4:
                    //load your game
                    process_load();
                break;
                case 5:
                    //Back
                    sub_menu = MAIN;
                    index = LOAD;
                break;
            }
        break;

We can have them having the same case, as the index will be different, and that's what we will use to work out which one was selected. Process_load will just be where we confirm that "Empty" is not the string, and if it's not we proceed with loading the game :
Code:
function process_load () {
    //get the ds map key, which is position 1 of the array menu
    var _key = menu[sub_menu][index][1];

    //if this is a valid file, load it
    if set[? _key][1][0] != "Empty" {
        //perform your loading process
        show_message("loading");
        //the key needs to relate to your method of saving/loading the game
        //so whatever your load game method is, do it here using the key, or the index (0-4), as the reference
    }
}

That should be all you need. The draw event doesn't even need to be touched using this method.
For saving you could do the same thing. A new SAVE macro, say set to 2, pushing SETTINGS to 3 (change step event if needed)
Code:
menu[SAVE][0] = ["Slot 1 : ", "save1"];
menu[SAVE][1] = ["Slot 2 : ", "save2"];
menu[SAVE][2] = ["Slot 3 : ", "save3"];
menu[SAVE][3] = ["Slot 4 : ", "save4"];
menu[SAVE][4] = ["Slot 5 : ", "save5"];
menu[SAVE][5] = "Back";

And the menu would look like this with the new macros, like MAIN 0 and EXIT 4
Code:
menu[MAIN][MAIN] = "New Game";
menu[MAIN][LOAD] = "Load Game";
menu[MAIN][SAVE] = "Save Game";
menu[MAIN][SETTINGS] = "Settings";
menu[MAIN][EXIT] = "Exit";

The step events for save would be :
Code:
        case SAVE:
            switch(index) {
                case 0:
                case 1:
                case 2:
                case 3:
                case 4:
                    //save your game
                    process_save();
                break;
                case 5:
                    //Back
                    sub_menu = MAIN;
                    index = SAVE;
                break;
            }
        break;

And process save would be setting the string correctly, and performing whatever your save process is, based on the key.
Code:
function process_save() {
    //save your game
    //whatever the process is for saving your game, do it here based on the index (0-4) we selected

    //update field entry with date and time
    //prepare time
    var _d, _mo, _h, _mi, _s;
    if current_day        < 10 _d = "0" + string(current_day)        else _d = string(current_day);
    if current_month    < 10 _mo = "0" + string(current_month)    else _mo = string(current_month);
    if current_hour        < 10 _h = "0" + string(current_hour)    else _h = string(current_hour);
    if current_minute    < 10 _mi = "0" + string(current_minute)    else _mi = string(current_minute);
    if current_second    < 10 _s = "0" + string(current_second)    else _s = string(current_second);
    var _str = _d + "/" + _mo + "/" + string(current_year) + " - " + _h + ":" + _mi + ":" + _s;

    //get the ds map key for this menu entry
    var _key = menu[sub_menu][index][1];

    //set menu entry for index position 1 of the ds_map value, position 0 of the array
    set[? _key][1][0] = _str;
}

Also you can add this to the draw event before we draw the items, to show the menu header, and your game name if needed.
Code:
//draw titles
if sub_menu != MAIN var _str = menu[MAIN][sub_menu];
else var _str = "The Amazing Game";
draw_set_colour(c_white);
draw_text(room_width/2, room_height * .3, _str);

Just in case you followed all of that above, lol, in the end, this would be the first switch statement case in the step event now :
Code:
        case MAIN:
            switch(index) {
                case MAIN:
                    //However you start your game
                break;
                case LOAD:
                case SAVE:
                case SETTINGS:          
                    sub_menu = index;
                    index = 0;
                break;
                case EXIT:
                    //Exit
                    game_end();
                break;
            }
        break;

As I say, I'll probably add a video to the series in the future that shows this all, but for now that may help you work through it.
 
Last edited:

zurbinjo

Member
Wow, thanks for your reply - this helps a lot! I've seen you are a teacher and I bet you are a very good one.

Already subscribed to your channel, yesterday. Keep up the great work!
 
Top