From de189301d4f4f89590f7647e8b72dfd25245cee4 Mon Sep 17 00:00:00 2001 From: TriantaTV Date: Sun, 12 Mar 2023 08:50:50 -0500 Subject: [PATCH 1/2] Cleaned up code for readability --- Makefile | 4 ++- include/GameState.h | 20 ++++++++++---- include/Snake.h | 10 ++++--- include/SnakeFood.h | 14 +++++++--- src/GameState.cpp | 66 +++++++++++++++++++++++++++++++-------------- src/Snake.cpp | 63 ++++++++++++++++++++++--------------------- src/SnakeFood.cpp | 30 ++++++++++++--------- src/main.cpp | 4 +-- 8 files changed, 133 insertions(+), 78 deletions(-) diff --git a/Makefile b/Makefile index 75c1ce8..7ae3f64 100644 --- a/Makefile +++ b/Makefile @@ -2,7 +2,9 @@ INC := -I include STD := -std=c++11 SFML := -lsfml-graphics -lsfml-window -lsfml-system -all: dirs compile link +all: compile link + +fresh: dirs compile link dirs: mkdir bin build diff --git a/include/GameState.h b/include/GameState.h index f5ccb13..5b0d616 100644 --- a/include/GameState.h +++ b/include/GameState.h @@ -1,22 +1,32 @@ // GameState.h #ifndef GAMESTATE_H #define GAMESTATE_H + #include +#include "Snake.h" class GameState { -private: public: - sf::VideoMode gameVideoMode; - sf::RenderWindow gameWindow; GameState(); GameState(int newHorizontal, int newVertical); - void startNewGame(); + void StartGame(void); + sf::Vector2f GetGameBoundaries(void); /* gameGridHorizontal = (videoSizeHorizontal // 25) * 25; gameGridVertical = (videoSizeVertical // 25) * 25; */ - // sf::Vector2f GetGameBoundaries(); +protected: + ; +private: + sf::RenderWindow gameWindow; + sf::VideoMode gameVideoSettings; + SnakeFood playerFood; + Snake player; + sf::Time delay; + void RegenerateFood(void); + void RunGameLoop(void); + void RenderWindow(void); }; #endif diff --git a/include/Snake.h b/include/Snake.h index aa873b3..235a0f4 100644 --- a/include/Snake.h +++ b/include/Snake.h @@ -11,9 +11,6 @@ bool GlobalCollision(sf::Vector2f object1Position, sf::Vector2f object2Position) class Snake { -private: - std::deque snakeBody; - int snakeDirection = 0; public: Snake(); Snake(sf::Vector2f head); @@ -21,10 +18,15 @@ public: sf::RectangleShape GetSnakeHead(); void DisplaySnake(sf::RenderWindow& window); void MoveSnake(SnakeFood& playerFood, sf::VideoMode gameVideoMode); - void SnakeFoodCollision(SnakeFood& snakeFood, sf::VideoMode gameVideoMode); void CheckDirection(); bool CheckBoundaries(); bool IsSelfCollision(sf::RectangleShape testRectangle); + bool IsTouchingObject(sf::RectangleShape object); +protected: + ; +private: + std::deque snakeBody; + int snakeDirection = 0; }; diff --git a/include/SnakeFood.h b/include/SnakeFood.h index 67f603a..824efb9 100644 --- a/include/SnakeFood.h +++ b/include/SnakeFood.h @@ -1,18 +1,24 @@ // SnakeFood.h #ifndef SNAKEFOOD_H #define SNAKEFOOD_H + #include #include +extern const int kGridSize; + class SnakeFood { -private: public: - sf::RectangleShape snakeFoodObject; - std::default_random_engine generator; SnakeFood(); SnakeFood(sf::Vector2f snakeFoodSize); - void GenerateNewLocation(int horizontalLocation, int verticalLocation); + void GenerateNewFood(sf::Vector2f windowSize); + sf::RectangleShape GetFoodObject(void); +protected: + ; +private: + sf::RectangleShape snakeFoodObject; + std::default_random_engine generator; int GenerateRandomNumber(int generationLimit); }; diff --git a/src/GameState.cpp b/src/GameState.cpp index f9a89a1..300ed95 100644 --- a/src/GameState.cpp +++ b/src/GameState.cpp @@ -6,42 +6,68 @@ GameState::GameState() { - sf::VideoMode tempVideoMode(1024, 725); - gameVideoMode = tempVideoMode; - sf::RenderWindow gameWindow(gameVideoMode, "SnakePlusPlus"); + delay = sf::milliseconds(100); + gameVideoSettings = sf::VideoMode(1024, 725); + gameWindow.create(gameVideoSettings, "SnakePlusPlus"); return; } -GameState::GameState(int newHorizontal, int newVertical) +GameState::GameState(int maxHorizontal, int maxVertical) { - sf::VideoMode tempVideoMode(newHorizontal, newVertical); - gameVideoMode = tempVideoMode; - sf::RenderWindow tempWindow(gameVideoMode, "SnakePlusPlus"); + delay = sf::milliseconds(100); + gameVideoSettings = sf::VideoMode(maxHorizontal, maxVertical); + gameWindow.create(gameVideoSettings, "SnakePlusPlus"); return; } -void GameState::startNewGame() +void GameState::StartGame() { - gameWindow.create(gameVideoMode, "SnakePlusPlus"); - sf::Time delay = sf::milliseconds(100); - int snakeDirection = 0; - Snake player(sf::Vector2f(25,25)); - SnakeFood playerFood(sf::Vector2f(25,25)); + gameWindow.create(gameVideoSettings, "SnakePlusPlus"); + Snake player(sf::Vector2f(kGridSize,kGridSize)); + SnakeFood playerFood(sf::Vector2f(kGridSize,kGridSize)); + RunGameLoop(); +} +sf::Vector2f GameState::GetGameBoundaries(void) +{ + sf::Vector2f boundaries; + boundaries.x = gameVideoSettings.width; + boundaries.y = gameVideoSettings.height; + return boundaries; +} + +// Generates new food until not colliding with player +void GameState::RegenerateFood(void) +{ + // Keep making new food until generating a valid spot + while (player.IsTouchingObject(playerFood.GetFoodObject())) + playerFood.GenerateNewFood(GetGameBoundaries()); + return; +} + +void GameState::RunGameLoop(void) +{ + sf::Event event; while (gameWindow.isOpen()) { - 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(); } player.CheckDirection(); - player.MoveSnake(playerFood, gameVideoMode); - gameWindow.clear(); - player.DisplaySnake(gameWindow); - gameWindow.draw(playerFood.snakeFoodObject); - gameWindow.display(); + player.MoveSnake(playerFood, gameVideoSettings); + RegenerateFood(); + RenderWindow(); sf::sleep(delay); } } + +void GameState::RenderWindow(void) +{ + gameWindow.clear(); + player.DisplaySnake(gameWindow); + gameWindow.draw(playerFood.GetFoodObject()); + gameWindow.display(); +} diff --git a/src/Snake.cpp b/src/Snake.cpp index d1216cf..f752c23 100644 --- a/src/Snake.cpp +++ b/src/Snake.cpp @@ -5,19 +5,37 @@ #include "Snake.h" #include "SnakeFood.h" +// General constructor for snake class +Snake::Snake() +{ + sf::RectangleShape newBodyPart(sf::Vector2f(kGridSize, kGridSize)); + newBodyPart.setFillColor(sf::Color::Green); + snakeBody.push_back(newBodyPart); + return; +} + +// Constructor for snake with position +Snake::Snake(sf::Vector2f headSize) +{ + sf::RectangleShape newBodyPart(headSize); + newBodyPart.setFillColor(sf::Color::Green); + snakeBody.push_back(newBodyPart); + return; +} + // Get a new coordinate position based on snake direction sf::Vector2f CalculateNewPosition(int direction, sf::Vector2f position) { if (direction == 0) return position; if (direction == 1) - position.x -= 25; + position.x -= kGridSize; if (direction == 2) - position.y -= 25; + position.y -= kGridSize; if (direction == 3) - position.y += 25; + position.y += kGridSize; if (direction == 4) - position.x += 25; + position.x += kGridSize; return position; } @@ -70,7 +88,7 @@ void Snake::MoveSnake(SnakeFood& snakeFood, sf::VideoMode gameVideoMode) if (CheckBoundaries()) return; newHeadPosition = CalculateNewPosition(snakeDirection, newHeadPosition); - sf::RectangleShape newBodyPart(sf::Vector2f(25,25)); + sf::RectangleShape newBodyPart(sf::Vector2f(kGridSize, kGridSize)); newBodyPart.setPosition(newHeadPosition); if (IsSelfCollision(newBodyPart)) // Do nothing if self collision { @@ -78,9 +96,8 @@ void Snake::MoveSnake(SnakeFood& snakeFood, sf::VideoMode gameVideoMode) } newBodyPart.setFillColor(sf::Color::Green); snakeBody.push_front(newBodyPart); - if (!GlobalCollision(GetSnakeHead().getPosition(), snakeFood.snakeFoodObject.getPosition())) + if (!GlobalCollision(GetSnakeHead().getPosition(), snakeFood.GetFoodObject().getPosition())) snakeBody.pop_back(); - SnakeFoodCollision(snakeFood, gameVideoMode); return; } @@ -123,30 +140,16 @@ bool Snake::IsSelfCollision(sf::RectangleShape testRectangle) return false; } -// If player collides with food then generate until no longer collided with food -void Snake::SnakeFoodCollision(SnakeFood& snakeFood, sf::VideoMode gameVideoMode) +// Checks if snake position matches object position +bool Snake::IsTouchingObject(sf::RectangleShape object) { - while(IsSelfCollision(snakeFood.snakeFoodObject)) + for (auto snakeBodyPart = snakeBody.cbegin(); snakeBodyPart != snakeBody.cend(); ++snakeBodyPart) { - snakeFood.GenerateNewLocation(gameVideoMode.width, gameVideoMode.height); + if ((*snakeBodyPart).getPosition().x != object.getPosition().x) + continue; + if ((*snakeBodyPart).getPosition().y != object.getPosition().y) + continue; + return true; } - return; -} - -// General constructor for snake class -Snake::Snake() -{ - sf::RectangleShape newBodyPart(sf::Vector2f(25,25)); - newBodyPart.setFillColor(sf::Color::Green); - snakeBody.push_back(newBodyPart); - return; -} - -// Constructor for snake with position -Snake::Snake(sf::Vector2f head) -{ - sf::RectangleShape newBodyPart(head); - newBodyPart.setFillColor(sf::Color::Green); - snakeBody.push_back(newBodyPart); - return; + return false; } diff --git a/src/SnakeFood.cpp b/src/SnakeFood.cpp index 4a1dd0f..ff8f525 100644 --- a/src/SnakeFood.cpp +++ b/src/SnakeFood.cpp @@ -2,11 +2,12 @@ #include #include #include "SnakeFood.h" -#include "Snake.h" + +const int kGridSize = 25; SnakeFood::SnakeFood() { - snakeFoodObject.setSize(sf::Vector2f(25,25)); + snakeFoodObject.setSize(sf::Vector2f(kGridSize,kGridSize)); snakeFoodObject.setFillColor(sf::Color::Red); } @@ -16,26 +17,31 @@ SnakeFood::SnakeFood(sf::Vector2f snakeFoodSize) snakeFoodObject.setFillColor(sf::Color::Red); } -void SnakeFood::GenerateNewLocation(int horizontalLocation, int verticalLocation) +// Returns a new food object for the snakeFood +void SnakeFood::GenerateNewFood(sf::Vector2f windowSize) { sf::Vector2f newPosition; - newPosition.x = GenerateRandomNumber(horizontalLocation); - newPosition.y = GenerateRandomNumber(verticalLocation); - if (GlobalCollision(snakeFoodObject.getPosition(), newPosition)) - { - std::cout << "Location error: " << newPosition.x << " " << newPosition.y << '\n'; - throw std::runtime_error("Error! New generation on same location"); - } + newPosition.x = GenerateRandomNumber(windowSize.x); + newPosition.y = GenerateRandomNumber(windowSize.y); snakeFoodObject.setPosition(newPosition); - return; + // if (GlobalCollision(snakeFoodObject.getPosition(), newPosition)) + // { + // std::cout << "Location error: " << newPosition.x << " " << newPosition.y << '\n'; + // throw std::runtime_error("Error! New generation on same location"); + // } } +sf::RectangleShape SnakeFood::GetFoodObject(void) +{ + return snakeFoodObject; +} +// Returns a newly generated number int SnakeFood::GenerateRandomNumber(int generationLimit) { int generatedNumber; std::uniform_int_distribution<> distribution(0, generationLimit); generatedNumber = distribution(generator); - generatedNumber -= (generatedNumber % 25); + generatedNumber -= (generatedNumber % kGridSize); return generatedNumber; } diff --git a/src/main.cpp b/src/main.cpp index bd09bb5..7a1a501 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -2,6 +2,6 @@ int main() { - GameState newGame; - newGame.startNewGame(); + GameState game; + game.StartGame(); } From 6589dabc098c7e80fefd79317df196d1cae54c6e Mon Sep 17 00:00:00 2001 From: TriantaTV Date: Sun, 12 Mar 2023 21:57:46 -0500 Subject: [PATCH 2/2] More cleaning for readabillity, added common file --- Makefile | 7 +- include/Common.h | 18 +++++ include/GameState.h | 5 +- include/Snake.h | 17 ++--- include/SnakeFood.h | 5 +- src/Common.cpp | 11 +++ src/GameState.cpp | 41 +++++++--- src/Snake.cpp | 182 +++++++++++++++++++------------------------- src/SnakeFood.cpp | 17 +++-- 9 files changed, 161 insertions(+), 142 deletions(-) create mode 100644 include/Common.h create mode 100644 src/Common.cpp diff --git a/Makefile b/Makefile index 7ae3f64..16244f8 100644 --- a/Makefile +++ b/Makefile @@ -6,15 +6,16 @@ all: compile link fresh: dirs compile link -dirs: - mkdir bin build - compile: g++ $(INC) $(STD) -c -o build/main.o src/main.cpp + g++ $(INC) $(STD) -c -o build/Common.o src/Common.cpp g++ $(INC) $(STD) -c -o build/GameState.o src/GameState.cpp g++ $(INC) $(STD) -c -o build/Snake.o src/Snake.cpp g++ $(INC) $(STD) -c -o build/SnakeFood.o src/SnakeFood.cpp +dirs: + mkdir bin build + link: g++ build/*.o -o bin/SnakePlusPlus $(SFML) diff --git a/include/Common.h b/include/Common.h new file mode 100644 index 0000000..22c2353 --- /dev/null +++ b/include/Common.h @@ -0,0 +1,18 @@ +#ifndef COMMON_H +#define COMMON_H + +#include + +const int kGridSize = 25; + +enum PlayerDirection +{ + kLeft = 1, + kUp = 2, + kDown = 3, + kRight = 4 +}; + +bool GlobalCollision(sf::Vector2f object1Position, sf::Vector2f object2Position); + +#endif \ No newline at end of file diff --git a/include/GameState.h b/include/GameState.h index 5b0d616..adca85d 100644 --- a/include/GameState.h +++ b/include/GameState.h @@ -12,10 +12,6 @@ public: GameState(int newHorizontal, int newVertical); void StartGame(void); sf::Vector2f GetGameBoundaries(void); - /* - gameGridHorizontal = (videoSizeHorizontal // 25) * 25; - gameGridVertical = (videoSizeVertical // 25) * 25; - */ protected: ; private: @@ -24,6 +20,7 @@ private: SnakeFood playerFood; Snake player; sf::Time delay; + void GetKeyboardInput(void); void RegenerateFood(void); void RunGameLoop(void); void RenderWindow(void); diff --git a/include/Snake.h b/include/Snake.h index 235a0f4..63f2edf 100644 --- a/include/Snake.h +++ b/include/Snake.h @@ -6,27 +6,26 @@ #include #include "SnakeFood.h" -sf::Vector2f CalculateNewPosition(int direction, sf::Vector2f position); -bool GlobalCollision(sf::Vector2f object1Position, sf::Vector2f object2Position); class Snake { public: - Snake(); + Snake(void); Snake(sf::Vector2f head); - sf::Vector2f GetSnakeHeadPosition(); - sf::RectangleShape GetSnakeHead(); void DisplaySnake(sf::RenderWindow& window); - void MoveSnake(SnakeFood& playerFood, sf::VideoMode gameVideoMode); - void CheckDirection(); - bool CheckBoundaries(); - bool IsSelfCollision(sf::RectangleShape testRectangle); + sf::RectangleShape GetSnakeHead(void); + sf::Vector2f GetSnakeHeadPosition(void); bool IsTouchingObject(sf::RectangleShape object); + void MoveSnake(SnakeFood* playerFood); + void UpdateDirection(int newDirection); protected: ; private: std::deque snakeBody; int snakeDirection = 0; + sf::Vector2f CalculateNewPosition(sf::Vector2f position); + bool CheckBoundaries(void); + bool IsSelfCollision(sf::RectangleShape testRectangle); }; diff --git a/include/SnakeFood.h b/include/SnakeFood.h index 824efb9..06b21cb 100644 --- a/include/SnakeFood.h +++ b/include/SnakeFood.h @@ -2,10 +2,8 @@ #ifndef SNAKEFOOD_H #define SNAKEFOOD_H -#include #include - -extern const int kGridSize; +#include class SnakeFood { @@ -14,6 +12,7 @@ public: SnakeFood(sf::Vector2f snakeFoodSize); void GenerateNewFood(sf::Vector2f windowSize); sf::RectangleShape GetFoodObject(void); + sf::Vector2f GetFoodObjectPosition(void); protected: ; private: diff --git a/src/Common.cpp b/src/Common.cpp new file mode 100644 index 0000000..e8887a6 --- /dev/null +++ b/src/Common.cpp @@ -0,0 +1,11 @@ +#include "Common.h" + +// Test for collision between two object positions +bool GlobalCollision(sf::Vector2f object1Position, sf::Vector2f object2Position) +{ + if (object1Position.x != object2Position.x) + return false; + if (object1Position.y != object2Position.y) + return false; + return true; +} \ No newline at end of file diff --git a/src/GameState.cpp b/src/GameState.cpp index 300ed95..13b05f4 100644 --- a/src/GameState.cpp +++ b/src/GameState.cpp @@ -1,20 +1,21 @@ // GameState.cpp #include #include +#include "Common.h" #include "Snake.h" #include "GameState.h" GameState::GameState() { - delay = sf::milliseconds(100); - gameVideoSettings = sf::VideoMode(1024, 725); + delay = sf::milliseconds(75); + gameVideoSettings = sf::VideoMode(1025, 725); gameWindow.create(gameVideoSettings, "SnakePlusPlus"); return; } GameState::GameState(int maxHorizontal, int maxVertical) { - delay = sf::milliseconds(100); + delay = sf::milliseconds(75); gameVideoSettings = sf::VideoMode(maxHorizontal, maxVertical); gameWindow.create(gameVideoSettings, "SnakePlusPlus"); return; @@ -26,6 +27,7 @@ void GameState::StartGame() Snake player(sf::Vector2f(kGridSize,kGridSize)); SnakeFood playerFood(sf::Vector2f(kGridSize,kGridSize)); RunGameLoop(); + return; } sf::Vector2f GameState::GetGameBoundaries(void) @@ -36,6 +38,26 @@ sf::Vector2f GameState::GetGameBoundaries(void) return boundaries; } +void GameState::GetKeyboardInput(void) +{ + sf::Event event; + while (gameWindow.pollEvent(event)) + { + if ((event.type == sf::Event::Closed) || + (sf::Keyboard::isKeyPressed(sf::Keyboard::Escape))) + gameWindow.close(); + } + if (sf::Keyboard::isKeyPressed(sf::Keyboard::Left)) + player.UpdateDirection(kLeft); + if (sf::Keyboard::isKeyPressed(sf::Keyboard::Up)) + player.UpdateDirection(kUp); + if (sf::Keyboard::isKeyPressed(sf::Keyboard::Down)) + player.UpdateDirection(kDown); + if (sf::Keyboard::isKeyPressed(sf::Keyboard::Right)) + player.UpdateDirection(kRight); + return; +} + // Generates new food until not colliding with player void GameState::RegenerateFood(void) { @@ -47,21 +69,15 @@ void GameState::RegenerateFood(void) void GameState::RunGameLoop(void) { - sf::Event event; while (gameWindow.isOpen()) { - while (gameWindow.pollEvent(event)) - { - if ((event.type == sf::Event::Closed) || - (sf::Keyboard::isKeyPressed(sf::Keyboard::Escape))) - gameWindow.close(); - } - player.CheckDirection(); - player.MoveSnake(playerFood, gameVideoSettings); + GetKeyboardInput(); + player.MoveSnake(&playerFood); RegenerateFood(); RenderWindow(); sf::sleep(delay); } + return; } void GameState::RenderWindow(void) @@ -70,4 +86,5 @@ void GameState::RenderWindow(void) player.DisplaySnake(gameWindow); gameWindow.draw(playerFood.GetFoodObject()); gameWindow.display(); + return; } diff --git a/src/Snake.cpp b/src/Snake.cpp index f752c23..b343abb 100644 --- a/src/Snake.cpp +++ b/src/Snake.cpp @@ -2,11 +2,12 @@ #include #include #include +#include "Common.h" #include "Snake.h" #include "SnakeFood.h" // General constructor for snake class -Snake::Snake() +Snake::Snake(void) { sf::RectangleShape newBodyPart(sf::Vector2f(kGridSize, kGridSize)); newBodyPart.setFillColor(sf::Color::Green); @@ -23,121 +24,28 @@ Snake::Snake(sf::Vector2f headSize) return; } -// Get a new coordinate position based on snake direction -sf::Vector2f CalculateNewPosition(int direction, sf::Vector2f position) +// Iterate through snake deque and draw to window +void Snake::DisplaySnake(sf::RenderWindow& window) { - if (direction == 0) - return position; - if (direction == 1) - position.x -= kGridSize; - if (direction == 2) - position.y -= kGridSize; - if (direction == 3) - position.y += kGridSize; - if (direction == 4) - position.x += kGridSize; - return position; -} - -// Test for collision between two object positions -bool GlobalCollision(sf::Vector2f object1Position, sf::Vector2f object2Position) -{ - if (object1Position.x != object2Position.x) - return 0; - if (object1Position.y != object2Position.y) - return 0; - - return 1; -} - -// Check keyboard for new direction of snake -void Snake::CheckDirection() -{ - if (sf::Keyboard::isKeyPressed(sf::Keyboard::Left)) - snakeDirection = 1; - if (sf::Keyboard::isKeyPressed(sf::Keyboard::Up)) - snakeDirection = 2; - if (sf::Keyboard::isKeyPressed(sf::Keyboard::Down)) - snakeDirection = 3; - if (sf::Keyboard::isKeyPressed(sf::Keyboard::Right)) - snakeDirection = 4; + for (auto snakeBodyPart = snakeBody.cbegin(); snakeBodyPart != snakeBody.cend(); ++snakeBodyPart) + window.draw(*snakeBodyPart); return; } -// Check snake head for running into boundaries -bool Snake::CheckBoundaries() -{ - if (snakeBody.front().getPosition().x == 0 && snakeDirection == 1) - return true; - if (snakeBody.front().getPosition().y == 0 && snakeDirection == 2) - return true; - // TODO: Change boundaries to not be hard-coded - if (snakeBody.front().getPosition().y > 675 && snakeDirection == 3) - return true; - if (snakeBody.front().getPosition().x > 975 && snakeDirection == 4) - return true; - return false; -} - -// Move snake based on direction and test for eating food -void Snake::MoveSnake(SnakeFood& snakeFood, sf::VideoMode gameVideoMode) -{ - // CheckDirection(); - sf::Vector2f newHeadPosition; - newHeadPosition = GetSnakeHeadPosition(); - if (CheckBoundaries()) - return; - newHeadPosition = CalculateNewPosition(snakeDirection, newHeadPosition); - sf::RectangleShape newBodyPart(sf::Vector2f(kGridSize, kGridSize)); - newBodyPart.setPosition(newHeadPosition); - if (IsSelfCollision(newBodyPart)) // Do nothing if self collision - { - return; - } - newBodyPart.setFillColor(sf::Color::Green); - snakeBody.push_front(newBodyPart); - if (!GlobalCollision(GetSnakeHead().getPosition(), snakeFood.GetFoodObject().getPosition())) - snakeBody.pop_back(); - return; -} - -// Return the Vector2f head of snake -sf::Vector2f Snake::GetSnakeHeadPosition() -{ - sf::Vector2f position; - position = snakeBody.front().getPosition(); - return position; -} - // Return the RectangleShape head of snake -sf::RectangleShape Snake::GetSnakeHead() +sf::RectangleShape Snake::GetSnakeHead(void) { sf::RectangleShape head; head = snakeBody.front(); return head; } -// Iterate through snake deque and draw to window -void Snake::DisplaySnake(sf::RenderWindow& window) +// Return the Vector2f head of snake +sf::Vector2f Snake::GetSnakeHeadPosition(void) { - for (auto it = snakeBody.cbegin(); it != snakeBody.cend(); ++it) - { - window.draw(*it); - } - return; -} - -// Test for snake self collision -bool Snake::IsSelfCollision(sf::RectangleShape testRectangle) -{ - for (auto it = snakeBody.cbegin(); it != snakeBody.cend(); ++it) - { - if (GlobalCollision(testRectangle.getPosition(), (*it).getPosition())) - { - return true; - } - } - return false; + sf::Vector2f position; + position = snakeBody.front().getPosition(); + return position; } // Checks if snake position matches object position @@ -153,3 +61,69 @@ bool Snake::IsTouchingObject(sf::RectangleShape object) } return false; } + +// Move snake based on direction and check for collision +void Snake::MoveSnake(SnakeFood* snakeFood) +{ + // TODO: Add losing on wall collision + if (CheckBoundaries()) // Wall collision + return; + sf::Vector2f newHeadPosition; + newHeadPosition = CalculateNewPosition(GetSnakeHeadPosition()); + sf::RectangleShape newBodyPart(sf::Vector2f(kGridSize, kGridSize)); + newBodyPart.setPosition(newHeadPosition); + // TODO: Add losing on self collision + if (IsSelfCollision(newBodyPart)) // Snake collision + return; + newBodyPart.setFillColor(sf::Color::Green); + snakeBody.push_front(newBodyPart); + if (!GlobalCollision(GetSnakeHeadPosition(), snakeFood->GetFoodObjectPosition())) + snakeBody.pop_back(); + return; +} + +void Snake::UpdateDirection(int newDirection) +{ + snakeDirection = newDirection; + return; +} + +// Get a new coordinate position based on snake direction +sf::Vector2f Snake::CalculateNewPosition(sf::Vector2f position) +{ + if (snakeDirection == 0) + return position; + if (snakeDirection == kLeft) + position.x -= kGridSize; + if (snakeDirection == kUp) + position.y -= kGridSize; + if (snakeDirection == kDown) + position.y += kGridSize; + if (snakeDirection == kRight) + position.x += kGridSize; + return position; +} + +// Check snake head for running into boundaries +bool Snake::CheckBoundaries(void) +{ + if (snakeBody.front().getPosition().x == 0 && snakeDirection == kLeft) + return true; + if (snakeBody.front().getPosition().y == 0 && snakeDirection == kUp) + return true; + // TODO: Change boundaries to not be hard-coded + if (snakeBody.front().getPosition().y > 675 && snakeDirection == kDown) + return true; + if (snakeBody.front().getPosition().x > 975 && snakeDirection == kRight) + return true; + return false; +} + +// Test for snake self collision +bool Snake::IsSelfCollision(sf::RectangleShape testRectangle) +{ + for (auto snakeBodyPart = snakeBody.cbegin(); snakeBodyPart != snakeBody.cend(); ++snakeBodyPart) + if (GlobalCollision(testRectangle.getPosition(), (*snakeBodyPart).getPosition())) + return true; + return false; +} diff --git a/src/SnakeFood.cpp b/src/SnakeFood.cpp index ff8f525..b1989e4 100644 --- a/src/SnakeFood.cpp +++ b/src/SnakeFood.cpp @@ -1,20 +1,22 @@ // SnakeFood.cpp #include #include +#include "Common.h" #include "SnakeFood.h" -const int kGridSize = 25; SnakeFood::SnakeFood() { - snakeFoodObject.setSize(sf::Vector2f(kGridSize,kGridSize)); + snakeFoodObject.setSize(sf::Vector2f(kGridSize, kGridSize)); snakeFoodObject.setFillColor(sf::Color::Red); + return; } SnakeFood::SnakeFood(sf::Vector2f snakeFoodSize) { snakeFoodObject.setSize(snakeFoodSize); snakeFoodObject.setFillColor(sf::Color::Red); + return; } // Returns a new food object for the snakeFood @@ -24,11 +26,7 @@ void SnakeFood::GenerateNewFood(sf::Vector2f windowSize) newPosition.x = GenerateRandomNumber(windowSize.x); newPosition.y = GenerateRandomNumber(windowSize.y); snakeFoodObject.setPosition(newPosition); - // if (GlobalCollision(snakeFoodObject.getPosition(), newPosition)) - // { - // std::cout << "Location error: " << newPosition.x << " " << newPosition.y << '\n'; - // throw std::runtime_error("Error! New generation on same location"); - // } + return; } sf::RectangleShape SnakeFood::GetFoodObject(void) @@ -36,6 +34,11 @@ sf::RectangleShape SnakeFood::GetFoodObject(void) return snakeFoodObject; } +sf::Vector2f SnakeFood::GetFoodObjectPosition(void) +{ + return snakeFoodObject.getPosition(); +} + // Returns a newly generated number int SnakeFood::GenerateRandomNumber(int generationLimit) {