#include "Game.h" #include Game::Game(unsigned int width, unsigned int height, unsigned int cSize) : cellSize(cSize) , cols(width/ cSize) , rows(height/ cSize) , view(sf::FloatRect(0.f, 0.f, static_cast(width), static_cast(height))) , grid(rows, std::vector()) , bufferGrid(rows, std::vector()) { this->window = new sf::RenderWindow(sf::VideoMode(800, 600), "Conway", sf::Style::Titlebar | sf::Style::Close); this->window->setFramerateLimit(60); this->initGrid(); //this->initWindow(); /* put a stable block in the center int cy = rows / 2; int cx = cols / 2; grid[cy][cx].alive = true; grid[cy+1][cx].alive = true; grid[cy][cx+1].alive = true; grid[cy+1][cx+1].alive = true; // Update colors for (int dy = 0; dy < 2; ++dy) for (int dx = 0; dx < 2; ++dx) grid[cy+dy][cx+dx].shape.setFillColor(sf::Color::White); */ } Game::~Game() { delete this->window; } const bool Game::getWindowIsOpen() const { return this->window->isOpen(); } void Game::pollEvent() { while (this->window->pollEvent(this->event)) { switch (this->event.type) { case sf::Event::Closed: { this->window->close(); break; } case sf::Event::KeyPressed: { if (this->event.key.code == sf::Keyboard::Right) newGen(); else if (this->event.key.code == sf::Keyboard::Space) { this->isRunning = !this->isRunning; clock.restart(); } break; } case sf::Event::MouseButtonPressed: { if (!this->isRunning && this->event.mouseButton.button == sf::Mouse::Left) { sf::Vector2f worldPos = window->mapPixelToCoords({ event.mouseButton.x, event.mouseButton.y }); int Wx = static_cast(worldPos.x) / cellSize; int Wy = static_cast(worldPos.y) / cellSize; //inside pollEvent because it needs to be called once to avoid flickering if (Wx >= 0 && Wx < static_cast(cols) && Wy >= 0 && Wy < static_cast(rows)) toggleCell(Wx, Wy); } break; } case sf::Event::MouseWheelScrolled: { //view.zoom(event.mouseWheelScroll.delta > 0 ? 0.9f : 1.1f); //this->window->setView(view); const float factor = event.mouseWheelScroll.delta > 0 ? 0.9f : 1.1f; view.zoom(factor); window->setView(view); break; } case sf::Event::Resized: { updateViewSize(event.size.width, event.size.height); break; } default: break; } } } void Game::toggleCell(int xCell, int yCell) { if (xCell >= 0 && xCell < static_cast(cols) && yCell >= 0 && yCell < static_cast(rows)) { Cell& cell = grid[yCell][xCell]; // & accesses the real cell instead of copy, cell.alive = !cell.alive; //flip! cell.shape.setFillColor(cell.alive ? sf::Color::White : sf::Color::Black); //if alive = true, set color to white else black } } void Game::newGen() { for (unsigned int y = 0; y < this->rows; ++y) { for (unsigned int x = 0; x < this->cols; ++x) { int n = this->countNeighbours(y, x); bool nextStateCheck = this->grid[y][x].alive ? (n == 2 || n == 3) : (n == 3); bufferGrid[y][x].alive = nextStateCheck; bufferGrid[y][x].shape.setFillColor(nextStateCheck ? sf::Color::White : sf::Color::Black); /* store in bufferGrid until loop is done. grid[y][x] is current cell. * if current cell is bool true, set boolean values of (n=2 or 3) to bufferGrid(when alive, chance to alive, or dead) * else if current cell is false, set boolean valuse of n=3 (when dead, chance to revive) */ } } //std::swap(grid, bufferGrid); grid.swap(bufferGrid); } int Game::countNeighbours(int y, int x) const { int count = 0; for (int dy = -1; dy <= 1; ++dy) { for (int dx = -1; dx <= 1; ++dx) //checks 3i*3j field { if (dy == 0 && dx == 0) continue; //dont count self int ny = y + dy; //shifts look to right(when i=1) or left(when i=-1) on y coord int nx = x + dx; //shifts look to right or left on x coord if (ny >= 0 && ny < static_cast(this->rows) && nx >= 0 && nx < static_cast(this->cols)) //checks if in bounds of window(in corners of screen) { count += this->grid[ny][nx].alive; //looks at grid coordinates, bool implicitly convert to int 1 or int 0, then adds } } } return count; } void Game::updateViewSize(unsigned int width, unsigned int height) { view.setSize(static_cast(width), static_cast(height)); window->setView(view); } void Game::Update() { this->pollEvent(); if (this->isRunning && this->clock.getElapsedTime().asSeconds() >= this->updateInterval) { std::cout << "Stepping\n"; this->newGen(); this->clock.restart(); } } void Game::Render() { this->window->setView(view); this->window->clear(sf::Color(0, 0, 0, 255)); //draw for (unsigned int y = 0; y < this->rows; ++y) for (unsigned int x = 0; x < this->cols; ++x) this->window->draw(grid[y][x].shape); this->window->display(); } void Game::initWindow() { //this->videoMode.height = height; //this->videoMode.width = gWidth; this->window = new sf::RenderWindow(this->videoMode, "Conway", sf::Style::Titlebar | sf::Style::Close); this->window->setFramerateLimit(60); } void Game::initGrid() { this->grid.assign(this->rows, std::vector()); this->bufferGrid = this->grid; for (unsigned int y = 0; y < rows; ++y) { grid[y].reserve(cols); //reserve only for optimisation(not needed) bufferGrid[y].reserve(cols); for (unsigned int x = 0; x < cols; ++x) { /*in each row of the grid we are adding the x and y valuse to the Cell*/ float px = x * cellSize; float py = y * cellSize; grid[y].emplace_back(cellSize, px, py);//using emplace_back because it doesnt create a copy of itself bufferGrid[y].emplace_back(cellSize, px, py); } } //this->view = new sf::FloatRect(0.f, 0.f, static_cast(gWidth), static_cast(gHeight)); view.setCenter(static_cast(cols * cellSize) / 2.f, static_cast(rows * cellSize) / 2.f); window->setView(view); } #pragma once #include #include #include #include #include struct Cell { bool alive = false; sf::RectangleShape shape; //initialize Cell(float size, float x, float y) : alive(false) { shape.setSize({ size - 2.f, size - 2.f }); //size -1.f, for clear grid pattern shape.setPosition(x +1.f, y +1.f); shape.setFillColor(sf::Color::Black); shape.setOutlineThickness(1.f); shape.setOutlineColor(sf::Color(255, 255, 0, 128)); } }; class Game { public: Game(unsigned int width = 1600, unsigned int height = 1200, unsigned int cellSize = 25); virtual ~Game(); //Accessors const bool getWindowIsOpen() const; //Functions void Update(); void Render(); private: //grid //unsigned int gWidth = 800; //unsigned int gHeight = 600; const unsigned int cols; const unsigned int rows; const unsigned int cellSize; std::vector> grid; std::vector> bufferGrid; //window sf::RenderWindow* window; //dinamicno alocirati jer se brise sf::VideoMode videoMode; sf::Event event; sf::View view; void initWindow(); void initGrid(); void pollEvent(); //clock sf::Clock clock; sf::Vector2i lastMouse; float updateInterval = 0.1f; //bool bool isRunning = false; bool panning = false; //game functions void toggleCell(int xCell, int yCell); void newGen(); int countNeighbours(int y, int x) const; void updateViewSize(unsigned int width, unsigned int height); };