diff --git a/include/gui/modal.hpp b/include/gui/modal.hpp new file mode 100644 index 0000000..7f38df4 --- /dev/null +++ b/include/gui/modal.hpp @@ -0,0 +1,60 @@ +#ifndef __SKIZZLE_MODAL_HPP__ +#define __SKIZZLE_MODAL_HPP__ + +#include +#include +#include + +/** + * Classe de base pour les fenêtres modales + * qui bloquent l'accès aux autres éléments du jeu + */ +class Modal { +protected: + sfg::Window::Ptr modal_main_window; + sfg::Window::Ptr modal_inner_window; + + sfg::Box::Ptr layout_box; + sfg::Box::Ptr buttons_box; + + sfg::Label::Ptr title_label; + sfg::Label::Ptr subtitle_label; + +public: + Modal(); + + /** + * Récupère la fenêtre de la modale + */ + sfg::Window::Ptr getWindow(); + + /** + * Récupère la boîte de layout interne de la modale + */ + sfg::Box::Ptr getLayoutBox(); + + /** + * Ajoute un nouveau bouton à la modale + */ + sfg::Button::Ptr addButton( + sf::String label, + std::function callback = std::function() + ); + + /** + * Modifie le titre de la modale + */ + void setTitle(sf::String label); + + /** + * Modifie le sous-titre de la modale + */ + void setSubtitle(sf::String label); + + /** + * Redimensionne la modale pour qu'elle prenne tout l'espace donné + */ + void resize(sf::Vector2u size); +}; + +#endif diff --git a/include/states/game.hpp b/include/states/game.hpp index 1fdc47a..53bafbb 100644 --- a/include/states/game.hpp +++ b/include/states/game.hpp @@ -1,6 +1,7 @@ #ifndef __SKIZZLE_GAME_HPP__ #define __SKIZZLE_GAME_HPP__ +#include "../gui/modal.hpp" #include "level.hpp" /** @@ -31,6 +32,11 @@ private: float time_left; + sfg::Label::Ptr death_message; + Modal pause_modal; + Modal won_modal; + Modal lost_modal; + /** * Met à jour les objets du jeu pour * qu'ils s'adaptent au nouvel état diff --git a/res/gui.theme b/res/gui.theme index 6bc6a1c..e84599d 100644 --- a/res/gui.theme +++ b/res/gui.theme @@ -19,6 +19,19 @@ Window { BackgroundColor: #FFFFFFff; BorderWidth: 0; + TitleBackgroundColor: #00000000; +} + +Window.modal { + BackgroundColor: #00000000; +} + +Window.modal Window { + Gap: 20; +} + +Window.modal .title { + FontSize: 24; } ScrolledWindow { diff --git a/src/gui/modal.cpp b/src/gui/modal.cpp new file mode 100644 index 0000000..1465fdb --- /dev/null +++ b/src/gui/modal.cpp @@ -0,0 +1,68 @@ +#include "gui/modal.hpp" +#include + +Modal::Modal() { + // création des fenêtres + modal_main_window = sfg::Window::Create(sfg::Window::Style::BACKGROUND); + modal_inner_window = sfg::Window::Create(sfg::Window::Style::BACKGROUND); + + modal_main_window->SetClass("modal"); + + // la fenêtre interne est alignée au centre de la principale + sfg::Alignment::Ptr inner_alignment = sfg::Alignment::Create(); + inner_alignment->SetAlignment(sf::Vector2f(.5f, .5f)); + inner_alignment->SetScale(sf::Vector2f(.0f, .0f)); + + // ajout des éléments dans la fenêtre interne + layout_box = sfg::Box::Create(sfg::Box::Orientation::VERTICAL, 10.f); + buttons_box = sfg::Box::Create(sfg::Box::Orientation::HORIZONTAL, 10.f); + sfg::Alignment::Ptr spacer = sfg::Alignment::Create(); + + title_label = sfg::Label::Create(""); + subtitle_label = sfg::Label::Create(""); + spacer->SetRequisition(sf::Vector2f(1.f, 6.f)); + title_label->SetClass("title"); + + layout_box->PackEnd(title_label); + layout_box->PackEnd(subtitle_label); + layout_box->PackEnd(spacer); + layout_box->PackEnd(buttons_box); + modal_inner_window->Add(layout_box); + + inner_alignment->Add(modal_inner_window); + modal_main_window->Add(inner_alignment); +} + +sfg::Window::Ptr Modal::getWindow() { + return modal_main_window; +} + +sfg::Box::Ptr Modal::getLayoutBox() { + return layout_box; +} + +sfg::Button::Ptr Modal::addButton(sf::String label, std::function callback) { + sfg::Button::Ptr button = sfg::Button::Create(label); + + // liaison du bouton avec la callback, s'il y en a une + if (callback) { + button->GetSignal(sfg::Widget::OnLeftClick).Connect(callback); + } + + buttons_box->PackEnd(button); + return button; +} + +void Modal::setTitle(sf::String label) { + title_label->SetText(label); +} + +void Modal::setSubtitle(sf::String label) { + subtitle_label->SetText(label); +} + +void Modal::resize(sf::Vector2u size) { + modal_main_window->SetAllocation(sf::FloatRect( + 0, 0, size.x, size.y + )); +} diff --git a/src/states/game.cpp b/src/states/game.cpp index 4ccc9ee..d5d88c7 100644 --- a/src/states/game.cpp +++ b/src/states/game.cpp @@ -34,9 +34,35 @@ Game::Game(Manager& manager, bool test) : Level(manager), std::bind(&Game::switchPause, this) ); } + + // création des modales + pause_modal.setTitle("En pause"); + pause_modal.addButton("Reprendre", std::bind(&Game::switchPause, this)); + pause_modal.addButton("Recommencer", std::bind(&Game::restart, this)); + + won_modal.setTitle(L"Vous avez gagné !"); + won_modal.addButton("Sortir", std::bind(&Manager::popState, &getManager())); + won_modal.addButton("Recommencer", std::bind(&Game::restart, this)); + + lost_modal.setTitle(L"Perdu…"); + lost_modal.addButton("Sortir", std::bind(&Manager::popState, &getManager())); + lost_modal.addButton("Recommencer", std::bind(&Game::restart, this)); + + // ajout des modales + pause_modal.getWindow()->Show(false); + won_modal.getWindow()->Show(false); + lost_modal.getWindow()->Show(false); + + getManager().addWidget(pause_modal.getWindow()); + getManager().addWidget(won_modal.getWindow()); + getManager().addWidget(lost_modal.getWindow()); } -Game::~Game() {} +Game::~Game() { + getManager().removeWidget(pause_modal.getWindow()); + getManager().removeWidget(won_modal.getWindow()); + getManager().removeWidget(lost_modal.getWindow()); +} void Game::enable() { Level::enable(); @@ -96,6 +122,29 @@ void Game::frame() { Level::frame(); sf::Time current_time = getManager().getCurrentTime(); + // on affiche les modales correctes selon l'état du jeu + pause_modal.getWindow()->Show(false); + won_modal.getWindow()->Show(false); + lost_modal.getWindow()->Show(false); + + switch (getMode()) { + case Game::Mode::NORMAL: + // rien à faire, le jeu suit son cours + break; + case Game::Mode::PAUSED: + pause_modal.resize(getManager().getWindow().getSize()); + pause_modal.getWindow()->Show(true); + break; + case Game::Mode::WON: + won_modal.resize(getManager().getWindow().getSize()); + won_modal.getWindow()->Show(true); + break; + case Game::Mode::LOST: + lost_modal.resize(getManager().getWindow().getSize()); + lost_modal.getWindow()->Show(true); + break; + } + if (current_time >= next_frame_time) { // si nous sommes en retard ou dans les temps // on replanifie la prochaine frame @@ -105,39 +154,6 @@ void Game::frame() { // si on est en mode normal if (getMode() == Game::Mode::NORMAL) { update(); - } else { - // TODO: pour le débogage affichage du mode actuel - switch (getMode()) { - case Game::Mode::NORMAL: - std::cout << "<< Reprise >>" << std::endl; - break; - case Game::Mode::PAUSED: - std::cout << "<< En pause >>" << std::endl; - break; - case Game::Mode::WON: - std::cout << "<< Gagné ! >>" << std::endl; - break; - case Game::Mode::LOST: - std::cout << "<< Perdu : "; - - switch (getDeathCause()) { - case Game::DeathCause::OUT_OF_BOUNDS: - std::cout << "sortie du cadre"; - break; - case Game::DeathCause::KILLED: - std::cout << "tué par bloc"; - break; - case Game::DeathCause::TIME_OUT: - std::cout << "temps écoulé"; - break; - case Game::DeathCause::NONE: - std::cout << "sans aucune raison"; - break; - } - - std::cout << " ! >>" << std::endl; - break; - } } // on s'assure que la caméra soit centrée sur nos joueurs @@ -301,6 +317,22 @@ Game::Mode Game::getMode() { void Game::setDeathCause(Game::DeathCause set_death_cause) { death_cause = set_death_cause; + + // mise à jour du label informant de la cause de la mort + switch (getDeathCause()) { + case Game::DeathCause::OUT_OF_BOUNDS: + lost_modal.setSubtitle(L"Vous êtes sorti de la zone de jeu"); + break; + case Game::DeathCause::KILLED: + lost_modal.setSubtitle(L"Vous avez touché un bloc tueur"); + break; + case Game::DeathCause::TIME_OUT: + lost_modal.setSubtitle(L"Le temps est écoulé !"); + break; + case Game::DeathCause::NONE: + lost_modal.setSubtitle(""); + break; + } } Game::DeathCause Game::getDeathCause() {