2020-02-19 12:50:09 -05:00
|
|
|
#include "game.h"
|
|
|
|
|
2020-02-21 12:34:28 -05:00
|
|
|
#include <SFML/Graphics/RectangleShape.hpp>
|
2020-02-21 16:55:13 -05:00
|
|
|
#include <SFML/Graphics/Text.hpp>
|
2020-02-21 12:34:28 -05:00
|
|
|
|
2020-02-21 16:55:13 -05:00
|
|
|
constexpr int cell_length = 30;
|
2020-02-21 12:34:28 -05:00
|
|
|
constexpr int window_side = cell_length * side;
|
|
|
|
|
2020-02-19 12:50:09 -05:00
|
|
|
Game::Game()
|
|
|
|
{
|
2020-02-20 13:34:41 -05:00
|
|
|
// Place the player with 10 initial charges onto x: 1, y: 1
|
2020-02-21 16:55:13 -05:00
|
|
|
hero = std::make_unique<Hero>(1, 1, 2);
|
2020-02-20 13:34:41 -05:00
|
|
|
|
|
|
|
// Generate level
|
|
|
|
level = std::make_unique<Level>();
|
|
|
|
|
2020-02-21 10:24:03 -05:00
|
|
|
main_window.create(sf::VideoMode(window_side, window_side), "SFML-Test Application", sf::Style::Default);
|
|
|
|
main_window.setActive();
|
2020-02-25 11:53:57 -05:00
|
|
|
|
|
|
|
current_level = 1;
|
|
|
|
loadLevel(current_level);
|
2020-02-19 12:50:09 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
int Game::run()
|
|
|
|
{
|
|
|
|
// On the game loop
|
|
|
|
while (main_window.isOpen())
|
|
|
|
{
|
|
|
|
sf::Event event;
|
|
|
|
while (main_window.pollEvent(event))
|
|
|
|
{
|
|
|
|
if (event.type == sf::Event::Closed)
|
|
|
|
main_window.close();
|
|
|
|
|
2020-02-20 13:34:41 -05:00
|
|
|
// Handling keyboard activity
|
|
|
|
if (event.type == sf::Event::KeyPressed)
|
|
|
|
{
|
|
|
|
// Move
|
2020-02-21 12:34:28 -05:00
|
|
|
onMoving(event.key.code);
|
2020-02-20 13:34:41 -05:00
|
|
|
}
|
2020-02-19 12:50:09 -05:00
|
|
|
}
|
2020-02-21 10:24:03 -05:00
|
|
|
|
|
|
|
// Draw level
|
2020-02-21 12:34:28 -05:00
|
|
|
renderMap();
|
2020-02-21 10:24:03 -05:00
|
|
|
|
|
|
|
main_window.display();
|
2020-02-19 12:50:09 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
return EXIT_SUCCESS;
|
|
|
|
}
|
2020-02-20 13:34:41 -05:00
|
|
|
|
2020-02-21 10:24:03 -05:00
|
|
|
////////////////////////////////////////////////////
|
|
|
|
|
2020-02-20 13:34:41 -05:00
|
|
|
Direction Game::getDirection(sf::Keyboard::Key &key) const
|
|
|
|
{
|
|
|
|
switch (key)
|
|
|
|
{
|
|
|
|
case sf::Keyboard::A:
|
|
|
|
case sf::Keyboard::Left:
|
2020-02-21 09:13:12 -05:00
|
|
|
case sf::Keyboard::Num4:
|
|
|
|
return Direction::Left;
|
2020-02-20 13:34:41 -05:00
|
|
|
|
|
|
|
case sf::Keyboard::W:
|
|
|
|
case sf::Keyboard::Up:
|
2020-02-21 09:13:12 -05:00
|
|
|
case sf::Keyboard::Num8:
|
|
|
|
return Direction::Up;
|
2020-02-20 13:34:41 -05:00
|
|
|
|
|
|
|
case sf::Keyboard::D:
|
|
|
|
case sf::Keyboard::Right:
|
2020-02-21 09:13:12 -05:00
|
|
|
case sf::Keyboard::Num6:
|
|
|
|
return Direction::Right;
|
2020-02-20 13:34:41 -05:00
|
|
|
|
|
|
|
case sf::Keyboard::S:
|
|
|
|
case sf::Keyboard::Down:
|
2020-02-21 09:13:12 -05:00
|
|
|
case sf::Keyboard::Num2:
|
|
|
|
return Direction::Down;
|
2020-02-20 13:34:41 -05:00
|
|
|
|
|
|
|
default:
|
2020-02-21 09:13:12 -05:00
|
|
|
return Direction::None;
|
2020-02-20 13:34:41 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-02-21 12:34:28 -05:00
|
|
|
void Game::onMoving(sf::Keyboard::Key &key)
|
2020-02-20 13:34:41 -05:00
|
|
|
{
|
|
|
|
// Determine where to move
|
|
|
|
const Direction direction = getDirection(key);
|
|
|
|
|
2020-02-21 12:34:28 -05:00
|
|
|
if (direction == Direction::None)
|
|
|
|
return;
|
2020-02-20 13:34:41 -05:00
|
|
|
|
2020-02-21 12:34:28 -05:00
|
|
|
// Save the initial coordinates
|
|
|
|
coordinate initial_x, initial_y;
|
|
|
|
hero->position(initial_x, initial_y);
|
2020-02-20 13:34:41 -05:00
|
|
|
|
2020-02-21 12:34:28 -05:00
|
|
|
// Try to move hero
|
|
|
|
hero->move(direction);
|
2020-02-21 09:13:12 -05:00
|
|
|
|
2020-02-21 12:34:28 -05:00
|
|
|
// Save the new coordinates after moving
|
|
|
|
coordinate attempt_x, attempt_y;
|
|
|
|
hero->position(attempt_x, attempt_y);
|
2020-02-21 09:13:12 -05:00
|
|
|
|
2020-02-21 12:34:28 -05:00
|
|
|
//////////////////////////
|
2020-02-21 09:13:12 -05:00
|
|
|
|
2020-02-25 11:53:57 -05:00
|
|
|
switch (level->cellOfType(attempt_x, attempt_y))
|
2020-02-21 12:34:28 -05:00
|
|
|
{
|
2020-02-25 11:53:57 -05:00
|
|
|
case CellType::Water:
|
|
|
|
|
2020-02-21 12:34:28 -05:00
|
|
|
// Try to use one charge to place a bridge
|
|
|
|
if (hero->useCharge())
|
|
|
|
level->placeBridge(attempt_x, attempt_y);
|
|
|
|
// If hero doesn't have enough charges, we move Hero back
|
|
|
|
else
|
|
|
|
hero->setPosition(initial_x, initial_y);
|
2020-02-21 09:13:12 -05:00
|
|
|
|
2020-02-25 11:53:57 -05:00
|
|
|
break;
|
|
|
|
|
|
|
|
case CellType::Charge:
|
2020-02-21 12:34:28 -05:00
|
|
|
|
|
|
|
// Hero picks up the charge; remove it from the map
|
|
|
|
hero->refillCharges(1);
|
|
|
|
level->removeCharge(attempt_x, attempt_y);
|
2020-02-25 11:53:57 -05:00
|
|
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
case CellType::Exit:
|
|
|
|
|
|
|
|
// Hero exists the level!
|
|
|
|
loadLevel(++current_level);
|
|
|
|
|
|
|
|
break;
|
2020-02-21 12:34:28 -05:00
|
|
|
}
|
2020-02-25 11:53:57 -05:00
|
|
|
|
2020-02-21 10:24:03 -05:00
|
|
|
}
|
|
|
|
|
2020-02-21 12:34:28 -05:00
|
|
|
void Game::renderMap()
|
2020-02-21 10:24:03 -05:00
|
|
|
{
|
|
|
|
const Map &map = level->mapArray();
|
|
|
|
|
|
|
|
coordinate painter_x = 0, painter_y = 0;
|
2020-02-21 09:13:12 -05:00
|
|
|
|
2020-02-21 12:34:28 -05:00
|
|
|
// Brush for cell sprites
|
|
|
|
sf::RectangleShape rectangle_brush;
|
|
|
|
rectangle_brush.setSize({cell_length, cell_length});
|
|
|
|
rectangle_brush.setFillColor(sf::Color::Blue);
|
|
|
|
rectangle_brush.setOutlineThickness(0);
|
|
|
|
rectangle_brush.setPosition(painter_x, painter_y);
|
|
|
|
|
2020-02-21 16:55:13 -05:00
|
|
|
// Counter for available charges
|
|
|
|
sf::Text text;
|
|
|
|
sf::Font font;
|
|
|
|
font.loadFromFile("font/VeraMono.ttf");
|
|
|
|
text.setFont(font);
|
|
|
|
text.setFillColor(sf::Color::White);
|
|
|
|
text.setCharacterSize(25);
|
|
|
|
text.setPosition(50, 350);
|
|
|
|
text.setString("Available bridge cells: " + std::to_string(hero->charges()));
|
|
|
|
|
2020-02-21 12:34:28 -05:00
|
|
|
// Draw map from 2D array
|
2020-02-21 10:24:03 -05:00
|
|
|
for (const Row &row : map)
|
2020-02-21 09:13:12 -05:00
|
|
|
{
|
2020-02-21 10:24:03 -05:00
|
|
|
for (const CellType &cell : row)
|
|
|
|
{
|
2020-02-21 16:55:13 -05:00
|
|
|
rectangle_brush.setPosition(painter_y, painter_x);
|
2020-02-21 10:24:03 -05:00
|
|
|
switch (cell)
|
2020-02-21 12:34:28 -05:00
|
|
|
{
|
2020-02-21 10:24:03 -05:00
|
|
|
case CellType::Ground:
|
2020-02-21 12:34:28 -05:00
|
|
|
rectangle_brush.setFillColor(sf::Color(165, 42, 42)); // Brown
|
|
|
|
break;
|
2020-02-21 10:24:03 -05:00
|
|
|
case CellType::Charge:
|
2020-02-21 12:34:28 -05:00
|
|
|
rectangle_brush.setFillColor(sf::Color::Green);
|
|
|
|
break;
|
2020-02-21 10:24:03 -05:00
|
|
|
case CellType::Bridge:
|
2020-02-21 12:34:28 -05:00
|
|
|
rectangle_brush.setFillColor(sf::Color::Black);
|
|
|
|
break;
|
2020-02-25 11:53:57 -05:00
|
|
|
case CellType::Exit:
|
|
|
|
rectangle_brush.setFillColor(sf::Color::Red);
|
|
|
|
break;
|
2020-02-21 10:24:03 -05:00
|
|
|
case CellType::Water:
|
|
|
|
default:
|
2020-02-21 12:34:28 -05:00
|
|
|
rectangle_brush.setFillColor(sf::Color::Blue);
|
2020-02-21 10:24:03 -05:00
|
|
|
}
|
|
|
|
|
2020-02-21 12:34:28 -05:00
|
|
|
main_window.draw(rectangle_brush);
|
|
|
|
|
2020-02-21 10:24:03 -05:00
|
|
|
// Move painter to next cell of row
|
|
|
|
painter_x += cell_length;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Move painter to next row of the map
|
|
|
|
painter_x = 0;
|
|
|
|
painter_y += cell_length;
|
2020-02-21 09:13:12 -05:00
|
|
|
}
|
2020-02-21 12:34:28 -05:00
|
|
|
|
|
|
|
// Where is hero
|
|
|
|
coordinate hero_x, hero_y;
|
|
|
|
hero->position(hero_x, hero_y);
|
|
|
|
|
|
|
|
// Place the hero sprite
|
|
|
|
rectangle_brush.setFillColor(sf::Color::White);
|
|
|
|
rectangle_brush.setPosition(hero_x * cell_length, hero_y * cell_length);
|
|
|
|
main_window.draw(rectangle_brush);
|
2020-02-21 16:55:13 -05:00
|
|
|
main_window.draw(text);
|
2020-02-20 13:34:41 -05:00
|
|
|
}
|
2020-02-25 11:53:57 -05:00
|
|
|
|
|
|
|
void Game::loadLevel(int level_index)
|
|
|
|
{
|
|
|
|
Map map;
|
|
|
|
|
|
|
|
// Fill the level with water
|
|
|
|
for (Row &row : map)
|
|
|
|
{
|
|
|
|
for (CellType &cell : row)
|
|
|
|
cell = CellType::Water;
|
|
|
|
}
|
|
|
|
|
|
|
|
switch (level_index)
|
|
|
|
{
|
|
|
|
case 1:
|
|
|
|
// Hardcoding is temporary!
|
|
|
|
hero->setPosition(1, 1);
|
|
|
|
hero->setCharges(2);
|
|
|
|
map[1][1] = CellType::Ground;
|
|
|
|
map[1][2] = CellType::Ground;
|
|
|
|
map[1][3] = CellType::Ground;
|
|
|
|
map[1][4] = CellType::Ground;
|
|
|
|
map[2][2] = CellType::Ground;
|
|
|
|
map[3][2] = CellType::Ground;
|
|
|
|
map[3][3] = CellType::Ground;
|
|
|
|
map[3][3] = CellType::Ground;
|
|
|
|
map[6][3] = CellType::Ground;
|
|
|
|
map[6][4] = CellType::Ground;
|
|
|
|
map[6][5] = CellType::Ground;
|
|
|
|
map[6][6] = CellType::Ground;
|
|
|
|
map[7][6] = CellType::Ground;
|
|
|
|
map[9][6] = CellType::Ground;
|
|
|
|
map[8][7] = CellType::Exit;
|
|
|
|
map[2][3] = CellType::Charge;
|
|
|
|
level->setMap(map);
|
|
|
|
break;
|
|
|
|
case 2:
|
|
|
|
// Hardcoding is temporary!
|
|
|
|
hero->setPosition(5, 5);
|
|
|
|
hero->setCharges(10);
|
|
|
|
map[5][6] = CellType::Ground;
|
|
|
|
map[5][5] = CellType::Ground;
|
|
|
|
map[5][4] = CellType::Ground;
|
|
|
|
map[4][5] = CellType::Ground;
|
|
|
|
map[4][6] = CellType::Ground;
|
|
|
|
map[4][4] = CellType::Ground;
|
|
|
|
map[6][6] = CellType::Ground;
|
|
|
|
map[6][5] = CellType::Ground;
|
|
|
|
map[6][4] = CellType::Ground;
|
|
|
|
map[6][7] = CellType::Ground;
|
|
|
|
map[6][8] = CellType::Ground;
|
|
|
|
map[5][8] = CellType::Ground;
|
|
|
|
map[8][8] = CellType::Ground;
|
|
|
|
map[8][9] = CellType::Ground;
|
|
|
|
map[8][10] = CellType::Exit;
|
|
|
|
map[4][7] = CellType::Charge;
|
|
|
|
level->setMap(map);
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
main_window.close();
|
|
|
|
}
|
|
|
|
}
|