initial implementation

-implemented basic movement
This commit is contained in:
Joseph Aquino 2025-12-19 11:40:38 -05:00
parent de9b81cf26
commit a3d6742d98
7 changed files with 249 additions and 64 deletions

View File

@ -1,4 +1,11 @@
framerate 60 framerate 60
playerColor 1 1 1 tickRate 60
playerHeadColor 1 1 1
playerBodyColor 1 1 1
headGridStartPos 10 10
gridSize 50

View File

@ -1,36 +1,14 @@
#pragma once #pragma once
#include <vector>
#include <Util.h> #include <Util.h>
#include <Player.h>
#include <GameConfig.h>
#include <SFML/Graphics.hpp> #include <SFML/Graphics.hpp>
#include <SFML/Audio.hpp> #include <SFML/Audio.hpp>
#include <imgui-SFML.h> #include <imgui-SFML.h>
#include <imgui.h> #include <imgui.h>
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 class Game
{ {
public: public:
@ -38,6 +16,8 @@ public:
void run(); void run();
bool init();
private: private:
void imgui(); void imgui();
@ -57,19 +37,26 @@ private:
void scoreSystem(); void scoreSystem();
void failState();
private: private:
GameConfig config;
sf::Clock clock; sf::Clock clock;
sf::RenderWindow window; sf::RenderWindow window;
sf::Font font; sf::Font font;
sf::Text lives;
sf::Text score; sf::Text score;
Player player; sf::SoundBuffer failSoundBuffer;
// mostly used for imgui sf::RectangleShape tempRect;
int framerate{};
float volume{}; //sf::Sound failSound;
Player player{};
size_t frameCount{};
bool useImgui; bool useImgui;
static constexpr unsigned int numPhysicsUpdates{4}; bool fail;
bool running{true};
}; };

13
include/GameConfig.h Normal file
View File

@ -0,0 +1,13 @@
#include <Util.h>
#include <SFML/Graphics.hpp>
struct GameConfig
{
float volume{10};
int tickRate{};
int framerate{};
Color playerHeadColor;
Color playerBodyColor;
sf::Vector2i headGridStartPos;
float gridSize;
};

38
include/Player.h Normal file
View File

@ -0,0 +1,38 @@
#include <SFML/Graphics.hpp>
#include <Util.h>
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<SnakeNode> body;
int score{};
Direction facing{Direction::up};
Direction inputBuffer{};
bool left{false};
bool right{false};
bool up{false};
bool down{false};
};

View File

@ -12,22 +12,36 @@
Game::Game(bool useImgui_in) 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") , font("assets/fonts/ChakraPetch-Regular.ttf")
, lives(font)
, score(font) , score(font)
, volume(10)
, useImgui(useImgui_in) , useImgui(useImgui_in)
{ {
if (!ImGui::SFML::Init(window))
if (!ImGui::SFML::Init(window)) return; {
std::cout << "ERROR: Could not open window\n";
if (!parseConfigFile()) return; return;
}
lives.setPosition({10, static_cast<float>(window.getSize().y - 40)}); if (!parseConfigFile())
score.setPosition({10, static_cast<float>(window.getSize().y - 80)}); {
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<float>(window.getSize().y - 40)});
window.setFramerateLimit(config.framerate);
} }
@ -44,7 +58,35 @@ bool Game::parseConfigFile()
std::string inputBuff; std::string inputBuff;
while(configFile >> 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; return true;
@ -63,12 +105,12 @@ void Game::input()
if (const auto* keyPressed = event->getIf<sf::Event::KeyPressed>()) if (const auto* keyPressed = event->getIf<sf::Event::KeyPressed>())
{ {
switch (keyPressed->scancode) switch (keyPressed->scancode)
{ {
case sf::Keyboard::Scan::Escape: case sf::Keyboard::Scan::Escape:
window.close(); window.close();
break; break;
case sf::Keyboard::Scan::Left: case sf::Keyboard::Scan::Left:
case sf::Keyboard::Scan::A: case sf::Keyboard::Scan::A:
player.left = true; player.left = true;
@ -92,7 +134,7 @@ void Game::input()
case sf::Keyboard::Scan::R: case sf::Keyboard::Scan::R:
resetGame(); resetGame();
break; break;
default: default:
break; break;
} }
@ -100,7 +142,7 @@ void Game::input()
if (const auto* keyReleased = event->getIf<sf::Event::KeyReleased>()) if (const auto* keyReleased = event->getIf<sf::Event::KeyReleased>())
{ {
switch (keyReleased->scancode) switch (keyReleased->scancode)
{ {
case sf::Keyboard::Scan::Left: case sf::Keyboard::Scan::Left:
case sf::Keyboard::Scan::A: case sf::Keyboard::Scan::A:
@ -120,29 +162,94 @@ void Game::input()
case sf::Keyboard::Scan::Down: case sf::Keyboard::Scan::Down:
case sf::Keyboard::Scan::S: case sf::Keyboard::Scan::S:
player.down = false; player.down = false;
break; break;
default: default:
break; break;
} }
} }
} }
} }
void Game::collision() 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() 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() void Game::imgui()
{ {
ImGui::SetNextWindowCollapsed(false, ImGuiCond_Once); ImGui::SetNextWindowCollapsed(true, ImGuiCond_Once);
ImGui::SetNextWindowSize({490,375}, ImGuiCond_Once); ImGui::SetNextWindowSize({490,375}, ImGuiCond_Once);
ImGui::SetNextWindowPos({26,29}, ImGuiCond_Once); ImGui::SetNextWindowPos({26,29}, ImGuiCond_Once);
if(!ImGui::Begin("menu")) if(!ImGui::Begin("menu"))
@ -156,7 +263,7 @@ void Game::imgui()
ImGui::Text("R: reset game"); ImGui::Text("R: reset game");
ImGui::Unindent(); 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() void Game::render()
{ {
window.clear(); 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)); score.setString("Score: " + std::to_string(player.score));
window.draw(lives);
window.draw(score); window.draw(score);
ImGui::SFML::Render(window); ImGui::SFML::Render(window);
window.display(); window.display();
} }
@ -195,26 +307,44 @@ void Game::resetGame()
} }
void Game::failState()
{
// if (failSound.getStatus() == sf::Sound::Status::Stopped)
// {
// resetGame();
// return;
// }
}
void Game::run() void Game::run()
{ {
while(window.isOpen()) while(window.isOpen())
{ {
ImGui::SFML::Update(window, clock.restart()); ImGui::SFML::Update(window, clock.restart());
frameCount++;
input(); input();
movement(); if (!fail)
{
collision(); movement();
soundSystem(); collision();
soundSystem();
scoreSystem();
}
else
{
failState();
}
scoreSystem();
imgui(); imgui();
render(); render();
} }
ImGui::SFML::Shutdown(); ImGui::SFML::Shutdown();

11
src/Player.cpp Normal file
View File

@ -0,0 +1,11 @@
#include <Player.h>
SnakeNode::SnakeNode(sf::Vector2i gridPos_in, sf::Color color_in)
: gridPos(gridPos_in)
, color(color_in)
{ }
SnakeNode& Player::head()
{
return body[0];
}

View File

@ -11,7 +11,6 @@ int main(int argc, char* argv[])
useImgui = false; useImgui = false;
} }
} }
Game game(useImgui); Game game(useImgui);
game.run(); game.run();