From 536980561634788b36ef58b45cfbd4930c9dfa02 Mon Sep 17 00:00:00 2001 From: Joscha Date: Thu, 22 Jun 2017 17:43:22 +0000 Subject: [PATCH] Add states and a setup state to Control --- Makefile | 2 +- src/Chromosome.cpp | 11 +++ src/Chromosome.hpp | 2 + src/Control.cpp | 124 +++++++++++++++++++++++++++--- src/Control.hpp | 16 +++- src/Screens.cpp | 188 +++++++++++++++++++++++++++++++++++++++++++++ src/Screens.hpp | 70 +++++++++++++++++ 7 files changed, 400 insertions(+), 13 deletions(-) create mode 100644 src/Screens.cpp create mode 100644 src/Screens.hpp diff --git a/Makefile b/Makefile index 9fe502f..6573f3d 100644 --- a/Makefile +++ b/Makefile @@ -9,7 +9,7 @@ SOURCEFILES = cpp SRCDIR = src TMPDIR = build TARGET = gross -FILES = Genes Chromosome Fitness Generation Control main +FILES = Genes Chromosome Fitness Generation Screens Control main #SOURCES = $(patsubst %,$(SRCDIR)/%.cpp,$(FILES)) OBJECTS = $(patsubst %,$(TMPDIR)/%.o,$(FILES)) diff --git a/src/Chromosome.cpp b/src/Chromosome.cpp index 51038af..68af040 100644 --- a/src/Chromosome.cpp +++ b/src/Chromosome.cpp @@ -16,12 +16,23 @@ void Chromosome::allowGeneType(Gene::GeneType gt, bool allowed) } +void Chromosome::toggleGeneType(Gene::GeneType gt) +{ + Chromosome::allowGeneType(gt, !Chromosome::isGeneTypeAllowed(gt)); +} + bool Chromosome::isGeneTypeAllowed(Gene::GeneType gt) { return Chromosome::allowedGeneTypes.find(gt) != Chromosome::allowedGeneTypes.end(); } +bool Chromosome::isAnyGeneTypeAllowed() +{ + return !Chromosome::allowedGeneTypes.empty(); +} + + Chromosome::Chromosome() { // empty so you can choose between crossover and creating a new chromosome diff --git a/src/Chromosome.hpp b/src/Chromosome.hpp index 3988424..adc8ef1 100644 --- a/src/Chromosome.hpp +++ b/src/Chromosome.hpp @@ -15,7 +15,9 @@ public: static std::minstd_rand* re; static void allowGeneType(Gene::GeneType gt, bool allowed=true); + static void toggleGeneType(Gene::GeneType gt); static bool isGeneTypeAllowed(Gene::GeneType gt); + static bool isAnyGeneTypeAllowed(); Chromosome(); // create empty chromosome Chromosome(const Chromosome& father, const Chromosome& mother); // crossover diff --git a/src/Control.cpp b/src/Control.cpp index e15ab67..0ab3c3f 100644 --- a/src/Control.cpp +++ b/src/Control.cpp @@ -2,18 +2,40 @@ #include +/* + * Setup: + * - current item + * - circles + * - triangles + * - spheres + * - max number limited? + * + * Generations: + * - paused + * - save image + * - display mode + * - saving? + * + * StepThrough: + * - which step am I at? -> enums + */ + Fitness* Control::fitness; Generation* Control::generation; float Control::barMargin = 4; -Control::Control(float winW, float winH, std::string name) +Control::Control(float winW, float winH, std::string name) : + screenSetup(this) { this->window.create(sf::VideoMode(winW, winH), name); - this->targetSprite.setTexture(Control::fitness->target.getTexture()); - this->chromosomeSprite.setTexture(Control::fitness->chromosome.getTexture()); +// this->targetSprite.setTexture(Control::fitness->target.getTexture()); +// this->chromosomeSprite.setTexture(Control::fitness->chromosome.getTexture()); + +// this->currentScreen = &this->screenSetup; +// this->nextScreen = this->currentScreen; this->leftText.setCharacterSize(20); this->leftText.setFillColor(sf::Color::Black); @@ -34,17 +56,52 @@ Control::~Control() void Control::interactive() { + this->currentScreen = nullptr; + this->switchScreen(this->screenSetup); + + std::cout << "Starting interactive loop" << std::endl; + sf::Clock clock; while (this->window.isOpen()) { - sf::Event event; - while (this->window.pollEvent(event)) { + if (this->currentScreen != this->nextScreen) { + if (this->currentScreen != nullptr) this->currentScreen->exit(); + if (this->nextScreen == nullptr) { + std::cout << "Switched to null screen; window closed" << std::endl; + window.close(); + continue; + } + this->currentScreen = this->nextScreen; + this->currentScreen->enter(); } - this->window.clear(); - this->window.draw(this->bar); - this->window.draw(this->rightText); - this->window.draw(this->leftText); + // handle window events + sf::Event event; + while (this->window.pollEvent(event)) { + this->currentScreen->event(event); + } + + // update screen + this->currentScreen->update(clock.restart()); + + // draw screen + this->window.clear(sf::Color::White); + this->window.draw(*this->currentScreen); this->window.display(); } + + std::cout << "Interactive loop stopped; window closed" << std::endl; +} + + +void Control::switchScreen(Screen& newScreen) +{ + std::cout << "Switched screens" << std::endl; + this->nextScreen = &newScreen; +} + + +void Control::close() +{ + this->nextScreen = nullptr; } @@ -53,6 +110,8 @@ void Control::setFont(const sf::Font& font) this->leftText.setFont(font); this->rightText.setFont(font); + this->screenSetup.setFont(font); + this->updateBar(); } @@ -73,6 +132,15 @@ void Control::setRightText(const std::string& text) } +void Control::setText(const std::string& left, const std::string& right) +{ + this->leftText.setString(left); + this->rightText.setString(right); + + this->updateBar(); +} + + void Control::updateBar() { // update bar size and position @@ -122,3 +190,41 @@ void Control::updateBar() ) ); } + + +void Control::drawBar(sf::RenderTarget& target, sf::RenderStates states) const +{ + target.draw(this->bar, states); + target.draw(this->rightText, states); + target.draw(this->leftText, states); +} + + +/* +void Control::modeGenerations() +{ + // handle window events + sf::Event event; + while (this->window.pollEvent(event)) { + // window closed + if (event.type == sf::Event::Closed) { + window.close(); + return; + } + + // key pressed + if (event.type == sf::Event::KeyPressed) { + if (event.key.code == sf::Keyboard::Q) { + window.close(); + return; + } + } + } + + this->window.clear(); + this->window.draw(this->bar); + this->window.draw(this->rightText); + this->window.draw(this->leftText); + this->window.display(); +} +*/ diff --git a/src/Control.hpp b/src/Control.hpp index ce8c241..0ce68e5 100644 --- a/src/Control.hpp +++ b/src/Control.hpp @@ -5,6 +5,7 @@ #include "Chromosome.hpp" #include "Fitness.hpp" #include "Generation.hpp" +#include "Screens.hpp" /* @@ -33,20 +34,29 @@ public: static float barMargin; + sf::RenderWindow window; + + ScreenSetup screenSetup; + Control(float winW, float winH, std::string name); // creates a window ~Control(); void interactive(); + void switchScreen(Screen& newScreen); + void close(); + void setFont(const sf::Font& font); void setLeftText(const std::string& text); void setRightText(const std::string& text); + void setText(const std::string& leftText, const std::string& rightText=""); + + void drawBar(sf::RenderTarget& target, sf::RenderStates states) const; private: - sf::RenderWindow window; - sf::Sprite targetSprite; - sf::Sprite chromosomeSprite; + Screen* currentScreen; + Screen* nextScreen; sf::RectangleShape bar; sf::Text leftText; diff --git a/src/Screens.cpp b/src/Screens.cpp new file mode 100644 index 0000000..d52ec5a --- /dev/null +++ b/src/Screens.cpp @@ -0,0 +1,188 @@ +#include "Screens.hpp" + +#include "Control.hpp" + +#include + +// Screen base class +Screen::Screen(Control* controlptr) +{ + this->control = controlptr; +} + + +Screen::~Screen() +{ +} + + + +// ScreenSetup setup screen +// const sf::Vector2f ScreenSetup::offset(20, 20); +// const float ScreenSetup::distance = 50; +// const int ScreenSetup::items = 3; + + +ScreenSetup::ScreenSetup(Control* controlptr) : + Screen(controlptr), + offset(20, 20), + distance(30), + items(4) +{ + this->selection = 0; + + this->text.setCharacterSize(20); + this->text.setFillColor(sf::Color::Black); + + this->rect.setFillColor(sf::Color::Yellow); +} + + +void ScreenSetup::enter() +{ + std::cout << "ENTERED!" << std::endl; + this->rect.setSize( + sf::Vector2f( + this->control->window.getSize().x, + 30 + ) + ); + + this->selectItem(0); +} + + +void ScreenSetup::event(sf::Event& event) +{ + if (event.type == sf::Event::KeyPressed) { + this->keyPressed(event); + } +} + + +void ScreenSetup::update(sf::Time dt) +{ + if (this->warnTimer > sf::Time::Zero) { + this->warnTimer -= dt; + } +} + + +void ScreenSetup::draw(sf::RenderTarget& target, sf::RenderStates states) const +{ + this->drawMenu(target, states); + + if (this->warnTimer > sf::Time::Zero) { + this->control->drawBar(target, states); + } +} + + +void ScreenSetup::exit() +{ +} + + +void ScreenSetup::setFont(const sf::Font& font) +{ + this->text.setFont(font); +} + + +void ScreenSetup::keyPressed(sf::Event& event) +{ + switch (event.key.code) { + // close window, stop program + case sf::Keyboard::Q: + this->control->close(); + return; + + // move selection up in menu + case sf::Keyboard::Up: + if (event.key.shift) this->selectItem(0); + else this->selectItem(this->selection - 1); + break; + + // move selection down in menu + case sf::Keyboard::Down: + if (event.key.shift) this->selectItem(this->items - 1); + else this->selectItem(this->selection + 1); + break; + + // select current item and perform action + case sf::Keyboard::Return: + this->executeItem(this->selection); + + default: break; + } +} + + +void ScreenSetup::selectItem(int position) +{ + // kinda ugly, just to get the same % behaviour as in python + this->selection = ((position%this->items) + this->items)%this->items; + this->rect.setPosition( + sf::Vector2f( + 0, + this->offset.y + this->distance*this->selection + ) + ); +} + + +void ScreenSetup::executeItem(int position) +{ + switch (position) { + case 0: Chromosome::toggleGeneType(Gene::Circle); break; + case 1: Chromosome::toggleGeneType(Gene::Triangle); break; + case 2: break; // spacing placeholder + case 3: + if (Chromosome::isAnyGeneTypeAllowed()) { +// this->control->switchScreen(Control::screenGenerations); + } else { + this->control->setText("Allow at least one gene type to continue."); + this->warnTimer = sf::seconds(3); + } + break; + } +} + + +void ScreenSetup::drawMenu(sf::RenderTarget& target, sf::RenderStates states) const +{ + target.draw(this->rect); + + sf::Vector2f position = this->offset; + + this->drawMenuItem( + target, states, position, "Circle genes: ", + Chromosome::isGeneTypeAllowed(Gene::Circle)?"x":" " + ); + position.y += this->distance; + + this->drawMenuItem( + target, states, position, "Triangle genes:", + Chromosome::isGeneTypeAllowed(Gene::Triangle)?"x":" " + ); + position.y += 2*this->distance; + + this->drawMenuItem( + target, states, position, "Continue" + ); +} + + +void ScreenSetup::drawMenuItem(sf::RenderTarget& target, sf::RenderStates states, + sf::Vector2f position, std::string name, std::string choice) const +{ + if (choice != "") { + name += " ["; + name += choice; + name += "]"; + } + + this->text.setString(name); + this->text.setPosition(position); + target.draw(text, states); +} diff --git a/src/Screens.hpp b/src/Screens.hpp new file mode 100644 index 0000000..5522bf3 --- /dev/null +++ b/src/Screens.hpp @@ -0,0 +1,70 @@ +#pragma once + +#include +#include + +class Control; + + + +class Screen : public sf::Drawable +{ +public: + Screen(Control* controlptr); + virtual ~Screen(); + + virtual void enter() =0; + virtual void event(sf::Event& event) =0; + virtual void update(sf::Time dt) =0; +// virtual void draw() const =0; + virtual void exit() =0; + +protected: + Control* control; +}; + + + +class ScreenSetup : public Screen +{ +public: + ScreenSetup(Control* controlptr); + + virtual void enter(); + virtual void event(sf::Event& event); + virtual void update(sf::Time dt); + virtual void draw(sf::RenderTarget& target, sf::RenderStates states) const; + virtual void exit(); + + void setFont(const sf::Font& font); + +private: + sf::Vector2f offset; + float distance; + int items; + + int selection; + mutable sf::Text text; + sf::RectangleShape rect; + + sf::Time warnTimer; + + void keyPressed(sf::Event& event); + void selectItem(int position); + void executeItem(int position); + void drawMenu(sf::RenderTarget& target, sf::RenderStates states) const; + void drawMenuItem(sf::RenderTarget& target, sf::RenderStates states, sf::Vector2f position, + std::string name, std::string choice="") const; +}; + + + +class ScreenGenerations : public Screen +{ +}; + + + +class ScreenStepThrough : public Screen +{ +};