diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 02db7fb..04900db 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -5,6 +5,7 @@ add_executable(snakeplusplus ./gamestate.cpp ./snake.cpp ./playerinterface.cpp + ./common.cpp ) target_include_directories(snakeplusplus PUBLIC ${CMAKE_CURRENT_LIST_DIR}) diff --git a/src/common.cpp b/src/common.cpp new file mode 100755 index 0000000..62088ee --- /dev/null +++ b/src/common.cpp @@ -0,0 +1,21 @@ +// common.cpp +#include +#include "common.hpp" + +namespace snakeplusplus +{ + std::default_random_engine generator; + void InitializeGenerator(void) + { + generator.seed(std::random_device{}()); + } + + // Returns a newly generated number + int GenerateRandomNumber(int generationLimit) + { + int generatedNumber; + std::uniform_int_distribution<> distribution(0, generationLimit - 1); + generatedNumber = distribution(snakeplusplus::generator); + return generatedNumber; + } +} diff --git a/src/common.hpp b/src/common.hpp index ef440c9..82f60e2 100755 --- a/src/common.hpp +++ b/src/common.hpp @@ -1,13 +1,20 @@ #ifndef COMMON_HPP #define COMMON_HPP -enum PlayerDirection +namespace snakeplusplus { - kNone = 0, - kLeft = 1, - kUp = 2, - kDown = 3, - kRight = 4 -}; + void InitializeGenerator(void); + int GenerateRandomNumber(int generationLimit); + + enum PlayerDirection + { + kNone = 0, + kLeft = 1, + kUp = 2, + kDown = 3, + kRight = 4 + }; + +} #endif diff --git a/src/gamestate.cpp b/src/gamestate.cpp index 51a5470..67941f4 100755 --- a/src/gamestate.cpp +++ b/src/gamestate.cpp @@ -1,9 +1,7 @@ // GameState.cpp -#include -#include #include -#include #include +#include #include "common.hpp" #include "playerinterface.hpp" #include "gamestate.hpp" @@ -12,27 +10,32 @@ namespace snakeplusplus { GameEngine::GameEngine() { + snakeplusplus::InitializeGenerator(); return; } - void GameEngine::StartGame() + void GameEngine::Start() { - //ApplySettings(); PrepareGameBoard(); graphics.StartGameWindow(); - GameLoop(); + Loop(); return; } - void GameEngine::GameLoop(void) + void GameEngine::Reset() + { + graphics.CheckContinue(); + player.Reset(); + PrepareGameBoard(); + isGameOver = 0; + return; + } + + void GameEngine::Loop(void) { while (graphics.IsOpen()) { - if (isGameOver) - { - graphics.CheckContinue(); - isGameOver = 0; - } + if (isGameOver) {Reset();} UpdatePlayerSpeed(); PlaceNewSnakePart(MovePlayer()); RegenerateFood(); @@ -56,11 +59,12 @@ namespace snakeplusplus void GameEngine::PlaceNewSnakePart(sf::Vector2f location) { + if (!player.speed.x && !player.speed.y) { return; } try { char* locationState; locationState = &gameBoard.at(location.y).at(location.x); - if (*locationState == 'O' && player.body.size() > 1) + if (*locationState == 'O' && (player.body.size() > 1)) isGameOver = true; // Game should end (Snake touching snake) *locationState = 'O'; player.body.push(locationState); @@ -69,8 +73,8 @@ namespace snakeplusplus player.Pop(); } catch (const std::out_of_range& error) { isGameOver = true; // Snake ran into edge - exit(0); } + return; } // Generates new food until not colliding with player @@ -78,7 +82,6 @@ namespace snakeplusplus { sf::Vector2f newLocation = playerFood.location; bool isUpdated = false; - // Keep making new food until generating a valid spot while (gameBoard.at(newLocation.y).at(newLocation.x) == 'O') { isUpdated = true; @@ -95,22 +98,26 @@ namespace snakeplusplus gameBoard.clear(); sf::Vector2f boardDimensions = GetGameBoundaries(); gameBoard.resize(boardDimensions.y, std::vector (boardDimensions.x, ' ')); - player.headLocation.x = 4; - player.headLocation.y = 5; - char* locationState = &gameBoard.at(player.headLocation.y).at(player.headLocation.x); - player.body.push(locationState); - *player.body.front() = 'O'; - playerFood.location.x = 2; - playerFood.location.y = 2; - playerFood.food = &gameBoard.at(2).at(2); - *playerFood.food = 'X'; + // Snake setup + { + player.headLocation.x = GenerateRandomNumber(boardDimensions.x); + player.headLocation.y = GenerateRandomNumber(boardDimensions.y); + char* locationState = &gameBoard.at(player.headLocation.y).at(player.headLocation.x); + player.body.push(locationState); + *locationState = 'O'; + } + // Food setup + { + playerFood.GenerateNewFood(boardDimensions); + sf::Vector2f newLocation = playerFood.location; + gameBoard.at(newLocation.y).at(newLocation.x) = 'X'; + } return; } void GameEngine::UpdatePlayerSpeed(void) { - PlayerDirection input = controls.GetPlayerInput(); - switch (input) { + switch (GetPlayerInput()) { case kUp: player.speed.x = 0; player.speed.y = -1; @@ -130,5 +137,6 @@ namespace snakeplusplus default: break; } + return; } } diff --git a/src/gamestate.hpp b/src/gamestate.hpp index 238aa4b..29763a4 100755 --- a/src/gamestate.hpp +++ b/src/gamestate.hpp @@ -2,7 +2,6 @@ #ifndef GAMESTATE_HPP #define GAMESTATE_HPP -#include #include #include "snake.hpp" #include "playerinterface.hpp" @@ -13,18 +12,17 @@ namespace snakeplusplus { public: GameEngine(); - void StartGame(void); + void Start(void); + void Reset(void); sf::Vector2f GetGameBoundaries(void); private: std::vector< std::vector > gameBoard; - PlayerInput controls; PlayerOutput graphics; Snake player; Food playerFood; - bool useSFML = 1; bool isGameOver = 0; void DisplayEndScreen(void); - void GameLoop(void); + void Loop(void); sf::Vector2f MovePlayer(void); void PlaceNewSnakePart(sf::Vector2f location); void RegenerateFood(void); diff --git a/src/main.cpp b/src/main.cpp index 854534f..2d529fb 100755 --- a/src/main.cpp +++ b/src/main.cpp @@ -3,5 +3,6 @@ int main(void) { snakeplusplus::GameEngine game; - game.StartGame(); + game.Start(); + return 0; } diff --git a/src/playerinterface.cpp b/src/playerinterface.cpp index 8e297d4..d63706c 100755 --- a/src/playerinterface.cpp +++ b/src/playerinterface.cpp @@ -1,26 +1,24 @@ #include "playerinterface.hpp" #include -#include -#include +#include namespace snakeplusplus { - PlayerInput::PlayerInput(void) + PlayerDirection GetPlayerInput(void) { - lastPlayerInput = kNone; - } - - PlayerDirection PlayerInput::GetPlayerInput(void) - { - if (sf::Keyboard::isKeyPressed(sf::Keyboard::Left)) - lastPlayerInput = kLeft; - if (sf::Keyboard::isKeyPressed(sf::Keyboard::Up)) - lastPlayerInput = kUp; - if (sf::Keyboard::isKeyPressed(sf::Keyboard::Down)) - lastPlayerInput = kDown; - if (sf::Keyboard::isKeyPressed(sf::Keyboard::Right)) - lastPlayerInput = kRight; - return lastPlayerInput; + if (sf::Keyboard::isKeyPressed(sf::Keyboard::Left) + || sf::Keyboard::isKeyPressed(sf::Keyboard::A)) + return kLeft; + if (sf::Keyboard::isKeyPressed(sf::Keyboard::Up) + || sf::Keyboard::isKeyPressed(sf::Keyboard::W)) + return kUp; + if (sf::Keyboard::isKeyPressed(sf::Keyboard::Down) + || sf::Keyboard::isKeyPressed(sf::Keyboard::S)) + return kDown; + if (sf::Keyboard::isKeyPressed(sf::Keyboard::Right) + || sf::Keyboard::isKeyPressed(sf::Keyboard::D)) + return kRight; + return kNone; } bool PlayerOutput::IsOpen(void) @@ -47,8 +45,8 @@ namespace snakeplusplus while (true) { gameWindow.pollEvent(event); - if ((event.type == sf::Event::Closed) || - (sf::Keyboard::isKeyPressed(sf::Keyboard::Escape))) + if ((event.type == sf::Event::Closed) + || (sf::Keyboard::isKeyPressed(sf::Keyboard::Escape))) { gameWindow.close(); return; @@ -66,7 +64,7 @@ namespace snakeplusplus textPosition.y = textPosition.y / 2; sf::Font font; font.loadFromFile("Arial.ttf"); - sf::Text gameOverText("Game Over", font); + sf::Text gameOverText("Game Over\nPress 'Enter' to play again", font); gameOverText.setPosition(textPosition); gameWindow.draw(gameOverText); gameWindow.display(); @@ -76,25 +74,22 @@ namespace snakeplusplus void PlayerOutput::DisplayGameState(std::vector< std::vector >& gameBoard) { CheckWindowEvents(); - sf::Vector2f location; char* letterOnBoard; for (float y = 0; y < gameBoundaries.y; y++) { for (float x = 0; x < gameBoundaries.x; x++) { - location.x = x; - location.y = y; - letterOnBoard = &gameBoard.at(location.y).at(location.x); + letterOnBoard = &gameBoard.at(y).at(x); switch (*letterOnBoard) { case 'O': - DrawSnake(location); + DrawSnake(sf::Vector2f(x, y)); break; case 'X': - DrawFood(location); + DrawFood(sf::Vector2f(x,y)); break; default: - DrawEmpty(location); + DrawEmpty(sf::Vector2f(x,y)); break; } } @@ -116,8 +111,8 @@ namespace snakeplusplus sf::Event event; while (gameWindow.pollEvent(event)) { - if ((event.type == sf::Event::Closed) || - (sf::Keyboard::isKeyPressed(sf::Keyboard::Escape))) + if ((event.type == sf::Event::Closed) + || (sf::Keyboard::isKeyPressed(sf::Keyboard::Escape))) gameWindow.close(); } } diff --git a/src/playerinterface.hpp b/src/playerinterface.hpp index f4267ca..26e12f5 100755 --- a/src/playerinterface.hpp +++ b/src/playerinterface.hpp @@ -8,14 +8,7 @@ const int kGridSize = 25; namespace snakeplusplus { - class PlayerInput - { - public: - PlayerInput(void); - PlayerDirection GetPlayerInput(void); - private: - PlayerDirection lastPlayerInput; - }; + PlayerDirection GetPlayerInput(void); class PlayerOutput { diff --git a/src/snake.cpp b/src/snake.cpp index 8de60c0..4dfc7f4 100755 --- a/src/snake.cpp +++ b/src/snake.cpp @@ -1,9 +1,7 @@ // Snake.cpp -#include -#include #include -#include #include +#include "common.hpp" #include "snake.hpp" namespace snakeplusplus @@ -12,26 +10,22 @@ namespace snakeplusplus { *(body.front()) = ' '; body.pop(); + return; } - Food::Food(void) + void Snake::Reset(void) { - generator.seed(std::random_device{}()); + while (!body.empty()) Pop(); + speed.x = 0; + speed.y = 0; + return; } // Returns a new food object for the snakeFood void Food::GenerateNewFood(sf::Vector2f boundaries) { - location.x = GenerateRandomNumber(boundaries.x); - location.y = GenerateRandomNumber(boundaries.y); - } - - // Returns a newly generated number - int Food::GenerateRandomNumber(int generationLimit) - { - int generatedNumber; - std::uniform_int_distribution<> distribution(0, generationLimit - 1); - generatedNumber = distribution(generator); - return generatedNumber; + location.x = snakeplusplus::GenerateRandomNumber(boundaries.x); + location.y = snakeplusplus::GenerateRandomNumber(boundaries.y); + return; } } diff --git a/src/snake.hpp b/src/snake.hpp index 3ed81ea..80cec53 100755 --- a/src/snake.hpp +++ b/src/snake.hpp @@ -3,10 +3,7 @@ #define SNAKE_HPP #include -#include #include -#include -#include namespace snakeplusplus { @@ -17,18 +14,15 @@ namespace snakeplusplus sf::Vector2f speed; std::queue body; void Pop(void); + void Reset(void); }; struct Food { public: - Food(void); sf::Vector2f location; char* food; void GenerateNewFood(sf::Vector2f boundaries); - private: - std::default_random_engine generator; - int GenerateRandomNumber(int generationLimit); }; }