From 75cf6f524db46b00e498cd6b487a7dd6192d0d24 Mon Sep 17 00:00:00 2001 From: Joseph Aquino Date: Sun, 21 Dec 2025 02:19:18 -0500 Subject: [PATCH] added fruit and edge collision --- include/Fruit.h | 16 +++++++ include/Game.h | 9 +++- include/GameConfig.h | 4 +- include/Player.h | 14 +++--- include/log.h | 11 +++++ src/Fruit.cpp | 35 ++++++++++++++ src/Game.cpp | 107 +++++++++++++++++++++++++++++++++++-------- src/Player.cpp | 7 ++- src/main.cpp | 9 ++++ 9 files changed, 185 insertions(+), 27 deletions(-) create mode 100644 include/Fruit.h create mode 100644 include/log.h create mode 100644 src/Fruit.cpp diff --git a/include/Fruit.h b/include/Fruit.h new file mode 100644 index 0000000..71a7bee --- /dev/null +++ b/include/Fruit.h @@ -0,0 +1,16 @@ +#pragma once + +#include +#include +#include + +struct Fruit +{ + Fruit() = default; + Fruit(sf::Vector2i gridPos_in, const sf::Color& color_in = sf::Color::White); + sf::Vector2u gridPos{}; + Color color{}; + + sf::Vector2f windowPos(float gridSize_in); + void respawn(const std::vector& body_in, sf::Vector2u gridCount_in); +}; \ No newline at end of file diff --git a/include/Game.h b/include/Game.h index 5e6fd0b..96a66e5 100644 --- a/include/Game.h +++ b/include/Game.h @@ -2,6 +2,7 @@ #include #include +#include #include #include #include @@ -39,6 +40,8 @@ private: void failState(); + void winState(); + private: GameConfig config; @@ -54,9 +57,13 @@ private: //sf::Sound failSound; Player player{}; + Fruit fruit{}; + + sf::Vector2u gridCount; size_t frameCount{}; bool useImgui; - bool fail; + bool fail{}; + bool win{}; bool running{true}; }; \ No newline at end of file diff --git a/include/GameConfig.h b/include/GameConfig.h index d6b8716..0f4be31 100644 --- a/include/GameConfig.h +++ b/include/GameConfig.h @@ -1,3 +1,5 @@ +#pragma once + #include #include @@ -8,6 +10,6 @@ struct GameConfig int framerate{}; Color playerHeadColor; Color playerBodyColor; - sf::Vector2i headGridStartPos; + sf::Vector2u headGridStartPos; float gridSize; }; diff --git a/include/Player.h b/include/Player.h index 333ecf3..8a48c48 100644 --- a/include/Player.h +++ b/include/Player.h @@ -1,4 +1,4 @@ - +#pragma once #include #include @@ -13,14 +13,16 @@ enum class Direction struct SnakeNode { - SnakeNode(sf::Vector2i gridPos_in, sf::Color color_in = sf::Color::White); - sf::Vector2f windowPos{}; - sf::Vector2i gridPos{}; - sf::Vector2i previousGridPos{}; + SnakeNode(sf::Vector2u gridPos_in, const sf::Color& color_in = sf::Color::White); + // sf::Vector2f windowPos{}; + sf::Vector2u gridPos{}; + sf::Vector2u previousGridPos{}; Color color{}; + + sf::Vector2f windowPos(float gridSize_in); }; -struct Player +struct Player { Player() = default; diff --git a/include/log.h b/include/log.h new file mode 100644 index 0000000..835b47c --- /dev/null +++ b/include/log.h @@ -0,0 +1,11 @@ +#pragma once + +#include + +#ifdef LOG_ENABLE +#define LOG_CONDITON(x) if (x) +#define LOG(x) std::cout << x << "\n" +#else +#define LOG(x) +#define LOG_CONDITON(x) +#endif \ No newline at end of file diff --git a/src/Fruit.cpp b/src/Fruit.cpp new file mode 100644 index 0000000..001f2ba --- /dev/null +++ b/src/Fruit.cpp @@ -0,0 +1,35 @@ +#include +#include +#include + +Fruit::Fruit(sf::Vector2i gridPos_in, const sf::Color& color_in) + : gridPos(gridPos_in) + , color(color_in) +{ } + +sf::Vector2f Fruit::windowPos(float gridSize_in) +{ + return {gridPos.x * gridSize_in, gridPos.y * gridSize_in}; +} + +void Fruit::respawn(const std::vector& body_in, sf::Vector2u gridCount_in) +{ + unsigned int tempX; + unsigned int tempY; + bool valid = false; + do + { + tempX = Random::get(0, gridCount_in.x - 1); + tempY = Random::get(0, gridCount_in.y - 1); + for (const auto& node : body_in) + { + if (node.gridPos.x != tempX and node.gridPos.y != tempY) + { + valid = true; + } + } + } while (!valid); + + this->gridPos = {tempX, tempY}; + +} \ No newline at end of file diff --git a/src/Game.cpp b/src/Game.cpp index d0f7e6e..bf688ea 100644 --- a/src/Game.cpp +++ b/src/Game.cpp @@ -31,13 +31,26 @@ Game::Game(bool useImgui_in) return; } + gridCount.x = window.getSize().x / config.gridSize; + gridCount.y = window.getSize().y / config.gridSize; + player.body.reserve(100); player.body.emplace_back(config.headGridStartPos); - player.head().windowPos.x = player.head().gridPos.x * config.gridSize; - player.head().windowPos.y = player.head().gridPos.y * config.gridSize; + fruit.gridPos = {5,5}; + fruit.color = sf::Color::Red; + + //uncomment to quickly test player movement + /* + player.body.emplace_back(sf::Vector2i{config.headGridStartPos.x - 1, config.headGridStartPos.y}); + player.body.emplace_back(sf::Vector2i{config.headGridStartPos.x - 2, config.headGridStartPos.y}); + player.body.emplace_back(sf::Vector2i{config.headGridStartPos.x - 3, config.headGridStartPos.y}); + player.body.emplace_back(sf::Vector2i{config.headGridStartPos.x - 4, config.headGridStartPos.y}); + */ + tempRect.setSize({config.gridSize, config.gridSize}); - tempRect.setOutlineThickness(5); + tempRect.setOutlineThickness(-5); + tempRect.setOutlineColor(sf::Color::Black); score.setPosition({10, static_cast(window.getSize().y - 40)}); @@ -179,10 +192,23 @@ void Game::collision() if (player.head().gridPos == player.body.at(i).gridPos) { fail = true; - //failSound.play(); return; } + } + if (player.head().gridPos == fruit.gridPos) + { + player.body.emplace_back(player.body.back().previousGridPos); + if (player.body.size() != (gridCount.x * gridCount.y)) + { + //play sound + fruit.respawn(player.body, gridCount); + } + else + { + //play win sound + + } } } @@ -211,39 +237,68 @@ void Game::movement() if (frameCount % config.tickRate != 0) return; + SnakeNode& head = player.head(); switch (player.inputBuffer) { case Direction::up: - player.head().previousGridPos = player.head().gridPos; - player.head().gridPos += sf::Vector2i{ 0, -1 }; + if (head.gridPos.y == 0) + { + fail = true; + return; + } + + head.previousGridPos = head.gridPos; + head.gridPos.y -= 1; player.facing = Direction::up; // std::cout << "up\n"; break; case Direction::down: - player.head().previousGridPos = player.head().gridPos; - player.head().gridPos += sf::Vector2i{ 0, 1 }; + if (head.gridPos.y == gridCount.y - 1) + { + fail = true; + return; + } + + head.previousGridPos = head.gridPos; + head.gridPos.y += 1; player.facing = Direction::down; // std::cout << "down\n"; break; case Direction::left: - player.head().previousGridPos = player.head().gridPos; - player.head().gridPos += sf::Vector2i{ -1, 0 }; + if (head.gridPos.x == 0) + { + fail = true; + return; + } + + head.previousGridPos = head.gridPos; + head.gridPos.x -= 1; player.facing = Direction::left; // std::cout << "left\n"; break; case Direction::right: - player.head().previousGridPos = player.head().gridPos; - player.head().gridPos += sf::Vector2i{ 1, 0 }; + if (head.gridPos.x == gridCount.x -1) + { + fail = true; + return; + } + + head.previousGridPos = head.gridPos; + head.gridPos.x += 1; player.facing = Direction::right; // std::cout << "right\n"; break; } - player.head().windowPos.x = player.head().gridPos.x * config.gridSize; - player.head().windowPos.y = player.head().gridPos.y * config.gridSize; + const size_t limit = player.body.size(); + for (size_t i = 1; i < limit; i++) + { + player.body[i].previousGridPos = player.body[i].gridPos; + player.body[i].gridPos = player.body[i-1].previousGridPos; + } } @@ -279,10 +334,14 @@ void Game::render() for (auto& node : player.body) { tempRect.setFillColor(node.color.sfml()); - tempRect.setPosition(node.windowPos); + tempRect.setPosition(node.windowPos(config.gridSize)); window.draw(tempRect); } + tempRect.setFillColor(fruit.color.sfml()); + tempRect.setPosition(fruit.windowPos(config.gridSize)); + window.draw(tempRect); + score.setString("Score: " + std::to_string(player.score)); window.draw(score); @@ -304,7 +363,10 @@ void Game::scoreSystem() void Game::resetGame() { - + player.body.clear(); + player.body.emplace_back(config.headGridStartPos); + fail = false; + player.facing = Direction::up; } void Game::failState() @@ -316,6 +378,11 @@ void Game::failState() // } } +void Game::winState() +{ + +} + void Game::run() { while(window.isOpen()) @@ -326,7 +393,7 @@ void Game::run() input(); - if (!fail) + if (!fail and !win) { movement(); @@ -336,10 +403,14 @@ void Game::run() scoreSystem(); } - else + else if (fail) { failState(); } + else if (win) + { + winState(); + } imgui(); diff --git a/src/Player.cpp b/src/Player.cpp index 4cc617c..a95033d 100644 --- a/src/Player.cpp +++ b/src/Player.cpp @@ -1,10 +1,15 @@ #include -SnakeNode::SnakeNode(sf::Vector2i gridPos_in, sf::Color color_in) +SnakeNode::SnakeNode(sf::Vector2u gridPos_in, const sf::Color& color_in) : gridPos(gridPos_in) , color(color_in) { } +sf::Vector2f SnakeNode::windowPos(float gridSize_in) +{ + return {gridPos.x * gridSize_in, gridPos.y * gridSize_in}; +} + SnakeNode& Player::head() { return body[0]; diff --git a/src/main.cpp b/src/main.cpp index e14861d..2bbb27e 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1,3 +1,4 @@ +#include #include int main(int argc, char* argv[]) @@ -11,6 +12,14 @@ int main(int argc, char* argv[]) useImgui = false; } } + + LOG("\n\n\033[32mTODO: "); + LOG("-Implement fruit eating"); + LOG("-Implement sound effects and background music"); + LOG("-Handle game over state"); + LOG("-Implement game config via imgui"); + LOG("\033[0m"); + Game game(useImgui); game.run();