diff --git a/build-debug/sfml-test b/build-debug/sfml-test index cd4ee8c..b203a06 100755 Binary files a/build-debug/sfml-test and b/build-debug/sfml-test differ diff --git a/build-release/sfml-test b/build-release/sfml-test index 4ebf91f..6a5ef59 100755 Binary files a/build-release/sfml-test and b/build-release/sfml-test differ diff --git a/src/game.cpp b/src/game.cpp index 72ee84b..6412f9b 100644 --- a/src/game.cpp +++ b/src/game.cpp @@ -1,15 +1,5 @@ #include "game.h" -#include -#include -#include - -constexpr int cell_width = 60; -constexpr int cell_height = 35; -constexpr int cell_deviation = 25; - -constexpr int window_side = cell_width * 4; - Game::Game() { // Place the player with 10 initial charges onto x: 1, y: 1 @@ -18,12 +8,21 @@ Game::Game() // Generate level level = std::make_unique(); - main_window.create(sf::VideoMode(window_side * 3, window_side * 3), "SFML-Test Application", sf::Style::Default); + // Prepare level renderer + renderer = std::make_unique(); + + main_window.create(sf::VideoMode(renderer->windowSize() * 5, renderer->windowSize() * 5), "SFML-Test Application", sf::Style::Default); main_window.setActive(); + main_window.setFramerateLimit(60); + + current_level = 1; } int Game::run() { + // Initial level rendering + renderer->render(level, hero, main_window); + // On the game loop while (main_window.isOpen()) { @@ -38,12 +37,12 @@ int Game::run() { // Move onMoving(event.key.code); + + // Probably something changed! Re-render + renderer->render(level, hero, main_window); } } - // Draw level - renderMap(); - main_window.display(); } @@ -104,95 +103,3 @@ void Game::onMoving(sf::Keyboard::Key &key) if (!level->getCellAt(attempt_row, attempt_col)->onMovingTo(hero, level)) hero->setPosition(initial_row, initial_col); } - -void Game::renderMap() -{ - float painter_x = 60, painter_y = 60; - float horizontal_shift = 0, vertical_shift = 0; - - // Brush for cell sprites - sf::ConvexShape convex_brush; - convex_brush.setPointCount(4); - convex_brush.setPoint(0, sf::Vector2f(cell_deviation, 0.f)); - convex_brush.setPoint(1, sf::Vector2f(cell_deviation + cell_width, 0.f)); - convex_brush.setPoint(2, sf::Vector2f(cell_width, cell_height)); - convex_brush.setPoint(3, sf::Vector2f(0.f, cell_height)); - convex_brush.setFillColor(palette::Blue); - convex_brush.setOutlineThickness(0); - convex_brush.setPosition(painter_x, painter_y); - - // Counter for available charges - sf::Text text; - sf::Font font; - font.loadFromFile("font/VeraMono.ttf"); - text.setFont(font); - text.setFillColor(palette::White); - text.setCharacterSize(25); - text.setPosition(50, 350); - text.setString("Available bridge cells: " + std::to_string(hero->charges())); - - // Where is hero - coordinate hero_row, hero_col; - hero->position(hero_row, hero_col); - - // Draw map from 2D array - for (coordinate x = 0; x < level->cols(); ++x) - { - horizontal_shift = static_cast(level->cols()) * cell_deviation; - for (coordinate y = 0; y < level->rows(); ++y) - { - vertical_shift = static_cast(level->getCellAt(y, x)->heightShift()); - - // If cell has any height value, we should draw walls for it - if (vertical_shift > 0) - { - // Brush for vertical walls - sf::ConvexShape convex_wall_brush; - convex_wall_brush.setPointCount(6); - convex_wall_brush.setPoint(0, sf::Vector2f(cell_deviation + cell_width, -vertical_shift)); - convex_wall_brush.setPoint(1, sf::Vector2f(cell_deviation + cell_width, 0.f)); - convex_wall_brush.setPoint(2, sf::Vector2f(cell_width, cell_height)); - convex_wall_brush.setPoint(3, sf::Vector2f(0.f, cell_height)); - convex_wall_brush.setPoint(4, sf::Vector2f(0.f, cell_height - vertical_shift)); - convex_wall_brush.setPoint(5, sf::Vector2f(cell_width, cell_height)); - convex_wall_brush.setOutlineThickness(0); - - sf::Color wall_color(sf::Uint8(level->getCellAt(y, x)->color().r - 40), - sf::Uint8(level->getCellAt(y, x)->color().g - 40), - sf::Uint8(level->getCellAt(y, x)->color().b - 40)); - convex_wall_brush.setFillColor(wall_color); - - convex_wall_brush.setPosition(painter_x + horizontal_shift, painter_y); - - main_window.draw(convex_wall_brush); - } - - // Draw the top surface of the cell itself - - float final_x = painter_x + horizontal_shift; - float final_y = painter_y - vertical_shift; - - convex_brush.setPosition(final_x, final_y); - convex_brush.setFillColor(level->getCellAt(y, x)->color()); - - main_window.draw(convex_brush); - - if (hero_row == y && hero_col == x) - { - // Draw the hero sprite - convex_brush.setFillColor(palette::White); - main_window.draw(convex_brush); - } - - // Move painter to next cell of current column - painter_y += cell_height; - horizontal_shift -= cell_deviation; - } - - // Move painter to next column - painter_y = 60; - painter_x += cell_width; - } - - main_window.draw(text); -} diff --git a/src/game.h b/src/game.h index 778c6fa..a1259a1 100644 --- a/src/game.h +++ b/src/game.h @@ -3,12 +3,11 @@ #include -#include #include -#include #include "hero.h" #include "level.h" +#include "renderer.h" /// The main class where all the process happens class Game @@ -17,6 +16,7 @@ private: // Game entities HeroPtr hero; LevelPtr level; + std::unique_ptr renderer; int current_level; @@ -29,9 +29,6 @@ private: /// Move player by pressed key void onMoving(sf::Keyboard::Key &key); - /// Render game state - void renderMap(); - /// Prepare map and hero for a game level //void loadLevel(int level_index = 1); diff --git a/src/renderer.cpp b/src/renderer.cpp new file mode 100644 index 0000000..a6b3f1b --- /dev/null +++ b/src/renderer.cpp @@ -0,0 +1,130 @@ +#include "renderer.h" + +#include "level.h" +#include "hero.h" + +constexpr unsigned int DEFAULT_CELL_WIDTH = 60; +constexpr unsigned int DEFAULT_CELL_HEIGHT = 35; +constexpr unsigned int DEFAULT_CELL_DEVIATION = 25; + +constexpr unsigned int DEFAULT_WINDOW_SIDE = DEFAULT_CELL_WIDTH * 4; + +Renderer::Renderer() : + cell_width(DEFAULT_CELL_WIDTH), + cell_height(DEFAULT_CELL_HEIGHT), + cell_deviation(DEFAULT_CELL_DEVIATION), + window_size(DEFAULT_WINDOW_SIDE), + init_painter_x(60), + init_painter_y(60), + vertical_shift(0), + horizontal_shift(0) +{ + font.loadFromFile("font/VeraMono.ttf"); + text_charges.setFont(font); + text_charges.setFillColor(palette::White); + text_charges.setCharacterSize(25); + + brush_background.setFillColor(palette::Black); + brush_background.setPosition(0.f, 0.f); + + brush_cell.setPointCount(4); + brush_cell.setPoint(0, sf::Vector2f(cell_deviation, 0.f)); + brush_cell.setPoint(1, sf::Vector2f(cell_deviation + cell_width, 0.f)); + brush_cell.setPoint(2, sf::Vector2f(cell_width, cell_height)); + brush_cell.setPoint(3, sf::Vector2f(0.f, cell_height)); + brush_cell.setFillColor(palette::Blue); + brush_cell.setOutlineThickness(0); + + brush_wall.setPointCount(6); // Points 0 and 4 should be calculated each iteration of rendering + brush_wall.setPoint(1, sf::Vector2f(cell_deviation + cell_width, 0.f)); + brush_wall.setPoint(2, sf::Vector2f(cell_width, cell_height)); + brush_wall.setPoint(3, sf::Vector2f(0.f, cell_height)); + brush_wall.setPoint(5, sf::Vector2f(cell_width, cell_height)); + brush_wall.setOutlineThickness(0); +} + +bool Renderer::drawCell(const CellPtr &cell, sf::RenderWindow &main_window) +{ + vertical_shift = static_cast(cell->heightShift()); + + // If cell has any height value, we should draw walls for it + if (vertical_shift > 0) + { + brush_wall.setPoint(0, sf::Vector2f(cell_deviation + cell_width, -vertical_shift)); + brush_wall.setPoint(4, sf::Vector2f(0.f, cell_height - vertical_shift)); + + sf::Color wall_color(sf::Uint8(cell->color().r - 40), sf::Uint8(cell->color().g - 40), sf::Uint8(cell->color().b - 40)); + brush_wall.setFillColor(wall_color); + brush_wall.setPosition(painter_x + horizontal_shift, painter_y); + + main_window.draw(brush_wall); + } + + // Draw the top surface of the cell itself + float final_x = painter_x + horizontal_shift; + float final_y = painter_y - vertical_shift; + + brush_cell.setPosition(final_x, final_y); + brush_cell.setFillColor(cell->color()); + + main_window.draw(brush_cell); + + return true; +} + +bool Renderer::render(const LevelPtr &level, const HeroPtr &hero, sf::RenderWindow &main_window) +{ + if (!hero || !level) + return false; + + painter_x = init_painter_x; + painter_y = init_painter_y; + horizontal_shift = 0; + vertical_shift = 0; + + brush_background.setSize({static_cast(main_window.getSize().x), static_cast(main_window.getSize().y)}); + main_window.draw(brush_background); + + brush_cell.setPosition(painter_x, painter_y); + + // Where is hero + coordinate hero_row, hero_col; + hero->position(hero_row, hero_col); + + // Draw map from 2D array + for (coordinate c = 0; c < level->cols(); ++c) + { + horizontal_shift = static_cast(level->cols()) * cell_deviation; + + for (coordinate r = 0; r < level->rows(); ++r) + { + drawCell(level->getCellAt(r, c), main_window); + + if (hero_row == r && hero_col == c) + { + // Draw the hero sprite + brush_cell.setFillColor(palette::White); + main_window.draw(brush_cell); + } + + // Move painter to next cell of current column + painter_y += cell_height; + horizontal_shift -= cell_deviation; + } + + // Move painter to next column + painter_y = init_painter_y; + painter_x += cell_width; + } + + text_charges.setPosition(50, 350); + text_charges.setString("Available charges left: " + std::to_string(hero->charges())); + main_window.draw(text_charges); + + return true; +} + +unsigned int Renderer::windowSize() const +{ + return window_size; +} diff --git a/src/renderer.h b/src/renderer.h new file mode 100644 index 0000000..a53726a --- /dev/null +++ b/src/renderer.h @@ -0,0 +1,43 @@ +#ifndef RENDERER_H +#define RENDERER_H + +#include +#include +#include +#include +#include + +class Level; +class Cell; +class Hero; + +/// Represents functionality to draw game level onto window +class Renderer +{ +private: + float cell_width, cell_height, cell_deviation; + unsigned int window_size; + + float init_painter_x, init_painter_y; + float painter_x, painter_y; + + float vertical_shift, horizontal_shift; + + sf::Text text_charges; + sf::Font font; + + sf::RectangleShape brush_background; + sf::ConvexShape brush_cell; + sf::ConvexShape brush_wall; + + bool drawCell(const std::unique_ptr &cell, sf::RenderWindow &main_window); + +public: + explicit Renderer(); + + bool render(const std::unique_ptr &level, const std::unique_ptr &hero, sf::RenderWindow &main_window); + + unsigned int windowSize() const; +}; + +#endif // RENDERER_H diff --git a/src/sfml-test.pro b/src/sfml-test.pro index 41f77ac..96655a6 100644 --- a/src/sfml-test.pro +++ b/src/sfml-test.pro @@ -11,14 +11,16 @@ SOURCES += \ game.cpp \ hero.cpp \ level.cpp \ - main.cpp + main.cpp \ + renderer.cpp HEADERS += \ cell.h \ entity.h \ game.h \ hero.h \ - level.h + level.h \ + renderer.h # Only to highlight syntax when I am on Windows win32:INCLUDEPATH += d:\SFML-2.5.1\include