Bienvenue, Invité. Merci de vous connecter ou de vous inscrire.
Avez-vous perdu votre e-mail d'activation ?

Auteur Sujet: Game States - ChangeStates  (Lu 3183 fois)

0 Membres et 1 Invité sur ce sujet

Zouox

  • Newbie
  • *
  • Messages: 2
    • Voir le profil
    • E-mail
Game States - ChangeStates
« le: Juillet 07, 2014, 10:44:11 pm »
Bonsoir,

Je débute sur SFML avec le C++ (auparavant, j'utilisais SDL avec le langage C). J'ai migré vers SFML pour mieux structurer mes projets en gérant les Game States.  :)

Cependant, j'ai du mal à passer du menu principal au jeu, c'est à dire à changer d'état.

Je vous joins les trois fichiers concernés, le dernier est celui du menu, où j'aimerais changer d'état.

Voici la structure du programme :
  • main.cpp
  • gameengine.cpp
  • menu.cpp
  • game.cpp

  • gameengine.h
  • menu.h
  • game.h
  • constantes.h
  • gamestate.h



Fichier Main.cpp :
int main()
{

    GameEngine engine;
        engine.Init("Space Exploration", SCREEN_WIDTH, SCREEN_HEIGHT);

    //On instancie le menu principal
        engine.ChangeState(Menu::Instance());

        //Boucle principale
        while (engine.Running())
        {
                engine.HandleEvents();
                engine.Update();
                engine.Draw();
        }

    //On nettoie l'engine
        engine.Cleanup();

    return 0;
}

Les fonctions de GameEngine.cpp :
void GameEngine::Init(const char* titre, int largeur, int hauteur)
{
    m_running = true;
    m_window = new sf::RenderWindow(sf::VideoMode(largeur, hauteur), titre);
}

void GameEngine::Cleanup()
{
    delete m_window;
}

void GameEngine::ChangeState(GameState* state)
{
        if(!states.empty())
    {
                states.back()->Cleanup();
                states.pop_back();
        }

        states.push_back(state);
        states.back()->Init();
}

void GameEngine::PushState(GameState* state)
{
        if(!states.empty())
    {
                states.back()->Pause();
        }

        states.push_back(state);
        states.back()->Init();
}

void GameEngine::PopState()
{
        if(!states.empty())
    {
                states.back()->Cleanup();
                states.pop_back();
        }

        if(!states.empty())
    {
                states.back()->Resume();
        }
}

Fichier Menu.cpp :
Menu Menu::m_Menu;

void Menu::Init() {}

void Menu::Cleanup()
{}

void Menu::Pause()
{}

void Menu::Resume()
{}

void Menu::HandleEvents(GameEngine* m_engine)
{
    //On inspecte tous les évènements de la fenêtre qui ont été émis depuis la précédente itération
    sf::Event event;

    while(m_engine->getWindow()->pollEvent(event))
    {
        if(event.type == sf::Keyboard::isKeyPressed(sf::Keyboard::Return)) {
//Je souhaite changer d'état ici
        }

        //Pour pouvoir fermer la fenêtre
        if(event.type == sf::Event::Closed || sf::Keyboard::isKeyPressed(sf::Keyboard::Escape)) {
            m_engine->getWindow()->close();
            m_engine->Quit();
        }
    }
}

void Menu::Update(GameEngine* m_engine)
{}

void Menu::Draw(GameEngine* m_engine)
{
   m_engine->getWindow()->clear(sf::Color::Black);

   sf::Vector2i mouse = sf::Mouse::getPosition();

    //charger bg
    sf::Texture menu_bg;
    if (!menu_bg.loadFromFile("ressources/menu_bg.jpg")){}

    //charger font
    sf::Font font;
    if (!font.loadFromFile("ressources/nulshock_bd.ttf")){}

    //draw
    //background
    sf::Sprite background;
    background.setTexture(menu_bg);
    background.setPosition(0, 0);
    m_engine->getWindow()->draw(background);

    //boutons
    //GAME
    sf::Text game;
    game.setFont(font);
    game.setString("GAME");
    game.setCharacterSize(50);
    game.setColor(sf::Color::White);
    sf::FloatRect gameRect = game.getLocalBounds();
    game.setOrigin(gameRect.left + gameRect.width/2.0f,
    gameRect.top  + gameRect.height/2.0f);
    game.setPosition(sf::Vector2f(SCREEN_WIDTH/2.0f,SCREEN_HEIGHT/2.0f-200));
    m_engine->getWindow()->draw(game);

    //OPTIONS
    sf::Text options;
    options.setFont(font);
    options.setString("OPTIONS");
    options.setCharacterSize(50);
    options.setColor(sf::Color::White);
    sf::FloatRect optionsRect = options.getLocalBounds();
    options.setOrigin(optionsRect.left + optionsRect.width/2.0f,
    optionsRect.top  + optionsRect.height/2.0f);
    options.setPosition(sf::Vector2f(SCREEN_WIDTH/2.0f,SCREEN_HEIGHT/2.0f));
    m_engine->getWindow()->draw(options);

    //EXIT
    sf::Text exit;
    exit.setFont(font);
    exit.setString("EXIT");
    exit.setCharacterSize(50);
    exit.setColor(sf::Color::White);
    sf::FloatRect exitRect = exit.getLocalBounds();
    exit.setOrigin(exitRect.left + exitRect.width/2.0f,
    exitRect.top  + exitRect.height/2.0f);
    exit.setPosition(sf::Vector2f(SCREEN_WIDTH/2.0f,SCREEN_HEIGHT/2.0f+200));
    m_engine->getWindow()->draw(exit);

    m_engine->getWindow()->display();
}


Merci beaucoup d'avance !
Bonne soirée.

Cmdu76

  • Full Member
  • ***
  • Messages: 194
    • Voir le profil
Re : Game States - ChangeStates
« Réponse #1 le: Juillet 08, 2014, 02:05:57 am »
Bonsoir,

Voici le lien d'une StateMachine plutôt cool en C++ (c'est pas de moi c'est de eXpl0it3r :) )

https://github.com/eXpl0it3r/SmallGameEngine

Sinon si tu es nouveau, je te conseille fortement d'aller voir ici :

https://github.com/SFML/SFML-Game-Development-Book

Il y a un chapitre sur les States qui est très bien construit :)



Sinon, par rapport à tes fichiers...

Pourquoi recrées-tu tes objets à chaque passage dans la boucle dans Menu::Draw ??? Cela prends beaucoup de temps pour une fonction a besoin d'être très rapide... Tu dois donc sauvegarder tes objets en tant que membres dans ta classe Menu (si tu viens vraiment du C et que tu ne comprends rien à ce que je viens de dire, cherche un cours sur la POO : http://fr.openclassrooms.com/informatique/cours/programmez-avec-le-langage-c/introduction-la-verite-sur-les-strings-enfin-devoilee)

Ensuite, je pense que voir les .h / .hpp de tes classes peut être utile :)

Petite remarque aussi, utilise les std::string à la place des const char* c'est plus C++ et personnellement c'est beaucoup plus simple :)

Petite remarque encore, en C++ tu peux aussi utiliser des références à la place de mettre des pointeurs partout (ça évite surtout de faire pas mal d'erreurs de mémoires)


Voilà, je te souhaite bonne chance :)
Le C++ est bien différent du C et la transition est un peu dure au début :)
« Modifié: Juillet 08, 2014, 02:14:20 am par Cmdu76 »

Zouox

  • Newbie
  • *
  • Messages: 2
    • Voir le profil
    • E-mail
Re : Game States - ChangeStates
« Réponse #2 le: Juillet 08, 2014, 03:32:32 pm »
Bonjour,

Avant tout, merci de m'avoir répondu !  :)

J'avais déjà vu les fichiers sources de Laurent Gomila, mais ils sont un peu lourds pour un débutant comme moi, en outre la State Machine de eXpl0it3r m'a l'air plus abordable, je regarderai plus en détails. ;)

EDIT : J'ai recommencé en me basant sur la State Machine de eXpl0it3r qui est mieux construite, cependant j'ai du mal à comprendre comment changer d'état de façon optimale.

Code source : https://github.com/zouox/Space_exploration

ReEDIT : J'ai trouvé par moi même.  ;D

Cependant j'ai une dernière question : ma façon de changer d'états est-elle correcte? Vous pouvez accéder au code source sur la page GitHub.

Merci d'avance!
« Modifié: Juillet 08, 2014, 09:16:21 pm par Zouox »

Cmdu76

  • Full Member
  • ***
  • Messages: 194
    • Voir le profil
Re : Game States - ChangeStates
« Réponse #3 le: Juillet 09, 2014, 02:27:06 am »
J'ai pris un exemple de ton code dans MenuState.cpp :

if(m_selectedItem == 1) {
                            m_next = StateMachine::build<PlayState>(m_machine, m_window, true);
                        } else if(m_selectedItem == 2) {
                            m_next = StateMachine::build<OptionsState>(m_machine, m_window, false);
                        } else if(m_selectedItem == 3) {
                            m_next = StateMachine::build<QuitterState>(m_machine, m_window, false);
                        }

Et oui, ça me paraît bien :)

Il me semble, que pour passer d'un State à l'autre il faut bien faire comme cela

Par contre il faut initialiser la StateMachine avec run() (mais c'est fait dans la fonction Application::run() :
m_machine.run( StateMachine::build<IntroState>( m_machine, m_window, true ) );