From a3d6742d9847ff47f4c8ea5e37af7b7481213d5a Mon Sep 17 00:00:00 2001 From: Joseph Aquino Date: Fri, 19 Dec 2025 11:40:38 -0500 Subject: [PATCH] initial implementation -implemented basic movement --- config/game-config.txt | 9 +- include/Game.h | 47 ++++------ include/GameConfig.h | 13 +++ include/Player.h | 38 ++++++++ src/Game.cpp | 194 ++++++++++++++++++++++++++++++++++------- src/Player.cpp | 11 +++ src/main.cpp | 1 - 7 files changed, 249 insertions(+), 64 deletions(-) create mode 100644 include/GameConfig.h create mode 100644 include/Player.h create mode 100644 src/Player.cpp diff --git a/config/game-config.txt b/config/game-config.txt index 3953675..dc58bd7 100644 --- a/config/game-config.txt +++ b/config/game-config.txt @@ -1,4 +1,11 @@ framerate 60 -playerColor 1 1 1 +tickRate 60 +playerHeadColor 1 1 1 + +playerBodyColor 1 1 1 + +headGridStartPos 10 10 + +gridSize 50 \ No newline at end of file diff --git a/include/Game.h b/include/Game.h index d8c6142..5e6fd0b 100644 --- a/include/Game.h +++ b/include/Game.h @@ -1,36 +1,14 @@ #pragma once -#include - #include - +#include +#include #include #include #include #include -class SnakeNode -{ - -}; - -struct Player -{ - Player() = default; - Player(sf::Vector2i gridPos_in); - - sf::Vector2i gridPos{}; - sf::Vector2i previousGridPos{}; - sf::Vector2f windowPos{}; - int score{}; - int lives{3}; - bool left{false}; - bool right{false}; - bool up{false}; - bool down{false}; -}; - class Game { public: @@ -38,6 +16,8 @@ public: void run(); + bool init(); + private: void imgui(); @@ -57,19 +37,26 @@ private: void scoreSystem(); + void failState(); + private: + GameConfig config; sf::Clock clock; sf::RenderWindow window; sf::Font font; - sf::Text lives; sf::Text score; - Player player; + sf::SoundBuffer failSoundBuffer; - // mostly used for imgui - int framerate{}; - float volume{}; + sf::RectangleShape tempRect; + + //sf::Sound failSound; + + Player player{}; + + size_t frameCount{}; bool useImgui; - static constexpr unsigned int numPhysicsUpdates{4}; + bool fail; + bool running{true}; }; \ No newline at end of file diff --git a/include/GameConfig.h b/include/GameConfig.h new file mode 100644 index 0000000..d6b8716 --- /dev/null +++ b/include/GameConfig.h @@ -0,0 +1,13 @@ +#include +#include + +struct GameConfig +{ + float volume{10}; + int tickRate{}; + int framerate{}; + Color playerHeadColor; + Color playerBodyColor; + sf::Vector2i headGridStartPos; + float gridSize; +}; diff --git a/include/Player.h b/include/Player.h new file mode 100644 index 0000000..333ecf3 --- /dev/null +++ b/include/Player.h @@ -0,0 +1,38 @@ + +#include + +#include + +enum class Direction +{ + up, + down, + left, + right +}; + +struct SnakeNode +{ + SnakeNode(sf::Vector2i gridPos_in, sf::Color color_in = sf::Color::White); + sf::Vector2f windowPos{}; + sf::Vector2i gridPos{}; + sf::Vector2i previousGridPos{}; + Color color{}; +}; + +struct Player +{ + Player() = default; + + SnakeNode& head(); + + std::vector body; + + int score{}; + Direction facing{Direction::up}; + Direction inputBuffer{}; + bool left{false}; + bool right{false}; + bool up{false}; + bool down{false}; +}; \ No newline at end of file diff --git a/src/Game.cpp b/src/Game.cpp index e678188..d0f7e6e 100644 --- a/src/Game.cpp +++ b/src/Game.cpp @@ -12,22 +12,36 @@ Game::Game(bool useImgui_in) - : window({sf::VideoMode({ 1920u, 1080u }), "project-breakout"}) + : config() + , window({sf::VideoMode({ 1920u, 1080u }), "project-snake"}) , font("assets/fonts/ChakraPetch-Regular.ttf") - , lives(font) , score(font) - , volume(10) , useImgui(useImgui_in) { - - if (!ImGui::SFML::Init(window)) return; - - if (!parseConfigFile()) return; + if (!ImGui::SFML::Init(window)) + { + std::cout << "ERROR: Could not open window\n"; + return; + } - lives.setPosition({10, static_cast(window.getSize().y - 40)}); - score.setPosition({10, static_cast(window.getSize().y - 80)}); + if (!parseConfigFile()) + { + std::cout << "ERROR: Could not parse config file\n"; + window.close(); + return; + } - window.setFramerateLimit(framerate); + 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; + + tempRect.setSize({config.gridSize, config.gridSize}); + tempRect.setOutlineThickness(5); + + score.setPosition({10, static_cast(window.getSize().y - 40)}); + + window.setFramerateLimit(config.framerate); } @@ -44,7 +58,35 @@ bool Game::parseConfigFile() std::string inputBuff; while(configFile >> inputBuff) { + if (inputBuff == "framerate") + { + configFile >> config.framerate; + } + if (inputBuff == "tickRate") + { + configFile >> config.tickRate; + } + + if (inputBuff == "playerHeadColor") + { + configFile >> config.playerHeadColor.r >> config.playerHeadColor.g >> config.playerHeadColor.b; + } + + if (inputBuff == "playerBodyColor") + { + configFile >> config.playerBodyColor.r >> config.playerBodyColor.g >> config.playerBodyColor.b; + } + + if (inputBuff == "headGridStartPos") + { + configFile >> config.headGridStartPos.x >> config.headGridStartPos.y; + } + + if (inputBuff == "gridSize") + { + configFile >> config.gridSize; + } } return true; @@ -63,12 +105,12 @@ void Game::input() if (const auto* keyPressed = event->getIf()) { - switch (keyPressed->scancode) + switch (keyPressed->scancode) { case sf::Keyboard::Scan::Escape: window.close(); break; - + case sf::Keyboard::Scan::Left: case sf::Keyboard::Scan::A: player.left = true; @@ -92,7 +134,7 @@ void Game::input() case sf::Keyboard::Scan::R: resetGame(); break; - + default: break; } @@ -100,7 +142,7 @@ void Game::input() if (const auto* keyReleased = event->getIf()) { - switch (keyReleased->scancode) + switch (keyReleased->scancode) { case sf::Keyboard::Scan::Left: case sf::Keyboard::Scan::A: @@ -120,29 +162,94 @@ void Game::input() case sf::Keyboard::Scan::Down: case sf::Keyboard::Scan::S: player.down = false; - break; + break; default: break; } } - } + } } void Game::collision() { - + const size_t limit = player.body.size(); + for (size_t i = 1; i < limit; i++) + { + if (player.head().gridPos == player.body.at(i).gridPos) + { + fail = true; + //failSound.play(); + return; + } + + } } void Game::movement() { + if (player.left and !player.right and (player.facing == Direction::up or player.facing == Direction::down)) + { + player.inputBuffer = Direction::left; + } + + if (player.right and !player.left and (player.facing == Direction::up or player.facing == Direction::down)) + { + player.inputBuffer = Direction::right; + } + + if (player.up and !player.down and (player.facing == Direction::left or player.facing == Direction::right)) + { + player.inputBuffer = Direction::up; + } + + if (player.down and !player.up and (player.facing == Direction::left or player.facing == Direction::right)) + { + player.inputBuffer = Direction::down; + } + + if (frameCount % config.tickRate != 0) return; + + switch (player.inputBuffer) + { + case Direction::up: + player.head().previousGridPos = player.head().gridPos; + player.head().gridPos += sf::Vector2i{ 0, -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 }; + 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 }; + 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 }; + 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; } void Game::imgui() { - ImGui::SetNextWindowCollapsed(false, ImGuiCond_Once); + ImGui::SetNextWindowCollapsed(true, ImGuiCond_Once); ImGui::SetNextWindowSize({490,375}, ImGuiCond_Once); ImGui::SetNextWindowPos({26,29}, ImGuiCond_Once); if(!ImGui::Begin("menu")) @@ -156,7 +263,7 @@ void Game::imgui() ImGui::Text("R: reset game"); ImGui::Unindent(); - if (ImGui::SliderFloat("Game Volume", &volume, 0, 100, "%.1f")) + if (ImGui::SliderFloat("Game Volume", &config.volume, 0, 100, "%.1f")) { } @@ -168,15 +275,20 @@ void Game::imgui() void Game::render() { window.clear(); - - lives.setString("Lives: " + std::to_string(player.lives)); + + for (auto& node : player.body) + { + tempRect.setFillColor(node.color.sfml()); + tempRect.setPosition(node.windowPos); + window.draw(tempRect); + } + score.setString("Score: " + std::to_string(player.score)); - window.draw(lives); window.draw(score); ImGui::SFML::Render(window); - + window.display(); } @@ -195,26 +307,44 @@ void Game::resetGame() } +void Game::failState() +{ + // if (failSound.getStatus() == sf::Sound::Status::Stopped) + // { + // resetGame(); + // return; + // } +} + void Game::run() { while(window.isOpen()) { ImGui::SFML::Update(window, clock.restart()); - + + frameCount++; + input(); - movement(); - - collision(); - - soundSystem(); + if (!fail) + { + movement(); + + collision(); + + soundSystem(); + + scoreSystem(); + } + else + { + failState(); + } - scoreSystem(); - imgui(); render(); - + } ImGui::SFML::Shutdown(); diff --git a/src/Player.cpp b/src/Player.cpp new file mode 100644 index 0000000..4cc617c --- /dev/null +++ b/src/Player.cpp @@ -0,0 +1,11 @@ +#include + +SnakeNode::SnakeNode(sf::Vector2i gridPos_in, sf::Color color_in) + : gridPos(gridPos_in) + , color(color_in) +{ } + +SnakeNode& Player::head() +{ + return body[0]; +} diff --git a/src/main.cpp b/src/main.cpp index bea0c7d..e14861d 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -11,7 +11,6 @@ int main(int argc, char* argv[]) useImgui = false; } } - Game game(useImgui); game.run();