Page 1 of 1

SDL Menu?

Posted: Thu Mar 19, 2009 12:03 pm
by Norbo
Hello, im new to these forums and new to sdl and c++, so dont bit** me out pls.

I am not sure how to make a working main menu in sdl. Like you know, at a start of the game, there are usually things like start game, options credits etc. I was wondering how to make that type of a menu. I guess make some boolean that is true when u are in a main menu at the start of the program, if true blit all the menu stuff etc. but im not entirely sure. If someone could guide me, it would be great.

Re: SDL Menu?

Posted: Thu Mar 19, 2009 1:26 pm
by programmerinprogress
I tend to write a class to manage menu buttons.

I tend to use an SDL rect to track the cursor, and then treat all my buttons as SDL rects, and then check for some collison.

I would make a class, which has methods for handling click events for each button.

Many people will likely tell you on the boards that there are ways to implement toolbar menus using external libraries, which is perfectly fine, but I have a hunch you just want a simple menu system where you select "New Game", "option" etc from the screen, so that's why I recommended that you might want to write a simple button class, or something along those lines.

Re: SDL Menu?

Posted: Thu Mar 19, 2009 2:45 pm
by ibly31
Never include everyything in your main loop. Make a menu function that has it's own loop that handles the input and checks for someone hitting the X or pressing escape. Don't EVER make your game loop have a whole portion for just the menu, just make a functions that's called before it.

Re: SDL Menu?

Posted: Thu Mar 19, 2009 3:46 pm
by Norbo
All right guys, thanks for the replies.
I will try to make a button class and combine it somehow to a main menu
but not now, tomorow :)
gn

Re: SDL Menu?

Posted: Thu Mar 19, 2009 8:31 pm
by ibly31
Off topic: but I'm super excited, I finished pixel perfect scrolling with my 2D rpg. And An array of SDL rects that give pixel perfect collision detection!

Re: SDL Menu?

Posted: Fri Mar 20, 2009 3:56 pm
by Norbo
Okay, i tried to make a menu but i failed. i got lots of errors, and really, i have no clue what they mean and why do they occur.

here is my code:

Code: Select all

#include "SDL/SDL.h"
#include "SDL/SDL_mixer.h"
#include "SDL/SDL_ttf.h"
#include "SDL/SDL_image.h"
#include <string>
#include <fstream>
#include <stdlib.h>

using namespace std;

//The attributes of the screen 
const int SCREEN_WIDTH = 800; 
const int SCREEN_HEIGHT = 600; 
const int SCREEN_BPP = 32; 

SDL_Surface *screen = NULL;
SDL_Surface *bg = NULL;
SDL_Event event;
int currentButton = 1;
//Get the keystates 
Uint8 *keystates = SDL_GetKeyState( NULL ); 
bool mainMenu = true;

//File stream for the game log. 
std::ofstream logger( "log.txt" ); 
//===============================================================================================

class Button {
    SDL_Rect offset;
    SDL_Surface *imageUp;
    SDL_Surface *imageOver;
    int id;
    void handle_input();
    void show();
}

//===============================================================================================
//Function

SDL_Surface *load_image( std::string filename )
{ 
    //The image that's loaded 
    SDL_Surface* loadedImage = NULL; 
    //The optimized image that will be used 
    SDL_Surface* optimizedImage = NULL; 
    //Load the image using SDL_image 
    loadedImage = IMG_Load( filename.c_str() ); 
    //If the image loaded 
    if( loadedImage != NULL ) 
    { 
        //Create an optimized image 
        optimizedImage = SDL_DisplayFormat( loadedImage ); 
        //Free the old image 
        SDL_FreeSurface( loadedImage ); 
    } 
    //Return the optimized image 
    return optimizedImage; 
} 

void draw_image(int x,int y,SDL_Surface *source,SDL_Surface *destination)
{
    //Make a temporary rectangle to hold the offsets 
    SDL_Rect offset; 
    
    //Give the offsets to the rectangle 
    offset.x = x; 
    offset.y = y; 
        
    SDL_BlitSurface(source,NULL,destination,&offset); 
}

Button::handle_input();
{
    //If up is pressed 
    if( keystates[ SDLK_UP ] ) 
    { 
        currentButton--
    } 
    //If down is pressed 
    if( keystates[ SDLK_DOWN ] ) 
    { 
       currentButton++
    }
}

void initButtons();
{
    play.id = 1;
    howto.id = 2;
    options.id = 3;
    credits.id = 4;
    exit.id = 5;
    ok.id = 6;
    back.id = 7;
    play.offset.x = 100;
    play.offset.y = 100;
    howto.offset.x = 100;
    howto.offset.y = 200;
    options.offset.x = 100;
    options.offset.y = 300;
    credits.offset.x = 100;
    credits.offset.y = 400;    
    exit.offset.x = 100;
    exit.offset.y = 500;
    ok.offset.x = 100;
    ok.offset.y = 600;
    back.offset.x = 100;
    back.offset.y = 700;
    back.imageOver = load_image("graphics/back_mouseover.bmp");
    back.imageUp = load_image("graphics/back_up.bmp");
    credits.imageOver = load_image("graphics/credits_mouseover.bmp");
    credits.imageUp = load_image("graphics/credits_up.bmp");
    exit.imageOver = load_image("graphics/exit_mouseover.bmp");
    exit.imageUp = load_image("graphics/exit_up.bmp");
    howto.imageOver = load_image("graphics/howto_mouseover.bmp");
    howto.imageUp = load_image("graphics/howto_up.bmp");
    ok.imageOver = load_image("graphics/ok_button mouse_over.bmp");
    ok.imageUp = load_image("graphics/ok_button_up.bmp");
    play.imageOver = load_image("graphics/playgame_mouseover.bmp");
    play.imageUp = load_image("graphics/playgame_up.bmp");
}

Button::show();
{
    if (currentButton==id) {
        draw_image(button.offset.x,button.offset.y,button.imageOver,screen)
    }
    else {
        draw_image(button.offset.x,button.offset.y,button.imageUp,screen)
    }
}

void clean_up() 
{ 
    SDL_FreeSurface(bg);
    //Quit SDL 
    SDL_Quit(); 
} 

bool init()
{
    //Initialize all SDL subsystems 
    if(SDL_Init(SDL_INIT_EVERYTHING)==-1) { 
        return false; 
    } 
    //Set up the screen 
    screen = SDL_SetVideoMode(SCREEN_WIDTH,SCREEN_HEIGHT,SCREEN_BPP,SDL_SWSURFACE); 
    if (screen == NULL)
    {
        return false;
    }
    Button play;
    Button howto;
    Button options;
    Button credits;
    Button exit;
    Button ok;
    Button back;
    initButtons();
    //Set the window caption 
    SDL_WM_SetCaption("yo",NULL); 
    return true;
}

#undef main
int main( int argc, char* args[] ) 
{
    bool quit = false;
    if (init == false){
        return 1;
    }
    while (quit == false)
    {
        while (mainMenu)
        {
            play.show();
            howto.show();
            options.show();
            credits.show();
            exit.show();
            ok.show();
            back.show();
        }
        //While there's an event to handle 
        while(SDL_PollEvent(&event)) 
        { 
            //If the user has Xed out the window 
            if(event.type == SDL_QUIT) 
            { 
                //Quit the program 
                quit = true; 
            } 
        } 
    }
    if (quit==true) {
        clean_up();
    }
    return 0;
} 
and here is the compile log from dev cpp:

Code: Select all

Compiler: Default compiler
Building Makefile: "C:\Dev-Cpp\sda\Makefile.win"
Executing  make...
make.exe -f "C:\Dev-Cpp\sda\Makefile.win" all
g++.exe -c main.cpp -o main.o -I"C:/Dev-Cpp/lib/gcc/mingw32/3.4.2/include"  -I"C:/Dev-Cpp/include/c++/3.4.2/backward"  -I"C:/Dev-Cpp/include/c++/3.4.2/mingw32"  -I"C:/Dev-Cpp/include/c++/3.4.2"  -I"C:/Dev-Cpp/include"  -I"C:/SDL-1.2.13/include"  -I"C:/Dev-Cpp/include"  -I"C:/Dev-Cpp/include/c++"  -I"C:/SDL-1.2.13/include"   

main.cpp:40: error: expected init-declarator before '*' token
main.cpp:40: error: expected `,' or `;' before '*' token

main.cpp:72: error: expected constructor, destructor, or type conversion before ';' token
main.cpp:73: error: expected unqualified-id before '{' token
main.cpp:73: error: expected `,' or `;' before '{' token

main.cpp:87: error: expected unqualified-id before '{' token
main.cpp:87: error: expected `,' or `;' before '{' token
main.cpp:123: error: expected constructor, destructor, or type conversion before ';' token
main.cpp:124: error: expected unqualified-id before '{' token
main.cpp:124: error: expected `,' or `;' before '{' token
main.cpp: In function `int main(int, char**)':
main.cpp:176: error: `play' undeclared (first use this function)

main.cpp:176: error: (Each undeclared identifier is reported only once for each function it appears in.)
main.cpp:177: error: `howto' undeclared (first use this function)
main.cpp:178: error: `options' undeclared (first use this function)
main.cpp:179: error: `credits' undeclared (first use this function)
main.cpp:180: error: request for member `show' in `exit', which is of non-class type `void ()(int)'
main.cpp:181: error: `ok' undeclared (first use this function)
main.cpp:182: error: `back' undeclared (first use this function)

make.exe: *** [main.o] Error 1

Execution terminated
i have no clue what to do now.

please help me! :worship:

Re: SDL Menu?

Posted: Fri Mar 20, 2009 4:18 pm
by programmerinprogress
One noticable error is the class delaration, you have to put a semicolon after the closing brace, this is essential.

I didn't have a proper check through your code (just a glance), but you will probably have a few less errors now, if you add that semicolon.


EDIT:
also, you can't declare objects within main, and expect the class function implementation to understand what they are...

your init function needs to initialise a hypothetical object (i.e. you need to initialise the member functions of a class, not the objects themselves)

Actually, some code would explain this a lot better.

This is how your class definition/object declarations should look.

Code: Select all

class Button
{
public: 
//your accessor methods 
Button(int x, int y, int w, int  h) {   Box.x = x, Box.y = y, Box.w = w, Box.h = h;}
private: 
// your member variables 
SDL_Rect Box; 

};

//main body of code 
int main(int argv, char** argc)
{
// declare your object here 
Button Start(23,42,8,15); 
Button Options(4,8,15,16); 
//etc
return 0; 
}
This was just an example of how you should implement a class (i'm not even getting into how they should be separated into different files or anything, the primary goal was to show you how to implement a basic class)


You might need to consider looking over your C++ to fully understand how classes work and are implemented, there seems to be a little confusion on this front.

How much programming experience do you have? because a generally accepted prerequisite of learning SDL is a basic grounding of the language you are using.

Re: SDL Menu?

Posted: Fri Mar 20, 2009 4:30 pm
by Norbo
programmerinprogress wrote:One noticable error is the class delaration, you have to put a semicolon after the closing brace, this is essential.

I didn't have a proper check through your code (just a glance), but you will probably have a few less errors now, if you add that semicolon.


EDIT:
also, you can't declare objects within main, and expect the class function implementation to understand what they are...

your init function needs to initialise a hypothetical object (i.e. you need to initialise the member functions of a class, not the objects themselves)


You might need to consider looking over your C++ to fully understand how classes work and are implemented, there seems to be a little confusion on this front.
err i kinda dont get what u mean by saying intitilize the member functions of a class.
well i fixed the semilicon error and some other things i spotted, but now i have problems with my button show function, and the way im calling it

Code: Select all

void Button::show(std::string button)
{
    if (currentButton==id) {
        draw_image(button.c_str().offset.x,button.c_str()offset.y,button.c_str().imageOver,screen);
    }
    else {
        draw_image(button.c_str().offset.x,button.c_str().offset.y,button.c_str().imageUp,screen);
    }
}
compiler says:

Code: Select all

main.cpp: In member function `void Button::show(std::string)':

main.cpp:134: error: `offset' is not a type
main.cpp:134: error: request for member of non-aggregate type before '.' token
main.cpp:134: error: expected `)' before "offset"

main.cpp:134: error: `imageOver' is not a type

main.cpp:134: error: request for member of non-aggregate type before ',' token

main.cpp:137: error: `offset' is not a type
main.cpp:137: error: request for member of non-aggregate type before '.' token
main.cpp:137: error: `offset' is not a type
main.cpp:137: error: request for member of non-aggregate type before '.' token
main.cpp:137: error: `imageUp' is not a type
main.cpp:137: error: request for member of non-aggregate type before ',' token
main.cpp: In function `int main(int, char**)':
main.cpp:177: error: `play' undeclared (first use this function)
main.cpp:177: error: (Each undeclared identifier is reported only once for each function it appears in.)
main.cpp:178: error: `howto' undeclared (first use this function)
main.cpp:179: error: `options' undeclared (first use this function)
main.cpp:180: error: `credits' undeclared (first use this function)
main.cpp:181: error: request for member `show' in `exit', which is of non-class type `void ()(int)'
main.cpp:182: error: `ok' undeclared (first use this function)
main.cpp:183: error: `back' undeclared (first use this function)
any ideas?

EDIT:
I just saw ur edited post
I have not much expirience, but im not a complete noob, because i coded before in visual basic and poscal, so i know the consepts
and also practise makes perfect, so im practising by doing this
and yeah, i never fully understanded classes. kinda hard for me.
oh and i forgot to tell u, im trying to make the buttons not clickable, but so i can navigate through them with arrows up and down

Re: SDL Menu?

Posted: Sat Mar 21, 2009 7:25 am
by Norbo
Okay i managed to fix all my compile time errors, but when i run my game it crashes immedietly.
crashes i mean the little window from microsoft pops out and wants me to send a raport to them. i have no clue why. please help me ;(

my new code:

Code: Select all

#include "SDL/SDL.h"
#include "SDL/SDL_mixer.h"
#include "SDL/SDL_ttf.h"
#include "SDL/SDL_image.h"
#include <string>
#include <fstream>
#include <stdlib.h>

using namespace std;

//The attributes of the screen 
const int SCREEN_WIDTH = 800; 
const int SCREEN_HEIGHT = 600; 
const int SCREEN_BPP = 32; 

SDL_Surface *screen = NULL;
SDL_Surface *bg = NULL;
SDL_Event event;
int currentButton = 1;
//Get the keystates 
Uint8 *keystates = SDL_GetKeyState( NULL ); 
bool mainMenu = true;

//File stream for the game log. 
std::ofstream logger( "log.txt" ); 
//===============================================================================================

class Button {
    public:
    SDL_Rect offset;
    SDL_Surface *imageUp;
    SDL_Surface *imageOver;
    int id;
    void handle_input();
    void show(std::string button);
};

    Button play;
    Button howto;
    Button options;
    Button credits;
    Button exit1;
    Button ok;
    Button back;

//===============================================================================================
//Function

SDL_Surface *load_image( std::string filename )
{ 
    //The image that's loaded 
    SDL_Surface* loadedImage = NULL; 
    //The optimized image that will be used 
    SDL_Surface* optimizedImage = NULL; 
    //Load the image using SDL_image 
    loadedImage = IMG_Load( filename.c_str() ); 
    //If the image loaded 
    if( loadedImage != NULL ) 
    { 
        //Create an optimized image 
        optimizedImage = SDL_DisplayFormat( loadedImage ); 
        //Free the old image 
        SDL_FreeSurface( loadedImage ); 
    } 
    //Return the optimized image 
    return optimizedImage; 
} 

void draw_image(int x,int y,SDL_Surface *source,SDL_Surface *destination)
{
    //Make a temporary rectangle to hold the offsets 
    SDL_Rect offset; 
    
    //Give the offsets to the rectangle 
    offset.x = x; 
    offset.y = y; 
        
    SDL_BlitSurface(source,NULL,destination,&offset); 
}

void Button::handle_input()
{
    //If up is pressed 
    if( keystates[ SDLK_UP ] ) 
    { 
        currentButton--;
    } 
    //If down is pressed 
    if( keystates[ SDLK_DOWN ] ) 
    { 
       currentButton++;
    }
}

void initButtons()
{
    play.id = 1;
    howto.id = 2;
    options.id = 3;
    credits.id = 4;
    exit1.id = 5;
    ok.id = 6;
    back.id = 7;
    play.offset.x = 100;
    play.offset.y = 100;
    howto.offset.x = 100;
    howto.offset.y = 200;
    options.offset.x = 100;
    options.offset.y = 300;
    credits.offset.x = 100;
    credits.offset.y = 400;    
    exit1.offset.x = 100;
    exit1.offset.y = 500;
    ok.offset.x = 100;
    ok.offset.y = 600;
    back.offset.x = 100;
    back.offset.y = 700;
    back.imageOver = load_image("graphics/back_mouseover.bmp");
    back.imageUp = load_image("graphics/back_up.bmp");
    credits.imageOver = load_image("graphics/credits_mouseover.bmp");
    credits.imageUp = load_image("graphics/credits_up.bmp");
    exit1.imageOver = load_image("graphics/exit_mouseover.bmp");
    exit1.imageUp = load_image("graphics/exit_up.bmp");
    howto.imageOver = load_image("graphics/howto_mouseover.bmp");
    howto.imageUp = load_image("graphics/howto_up.bmp");
    ok.imageOver = load_image("graphics/ok_button mouse_over.bmp");
    ok.imageUp = load_image("graphics/ok_button_up.bmp");
    play.imageOver = load_image("graphics/playgame_mouseover.bmp");
    play.imageUp = load_image("graphics/playgame_up.bmp");
}

void Button::show(string button)
{
    if (currentButton==id) {
        draw_image(offset.x,offset.y,imageOver,screen);
    }
    else {
        draw_image(offset.x,offset.y,imageUp,screen);
    }
}

void clean_up() 
{ 
    SDL_FreeSurface(bg);
    //Quit SDL 
    SDL_Quit(); 
} 

bool init()
{
    //Initialize all SDL subsystems 
    if(SDL_Init(SDL_INIT_EVERYTHING)==-1) { 
        return false; 
    } 
    //Set up the screen 
    screen = SDL_SetVideoMode(SCREEN_WIDTH,SCREEN_HEIGHT,SCREEN_BPP,SDL_SWSURFACE); 
    if (screen == NULL)
    {
        return false;
    }
    //Set the window caption 
    SDL_WM_SetCaption("yo",NULL); 
    return true;
}

#undef main
int main( int argc, char* args[] ) 
{
    bool quit = false;
    if (init == false){
        return 1;
    }
    while (quit == false)
    {
        while (mainMenu)
        {
            initButtons();
            play.show("play");
            howto.show("howto");
            options.show("options");
            credits.show("credits");
            exit1.show("exit");
            ok.show("ok");
            back.show("back");
        }
        //While there's an event to handle 
        while(SDL_PollEvent(&event)) 
        { 
            //If the user has Xed out the window 
            if(event.type == SDL_QUIT) 
            { 
                //Quit the program 
                quit = true; 
            } 
        } 
    }
    if (quit==true) {
        clean_up();
    }
    return 0;
} 

Re: SDL Menu?

Posted: Sat Mar 21, 2009 9:45 am
by programmerinprogress
I have not much expirience, but im not a complete noob, because i coded before in visual basic and poscal, so i know the concepts
That's all fine and well, you know how program, however, classes are a component of Object-Oriented Programming (or OOP), you need to understand how they work for my suggestion, and how to implement them, they work a little differently to normal structured or procedural methods.

In your 'Show' method, why do you pass a string?, I see no use for it?

Why don't you initialise some of your variables in your constructor?, it would be so much easier to read than putting them in a big list in a function.

your program could be crashing, because you're Init'ing your buttons every frame, your probably causing some sort of a memory leak or something by putting the who thing within a while loop.

if you want to keep it like that, I would definately suggest you make sure that your surfaces are freed before you try to allocate the pointer again.

so you could do something like this in your initButtons() function (although I would probably think of a different way of doing this whole 'init button' thing)

Code: Select all

if(Back.imageOver != NULL)
{
SDL_FreeSurface(Back.imageOver); 
Back.imageOver = NULL; 
}
Back.imageover = load_image("graphics/back_mouseover.bmp");

I hope you get this sorted out, but I really would advise you to look up some theory on object oriented programming
(any decent C++ book will give yo a basic footing on this)

I did make the assumption that you understood OOP when I suggested a class, so I apologise for that.