0
\$\begingroup\$
#include<SFML/Graphics.hpp>
#include<iostream>
#include <SFML/Graphics/Font.hpp>
#include <SFML/Audio.hpp>
#include "menu1.h"
//#include "menuNames.h"
using namespace std;
using namespace sf;

/*
    class menu2play
    in main function:
        check event if event keboard enter
            check mainMenuPressed == 0:
            window menu2play
*/

int  page_number;
sf::Event event;
bool check(int x, int y, int& value);


int boarddata1[9][9] = {
    {0, 0, 0, 2, 6, 0, 7, 0, 1},
    {6, 8, 0, 0, 7, 0, 0, 9, 0},
    {1, 9, 0, 0, 0, 4, 5, 0, 0},
    {8, 2, 0, 1, 0, 0, 0, 4, 0},
    {0, 0, 4, 6, 0, 2, 9, 0, 0},
    {0, 5, 0, 0, 0, 3, 0, 2, 8},
    {0, 0, 9, 3, 0, 0, 0, 7, 4},
    {0, 4, 0, 0, 5, 0, 0, 3, 6},
    {7, 0, 3, 0, 1, 8, 0, 0, 0}
};

int answer1[9][9] = {
  {4, 3, 5, 2, 6, 9, 7, 8, 1},
  {6, 8, 2, 5, 7, 1, 4, 9, 3},
  {1, 9, 7, 8, 3, 4, 5, 6, 2},
  {8, 2, 6, 1, 9, 5, 3, 4, 7},
  {3, 7, 4, 6, 8, 2, 9, 1, 5},
  {9, 5, 1, 7, 4, 3, 6, 2, 8},
  {5, 1, 9, 3, 2, 6, 8, 7, 4},
  {2, 4, 8, 9, 5, 7, 1, 3, 6},
  {7, 6, 3, 4, 1, 8, 2, 5, 9}
};

int boardData2[9][9] = {

    {2, 0, 0, 0, 0, 1, 0, 0, 7},
    {0, 0, 0, 8, 0, 9, 4, 2, 0},
    {0, 0, 3, 6, 0, 0, 0, 0, 0},
    {0, 7, 2, 0, 3, 0, 0, 0, 0},
    {9, 3, 0, 0, 0, 2, 1, 5, 0},
    {8, 6, 0, 0, 9, 0, 7, 0, 0},
    {5, 0, 0, 9, 0, 0, 0, 0, 0},
    {0, 1, 0, 2, 0, 3, 6, 0, 8},
    {0, 8, 0, 0, 6, 7, 2, 0, 0}
};

int answer2[9][9] = {

{2, 9, 8, 3, 4, 1, 5, 6, 7},
{6, 5, 1, 8, 7, 9, 4, 2, 3},
{7, 4, 3, 6, 2, 5, 9, 8, 1},
{1, 7, 2, 5, 3, 6, 8, 4, 9},
{9, 3, 4, 7, 8, 2, 1, 5, 6},
{8, 6, 5, 1, 9, 4, 7, 3, 2},
{5, 2, 6, 9, 1, 8, 3, 7, 4},
{4, 1, 7, 2, 5, 3, 6, 9, 8},
{3, 8, 9, 4, 6, 7, 2, 1, 5}
};

int boardData3[9][9] = {
{8, 0, 1, 0, 0, 0, 0, 0, 4},
{4, 5, 0, 3, 0, 2, 6, 0, 7},
{3, 0, 0, 0, 0, 0, 5, 9, 1},
{0, 3, 0, 0, 0, 0, 0, 0, 8},
{6, 1, 2, 9, 8, 0, 0, 0, 0},
{0, 0, 5, 1, 6, 0, 0, 2, 3},
{0, 4, 0, 5, 0, 0, 8, 7, 0},
{0, 6, 0, 2, 4, 0, 0, 5, 0},
{0, 9, 0, 8, 0, 0, 0, 1, 2}
};

int answer3[9][9] = {

{8, 7, 1, 6, 5, 9, 2, 3, 4},
{4, 5, 9, 3, 1, 2, 6, 8, 7},
{3, 2, 6, 4, 7, 8, 5, 9, 1},
{9, 3, 4, 7, 2, 5, 1, 6, 8},
{6, 1, 2, 9, 8, 3, 7, 4, 5},
{7, 8, 5, 1, 6, 4, 9, 2, 3},
{2, 4, 3, 5, 9, 1, 8, 7, 6},
{1, 6, 8, 2, 4, 7, 3, 5, 9},
{5, 9, 7, 8, 3, 6, 4, 1, 2}
};
int usedarray[9][9];
int answer[9][9];

bool lock[9][9];


int X, Y;
int counter = 0;
int variable = 0;
sf::Text boardtext[9][9];
sf::RenderWindow window1(sf::VideoMode(1067, 715), "Sudoku!");
sf::SoundBuffer wrongAnswer;
sf::Sound explosionWrong;
sf::SoundBuffer youWin;
sf::Sound explosionWin;

int raw, column;

int main()
{
    RenderWindow window(sf::VideoMode(600, 600), "suduko");

    menu1 Menu(500, 500);
    //menu1 menuPlay(500, 500);
    /*menuNames  menu(string);
    menuNames m;*/
    while (window.isOpen())
    {
        sf::Event event;
        while (window.pollEvent(event))
        {
            if (event.type == sf::Event::Closed)
                window.close();
            if (event.type == sf::Event::KeyReleased)
            {
                if (event.key.code == sf::Keyboard::Up)
                {
                    Menu.moveUp();
                    break;
                }
                if (event.key.code == sf::Keyboard::Down)
                {
                    Menu.moveDown();
                    break;

                }
                //choose page
                if (event.key.code == sf::Keyboard::Return) //enter
                {

                    if (Menu.mainMenuPressed() == 0)
                    {
                        window.close();
                        page_number = 0;
                    }
                    if (Menu.mainMenuPressed() == 1)
                    {
                        window.close();
                        page_number = 1;
                    }
                    if (Menu.mainMenuPressed() == 2)
                    {
                        window.close();
                        page_number = 2;
                    }
                }


            }

        }

        window.clear();
        Menu.draw(window);
        window.display();
    }
        if (page_number == 0)
        {
            srand(time(0));
            int randomnumber = rand() % 3 + 1;

            for (int i = 0; i < 9; i++) {
                for (int j = 0; j < 9; j++) {


                    if (randomnumber == 1)
                    {

                        usedarray[i][j] = boarddata1[i][j];
                        answer[i][j] = answer1[i][j];

                    }
                    else if (randomnumber == 2)
                    {
                        usedarray[i][j] = boardData2[i][j];
                        answer[i][j] = answer2[i][j];
                    }
                    else
                    {
                        usedarray[i][j] = boardData3[i][j];
                        answer[i][j] = answer3[i][j];

                    }


                }
            }




            for (int i = 0; i < 9; i++)
            {
                for (int j = 0; j < 9; j++)
                {
                    if (usedarray[i][j] != 0)

                        lock[i][j] = 1;
                    else
                        counter++;
                }
            }

            sf::Texture texture;
            texture.loadFromFile("sudoku-test.png");
            sf::Sprite background(texture);
            background.setScale(1, 1);

            sf::Font font;
            if (!font.loadFromFile("arial.ttf"))
                throw("couldn't open font");

            window1.clear();

            window1.display();



            sf::Text space;
            space.setString(" ");

            if (wrongAnswer.loadFromFile("wrong answer.wav") == 0)
            {
                return 1;
            }
            if (youWin.loadFromFile("clapping.wav") == 0)
            {
                return 1;
            }


            for (int i = 0; i < 9; i++)
            {
                for (int j = 0; j < 9; j++)
                {
                    boardtext[i][j] = sf::Text();
                    boardtext[i][j].setCharacterSize(30);
                    boardtext[i][j].setFont(font);
                    boardtext[i][j].setFillColor(sf::Color::Blue);
                    boardtext[i][j].setString(std::to_string(usedarray[i][j]));
                    boardtext[i][j].setPosition(sf::Vector2f((window1.getSize().x - 337) / 9 * i + 35, window1.getSize().y / 9 * j + 25));
                }
            }

        //mouse event
        if (sf::Mouse::isButtonPressed(sf::Mouse::Left)) {
            sf::Vector2i position = sf::Mouse::getPosition();
            sf::Mouse::setPosition(sf::Vector2i(100, 200), window1);
        }



        //play
        sf::RenderWindow window1(VideoMode(1067, 715), "play", sf::Style::Close);
        while (window1.isOpen())
            //background.jpeg


            while (window1.pollEvent(event))
            {

                if (event.type == sf::Event::Closed)
                    window1.close();

                switch (event.type)
                {
                case sf::Event::MouseButtonPressed:
                    X = sf::Mouse::getPosition(window1).x;
                    Y = sf::Mouse::getPosition(window1).y;


                    raw = X / 80;
                    column = Y / 80;
                    cout << "i" << raw << " j " << column << endl;
                    if ((X < 861) && (X > 758)) 
                    {
                        if ((Y > 529) && (Y < 587)) {
                            variable = 0;
                        }
                    }
                    if (X > 720)
                    {
                        if ((Y > 160) && (Y <= 260)) {
                            variable = (((X - 780) / 74) + 1);
                        }
                        else if ((Y > 260) && (Y <= 369)) {
                            variable = (((X - 780) / 74) + 4);
                        }
                        else if ((Y > 369) && (Y <= 478)) {
                            variable = (((X - 780) / 74) + 7);
                        }
                        std::cout << "number is" << variable << endl;
                    }
                    if (X < 720) check(raw, column, variable);


                    break;
                }


            }
        window1.clear();

        window1.draw(background);

        window1.display();
        for (int i = 0; i < 9; i++)
        {
            for (int j = 0; j < 9; j++)
            {
                if (usedarray[i][j] == 0)
                    window1.draw(space);
                else
                    window1.draw(boardtext[i][j]);


            }
        }


    /*  window1.clear();
        
        window1.display();*/

    }

}
    

    //if (page_number == 1)
    //{
    //  //About
    //  sf::RenderWindow window_play(VideoMode(300, 300), "About", sf::Style::Close);
    //  while (window_play.isOpen())
    //  {
    //      while (window_play.pollEvent(event))
    //      {
    //          if (event.type == sf::Event::Closed)
    //              window_play.close();

    //          cout << "Tesser Redaa";
    //          cout << "Smaa Salah";
    //          cout << "Doaa Mohamed";
    //          cout << "Salwa Ahmed";
    //          cout << "Menna Shaaban";
    //          cout << "Rana Ahmed";
    //          cout << "ranneem Loaa";

    //      }
    //      window_play.clear();
    //      window_play.display();
    //  }
    //}


    //if (page_number == 2)
    //{
    //  //play
    //  sf::RenderWindow window_play(VideoMode(300, 300), "Exit", sf::Style::Close);
    //  while (window_play.isOpen())
    //  {
    //      while (window_play.pollEvent(event))
    //      {
    //          if (event.type == sf::Event::Closed)
    //              window_play.close();
    //          break;

    //      }
    //      window_play.clear();

    //      window_play.display();
    //  }
    //}

    //if (page_number == 2)
    //{
    //  //exit
    //  break;
    //}

    /*return 0;

}*/

bool check(int i, int j, int& value)
{
    if (lock[i][j] == 0)
    {
        i = raw;
        j = column;
        cout << "correct answer is" << answer[i][j] << endl;
        if (value == answer[i][j])
        {
            usedarray[i][j] = value;
            lock[i][j] = 1;
            counter--;
            boardtext[i][j].setFillColor(sf::Color::Green);
            cout << usedarray[i][j] << " correct\n";
            boardtext[i][j].setString(std::to_string(usedarray[i][j]));


            if (counter == 0)
            {
                cout << "you winned !!!!!";


                explosionWin.setBuffer(youWin);
                explosionWin.setVolume(1000);

                explosionWin.play();
            }

            return 1;
        }
        else
        {
            usedarray[i][j] = value;
            boardtext[i][j].setFillColor(sf::Color::Red);
            cout << boarddata1[i][j] << " wrong\n";
            boardtext[i][j].setString(std::to_string(usedarray[i][j]));


            explosionWrong.setBuffer(wrongAnswer);
            explosionWrong.setVolume(1000);

            explosionWrong.play();

            return 0;

        }
    }


}
\$\endgroup\$
7
  • \$\begingroup\$ Why do you have two main functions? What's the actual issue you're currently facing, and what have you tried to solve it? \$\endgroup\$
    – Vaillancourt
    Commented Jun 4, 2021 at 14:01
  • \$\begingroup\$ @Vaillancourt i edit the code to the last thing i do in it ... i what to make the game appear when i enter play \$\endgroup\$ Commented Jun 4, 2021 at 14:16
  • \$\begingroup\$ i made a class to do the menu in the menu there is 3 options play ,about and exit and i what to make the game appear when i enter play \$\endgroup\$ Commented Jun 4, 2021 at 14:17
  • \$\begingroup\$ Typically, we'll only create one window for the whole game, not one per "state". So what you want is essentially a state machine; first state is the "Menu"; when you enter the state, you initialize the gfx of the Menu; each frame you render that state, and you update the logic, where you check if the player has clicked any menu button. If they do, you request your main loop to swap the state after the current loop execution. When you swap the state, you first call "on exit state" of the Menu state where you clean everything up, then you initialize the new Play state by loading the gfx. \$\endgroup\$
    – Vaillancourt
    Commented Jun 4, 2021 at 14:23
  • \$\begingroup\$ Then when the main loop runs, you update the logic of the Play state, where it's your actual game. \$\endgroup\$
    – Vaillancourt
    Commented Jun 4, 2021 at 14:24

1 Answer 1

1
\$\begingroup\$

Just like what's been said in the comment section of your question, you typically create one (1) window, with a lifetime of game startup to game shutdown, and then you have a so-called state machine, which controls what state the game is/should be in.

What I usually do is that I have a base class, which serves as a single state in my game and other sub classes inherits from that class. When I say sub classes, I mean each individual state in my game, like menu state, game state, quit state etc.

When I have that structure set up, I usually also have a state machine class, which only purpose is to keep track of the states that exist in the game, handling switching from one state to another and finally also to update- and render the state the game is currently in.

Let's see how we can structure the code to make this happen:

First we have the state class, which every state in the game should inherit from.

class IState
{
public:

             IState         (void) {}
    virtual ~IState         (void) {}

    virtual bool Create     (CApplication* pApplication, CStateMachine* pStateMachine)  = 0;
    virtual void Destroy    (void)                                                      = 0;
    virtual void OnCreate   (void)                                                      = 0;
    virtual void OnDestroy  (void)                                                      = 0;
    virtual void OnEnter    (void)                                                      = 0;
    virtual void OnExit     (void)                                                      = 0;
    virtual void Update     (const float DeltaTime)                                     = 0;
    virtual void Render     (void)                                                      = 0;

protected:

    CApplication*   m_pApplication;

    CStateMachine*  m_pStateMachine;

};

As you can see, it's an abstract class with only virtual functions, which will be called by the state machine later.

Next we have each state in the game and I will show an example of a menu state.

/**
* h file:
**/

class CStateMenu : public IState
{
public:

     CStateMenu     (void);
    ~CStateMenu     (void);

    bool Create     (CApplication* pApplication, CStateMachine* pStateMachine) override;
    void Destroy    (void) override;
    void OnCreate   (void) override;
    void OnDestroy  (void) override;
    void OnEnter    (void) override;
    void OnExit     (void) override;
    void Update     (const float DeltaTime) override;
    void Render     (void) override;

private:

};

//////////////////////////////////////////////////////////////////////////

/**
* cpp file:
**/

#include "CStateMenu.h"

#include "CApplication.h"
#include "CStateMachine.h"

#include <SFML/Window.hpp>

CStateMenu::CStateMenu(void)
{
    m_pApplication  = nullptr;
    m_pStateMachine = nullptr;
}

CStateMenu::~CStateMenu(void)
{

}

bool CStateMenu::Create(CApplication* pApplication, CStateMachine* pStateMachine)
{
    // Stuff that needs to be created/set at application startup, and not on each state change, and needs to last during the lifetime of the state

    m_pApplication  = pApplication;
    m_pStateMachine = pStateMachine;

    return true;
}

void CStateMenu::Destroy(void)
{
    // Stuff that needs to be destroyed/unset at application shutdown, and not on each state change

    m_pStateMachine = nullptr;
    m_pApplication  = nullptr;
}

void CStateMenu::OnCreate(void)
{
    // Create the menu objects, load font file(s), load menu music file(s) etc

    /*
    Example:

    ButtonStartGame.Create();
    ButtonQuit.Create();
    Music->Load("Menu music.mp3");
    */
}

void CStateMenu::OnDestroy(void)
{
    // Destroy the menu objects, unload font file(s), unload menu music file(s) etc

    /*
    Example:

    Music->Unload();
    ButtonQuit.Destroy();
    ButtonStartGame.Destroy();
    */
}

void CStateMenu::OnEnter(void)
{
    // Start the menu music etc

    /*
    Example:

    Music->Play();
    */
}

void CStateMenu::OnExit(void)
{
    // Stop the menu music etc

    /*
    Example:

    Music->Stop();
    */
}

void CStateMenu::Update(const float DeltaTime)
{
    // Update the menu, handle input from the keyboard and/or mouse etc

    if(sf::Keyboard::isKeyPressed(sf::Keyboard::Return))
        m_pStateMachine->SetState(m_pStateMachine->GetStateGame());

    /*
    Example for mouse usage:

    if(ButtonStartGame.Pressed())
        m_pStateMachine->SetState(m_pStateMachine->GetStateGame());
    */
}

void CStateMenu::Render(void)
{
    // Render the menu buttons etc

    /*
    Example:

    ButtonGameStart.Render();
    ButtonQuit.Render();
    */
}

Note how the menu state class is inheriting from the state class and overrides its virtual functions. If you have, say, a class called StateGame, and you want to use it as a game state as well, that class should inherit from the state and override its functions too, just like the menu state class does.

In the menu state class above, I'm showing an example on how to use it, how to render stuff and also how to change from the menu state into the game state, which happens when the return key on the keyboard is pressed. The same usage can be used when you want to switch back to the menu state from the game state etc.

Next we have the state machine class, which, again, will handle the different states the game can/should be in, handling switching from one state to another and finally also to update- and render the current state the game is in.

/**
* h file:
**/

class CStateMachine
{
public:

     CStateMachine              (void);
    ~CStateMachine              (void);

    bool        Create          (CApplication* pApplication);
    void        Destroy         (void);

    void        Update          (const float DeltaTime);
    void        Render          (void);

    void        SetState        (IState* pNewState);

public:

    CStateMenu* GetStateMenu    (void)  const   {return m_pStateMenu;}
    CStateGame* GetStateGame    (void)  const   {return m_pStateGame;}

private:

    void SwitchState(void);

private:

    IState*     m_pCurrentState;
    IState*     m_pNextState;

    CStateMenu* m_pStateMenu;
    CStateGame* m_pStateGame;

};

//////////////////////////////////////////////////////////////////////////

/**
* cpp file:
**/

#include "CStateMachine.h"

CStateMachine::CStateMachine(void)
: m_pCurrentState(nullptr)
, m_pNextState(nullptr)
, m_pStateMenu(nullptr)
, m_pStateGame(nullptr)
{

}

CStateMachine::~CStateMachine(void)
{

}

bool CStateMachine::Create(CApplication* pApplication)
{
    m_pStateMenu = new CStateMenu;
    if(!m_pStateMenu->Create(pApplication, this))
        return false;

    m_pStateGame = new CStateGame;
    if(!m_pStateGame->Create(pApplication, this))
        return false;

    // Set the start state
    m_pCurrentState = m_pStateMenu;
    m_pCurrentState->OnCreate();
    m_pCurrentState->OnEnter();

    return true;
}

void CStateMachine::Destroy(void)
{
    m_pCurrentState = nullptr;
    m_pNextState    = nullptr;

    m_pStateGame->Destroy();
    delete m_pStateGame;
    m_pStateGame = nullptr;

    m_pStateMenu->Destroy();
    delete m_pStateMenu;
    m_pStateMenu = nullptr;
}

void CStateMachine::Update(const float DeltaTime)
{
    m_pCurrentState->Update(DeltaTime);

    if(m_pNextState)
        SwitchState();
}

void CStateMachine::Render(void)
{
    m_pCurrentState->Render();
}

void CStateMachine::SetState(IState* pNewState)
{
    // Queue a state change, which will occur when the current state's update function is finished    
    m_pNextState = pNewState;
}

void CStateMachine::SwitchState(void)
{
    /*
    I have separated the state creation/preparation into two functions since you
    might wanna execute 'OnCreate' / 'OnDestroy' in a loading thread to load assets etc,
    while having the main thread showing a loading screen
    */

    m_pCurrentState->OnExit();
    m_pCurrentState->OnDestroy();

    m_pCurrentState = m_pNextState;
    m_pCurrentState->OnCreate();
    m_pCurrentState->OnEnter();

    m_pNextState = nullptr;
}

The class itself is very simple, with only a few functions, and using this class is very simple as well.

I always try to make the main function as short/minimal as possible, so I usually end up creating an application class, which creates my window and other needed objects for my game, while also keeping track of their lifetime etc. Let's see how a simple application class can look like:

/**
* h file:
**/

class CApplication
{
public:

     CApplication                   (void);
    ~CApplication                   (void);

    bool                Create      (void);
    void                Destroy     (void);

    void                Run         (void);

    void                Update      (void);
    void                Render      (void);

    void                Quit        (void);

public:

    sf::RenderWindow&   GetWindow   (void)  {return m_Window;}

private:

    sf::RenderWindow    m_Window;

    sf::Clock           m_Clock;

    sf::Event           m_Event;

    CStateMachine*      m_pStateMachine;

    bool                m_Running;

};

//////////////////////////////////////////////////////////////////////////

/**
* cpp file:
**/

#include "CApplication.h"

CApplication::CApplication(void)
: m_Window()
, m_Clock()
, m_Event()
, m_pStateMachine(nullptr)
, m_Running(true)
{
    m_Clock.restart();
}

CApplication::~CApplication(void)
{

}

bool CApplication::Create(void)
{
    m_Window.create(sf::VideoMode(1280, 720), "SFML state machine");

    m_pStateMachine = new CStateMachine;
    if(!m_pStateMachine->Create(this))
        return false;

    return true;
}

void CApplication::Destroy(void)
{
    m_pStateMachine->Destroy();
    delete m_pStateMachine;
    m_pStateMachine = nullptr;

    m_Window.close();
}

void CApplication::Run(void)
{
    while(m_Running)
    {
        Update();
        Render();
    }
}

void CApplication::Update(void)
{
    while(m_Window.pollEvent(m_Event))
    {
        switch(m_Event.type)
        {
            case sf::Event::Closed:
            {
                Quit();

                break;
            }
        }
    }

    m_pStateMachine->Update(m_Clock.restart().asSeconds());
}

void CApplication::Render(void)
{
    m_Window.clear();

    m_pStateMachine->Render();

    m_Window.display();
}

void CApplication::Quit(void)
{
    m_Running = false;
}

As you can see, the application class creates the SFML window and the state machine, which creates each individual state.

Finally, the main function/entry point would then look something like this:

int main()
{
    CApplication* pApplication = new CApplication;

    if(!pApplication->Create())
        return 0;

    pApplication->Run();

    pApplication->Destroy();
    delete pApplication;
    pApplication = nullptr;

    return 0;
}

Hope this helps a bit.

Let me know if you have any questions and/or need me to explain something better.

\$\endgroup\$
0

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .