5
\$\begingroup\$

I have been following the tutorials at http://lazyfoo.net/tutorials/SDL/index.php and although they are all very well written and I have learned more than I would have on my own, I am not sure how to go about building a basic main menu that has the normal "new game," "settings" and "exit" options.

How would I handle such a menu inside of a normal game loop?

\$\endgroup\$
7
\$\begingroup\$

As congusbongus notes in his answer, many games benefit from dividing content into "scenes". A scene might represent a particular level, a room, a minigame, or lots of other possibilities, depending on the game. In such a system, menus can be implemented as scenes as well, and this works well for simple games with only a few menus.

Personally, I like to think of menus as overlays. Most games don't need more than one scene active at a time, but benefit from having a menu open while the game is running, and knowing what menu you came from if there are sub-menus. If you treat menus and scenes the same and don't allow multiple scenes to coexist, it's difficult to make a pause menu, or have menus that can be reached in multiple ways.

I find the most useful representation for menus is a stack. Such an implementation might look like this:

  • When the game (application) starts, push the main menu onto the stack.
  • When a sub-menu is selected, push it onto the stack.
  • When a "back" button is pressed, pop the top menu from the stack.
  • When the actual game begins (scene is loaded), pop all menus.
  • If the stack is not empty, render its top menu after you render your current scene (if there is one). Of course, if the top menu is opaque, you can skip drawing the current scene to save time, but having a pause menu with a transparent/translucent background can be nice.
  • If the menu stack is empty, dispatch input events to the current scene, otherwise, dispatch them to the top menu in the stack.

For example, if you have a main menu, high scores menu, settings menu, pause menu, and end-of-game summary menu, you might be able to get to the settings menu via the main menu or pause menu, but you can return to wherever you came from without having to deal with any special cases or complex state tracking. You can even return to the main menu from a paused game and later return to the game by having a "return to game" option on the main menu that is deactivated and invisible if the menu stack has a size of 1 (the main menu)

\$\endgroup\$
  • 1
    \$\begingroup\$ I just have a gui variable, and if it isn't null, I update and render it. Because Gui is an abstract class, I can easily create many different menus. But I really like your stack method. I will definitely have to use this. \$\endgroup\$ – Lysol Apr 3 '14 at 6:08
  • \$\begingroup\$ Could you provide me an example of pushing a menu onto the stack? I'm still very new to video game development and C++ in general. \$\endgroup\$ – Elias Apr 11 '14 at 0:04
  • 1
    \$\begingroup\$ @Elias gist.github.com/bcrist/10517070 \$\endgroup\$ – bcrist Apr 12 '14 at 3:21
3
\$\begingroup\$

The typical way to implement this is using game screens or scenes.

  • Your game loop updates and draws the current screen, whatever that may be
  • Your menu(s) live in one screen or set of screens, your game world lives in another screen
  • Choosing certain menu options (e.g. start game) switches the current screen

In this sense, it's just a plain programming problem. The difficulty is in the details though, such as how to draw and layout the menu, how to strike a balance between making it easy to modify the menu and giving it power (i.e. perform arbitrary changes to your game), handling input, different menu control types and so on. I suspect you'll have plenty of follow-up questions once you start.

For more details (including some sample code), check out this: http://www.gamedev.net/topic/521366-making-a-menu-with-sdl/

You could also try a menu library that supports SDL such as guichan. I haven't used any myself so I can't recommend, sorry.

\$\endgroup\$
1
\$\begingroup\$

I'm not sure if you'd like my method but based on what you said, "New Game, Settings, Exit" then I'm assuming the menu would be the main screen right? I'm a texture user , by the way, and not a surface one.

//Let's assume that your method of input is a mouse
//since this is long, you can create a class for this then recall it in the gameloop


//WE CREATE THE COORDINATES OF THE MOUSE
int Mx = 0;
int My = 0;
bool play1 = false;

//Let's make the menu's background
SDL_Texture *background = IMG_LoadTexture(renderer, "FilePath");
//Now the Background's rect, it should give us power to control it's size and location
SDL_Rect background_rect;
background_rect x = 0;   //X COORDINATE
background_rect y = 0;   //Y COORDINATE
background_rect w = 400; //WIDTH
background_rect h = 400; //HEIGHT
/*Now, our background should start from the top left since it's coordinates are in 
(0, 0) and it should stretch 400 to the right and 400 down making it a square, 400X400*/

//The New Game button
SDL_Texture *newGame = IMG_LoadTexture(renderer, "FilePath");
//The game button's rect
SDL_Rect newGame_Rect;
newGame_Rect.x = 0;
newGame_Rect.y = 100;
newGame_Rect.w = 50;
newGame_Rect.h = 25;

//I'll just skip to the exit button
SDL_Texture *exit = IMG_LoadTexture(renderer, "FilePath");
//The exit button's rect
SDL_Rect exit_Rect;
exit_Rect.x = 0;
exit_Rect.y = 200;
exit_Rect.w = 50;
exit_Rect.h = 25;

IN THE GAME LOOP

SDL_GetMouseState(&Mx, &My); //This would constantly input the the x coordinate into Mx and the y coordinate of the mouse into My


//WARNING: THIS AREA COULD BE A BIT TRICKY IF YOU DON'T UNDERSTAND COLLISION

//Let's make an if statement that checks if the mouse is touching the New Game Button

if (Mx >= newGame_Rect.x && Mx <= newGame_Rect.x + newGame_Rect.w && My >= newGame_Rect.y && My <= newGame_Rect.y + newGame_Rect.h)

/*The if statement basically checks if the pointer is inside the area of the rect, 
it may look confusing but it's actually pretty simple, since (0, 0) is at the 
top-left and the going down is +y then there's no negative coordinate, that also goes
for the texture, the top left point is the origin, so basically, it checks if
the mouse's x-coordinate is greater than the origin but less than the origin plus
width (newGame_Rect.x + newGame_Rect.w to make sure that the pointer is inside, the
same goes for the y coordinate*/ 
{
SDL_SetTextureColorMod(newGame, 250, 0, 0 ); 
    /*This would make the texture change color if the mouse is inside the rect,
    it takes the name of the texture which is newGame, and the following variables
    are the r, g, and b, if you were to make all except red into 0 then the texture
    would be tinted red, I assumed you wanted the player to know that it is hovering
    over the new game so I added this as a bonus*/

if (event->type == SDL_MOUSEBUTTONDOWN)  //this calls an event, I assume that you already know how to make an event right? 
{
    if (event->button.button == SDL_BUTTON_LEFT)
    {    //if it is pressed then play1 becomes true which you could use to initiate the newgame
        play1 = true;
    }
}
}
else 
{
SDL_SetTextureColorMod(Gettexture(), 250, 250, 250); 
    // Tints the texture white if the cursor isn't over the button
}

This should give you a proper knowledge over the menu, you could now create your own exit button and just make it execute another bool that could break your gameloop, I didnl't make a sample for the exit since it would just be similar to the NewGame button.

Happy Coding :)

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.