Code refactor

-added commandline arg to disable imgui
-implemented a config text file
-split util.h into seperate .h and .cpp files
This commit is contained in:
Joseph Aquino 2025-09-09 20:10:53 -04:00
parent 593dbbf86b
commit 79f6fc9af5
9 changed files with 254 additions and 80 deletions

27
Config/game-config.txt Normal file
View File

@ -0,0 +1,27 @@
framerate 60
playerStartPos 700 700
playerSize 500 10
playerSpeed 10
playerColor 1 1 1
ballRadius 5
ballSpeed 2.5
ballColor 1 0 0
brickSize 50 10
brickColor 1 1 1
specialBrickColor 0 1 0
bricksPerRow 8
bricksPerColumn 5
specialBrickCount 3

20
include/Color.h Normal file
View File

@ -0,0 +1,20 @@
#pragma once
#include <SFML/Graphics.hpp>
struct Color
{
Color() = default;
Color(float r_in, float g_in, float b_in, float a_in);
Color(sf::Color color_in);
sf::Color sfml();
float* imgui();
float r{};
float g{};
float b{};
float a{1.f};
};

View File

@ -3,7 +3,6 @@
#include <vector> #include <vector>
#include <Util.h> #include <Util.h>
#include <Random.h>
#include <SFML/Graphics.hpp> #include <SFML/Graphics.hpp>
#include <imgui-SFML.h> #include <imgui-SFML.h>
@ -15,8 +14,8 @@ struct Ball
Ball(sf::Vector2f position_in, sf::Vector2f vel_in); Ball(sf::Vector2f position_in, sf::Vector2f vel_in);
sf::Vector2f pos; sf::Vector2f pos;
sf::Vector2f previousPos{};
sf::Vector2f velocity; sf::Vector2f velocity;
sf::Vector2f previousPos{};
bool alive{true}; bool alive{true};
}; };
@ -47,6 +46,7 @@ public:
Game(); Game();
void run(); void run();
void runNoImgui();
private: private:
void imgui(); void imgui();
@ -65,6 +65,10 @@ private:
void checkBallCollision(); void checkBallCollision();
void resetGame();
bool parseConfigFile();
private: private:
sf::Clock clock; sf::Clock clock;
@ -79,23 +83,23 @@ private:
sf::RectangleShape tempRect; sf::RectangleShape tempRect;
// mostly used for imgui // mostly used for imgui
sf::Vector2f brickSize{50, 10}; sf::Vector2f brickSize{};
sf::Vector2f playerSize{500, 10}; sf::Vector2f playerSize{};
sf::Vector2f playerStartPos{700,700}; sf::Vector2f playerStartPos{};
sf::Vector2f brickHalfSize{brickSize / 2.f}; sf::Vector2f brickHalfSize{};
sf::Vector2f playerHalfSize{playerSize / 2.f}; sf::Vector2f playerHalfSize{};
int rowSize{8}; int rowSize{};
int columnSize{5}; int columnSize{};
int totalSpecialBricks{3}; int totalSpecialBricks{};
int totalBricks{rowSize * columnSize}; int totalBricks{rowSize * columnSize};
unsigned int frameRate{60}; unsigned int framerate{};
float playerSpeed{10}; float playerSpeed{};
float ballRadius{5.0f}; float ballRadius{};
float ballMaxSpeed{10}; float ballMaxSpeed{};
Color ballColor{sf::Color::Red}; Color ballColor{};
Color brickColor{sf::Color::White}; Color brickColor{};
Color playerColor{sf::Color::White}; Color playerColor{};
Color specialBrickColor{sf::Color::Blue}; Color specialBrickColor{};
bool windowCollasped{false}; bool windowCollasped{false};
static constexpr unsigned int numPhysicsUpdates{4}; static constexpr unsigned int numPhysicsUpdates{4};
}; };

7
include/Physics.h Normal file
View File

@ -0,0 +1,7 @@
#pragma once
#include <SFML/Graphics.hpp>
sf::Vector2f getOverlap(sf::FloatRect first, sf::FloatRect second);
sf::Vector2f velocityInRandomDir(float speed_in);
sf::Vector2f velocityInDirection(float speed_in, sf::Angle angle_in);

View File

@ -1,40 +1,5 @@
#pragma once #pragma once
#include <SFML/Graphics.hpp> #include <Physics.h>
#include <Random.h>
struct Color #include <Color.h>
{
Color() = default;
Color(float r_in, float g_in, float b_in, float a_in = 1.0f)
: r(r_in)
, g(g_in)
, b(b_in)
, a(a_in)
{ }
Color(sf::Color color_in)
: r((float)color_in.r / 255.f)
, g((float)color_in.g / 255.f)
, b((float)color_in.b / 255.f)
, a((float)color_in.a / 255.f)
{ }
float r{};
float g{};
float b{};
float a{};
sf::Color sfml()
{
return sf::Color{uint8_t(r * 255), uint8_t(g * 255), uint8_t(b * 255), uint8_t(a * 255)};
}
float* imgui()
{
return &r;
}
};
sf::Vector2f getOverlap(sf::FloatRect first, sf::FloatRect second);
sf::Vector2f velocityInRandomDir(float speed_in);
sf::Vector2f velocityInDirection(float speed_in, sf::Angle angle_in);

27
src/Color.cpp Normal file
View File

@ -0,0 +1,27 @@
#include <Color.h>
#include <SFML/Graphics.hpp>
Color::Color(float r_in, float g_in, float b_in, float a_in = 1.0f)
: r(r_in)
, g(g_in)
, b(b_in)
, a(a_in)
{ }
Color::Color(sf::Color color_in)
: r(color_in.r / 255.f)
, g(color_in.g / 255.f)
, b(color_in.b / 255.f)
, a(color_in.a / 255.f)
{ }
sf::Color Color::sfml()
{
return sf::Color{uint8_t(r * 255), uint8_t(g * 255), uint8_t(b * 255), uint8_t(a * 255)};
}
float* Color::imgui()
{
return &r;
}

View File

@ -2,18 +2,18 @@
#include <vector> #include <vector>
#include <Util.h> #include <Util.h>
#include <Random.h>
#include <SFML/Graphics.hpp> #include <SFML/Graphics.hpp>
#include <imgui-SFML.h> #include <imgui-SFML.h>
#include <imgui.h> #include <imgui.h>
#include <algorithm> #include <algorithm>
#include <fstream>
#include <iostream> #include <iostream>
Ball::Ball(sf::Vector2f position_in, sf::Vector2f vel_in) Ball::Ball(sf::Vector2f position_in, sf::Vector2f vel_in)
: velocity(vel_in) : pos(position_in)
, pos(position_in) , velocity(vel_in)
{ } { }
Brick::Brick(sf::Vector2f position_in) Brick::Brick(sf::Vector2f position_in)
@ -28,13 +28,19 @@ Player::Player(sf::Vector2f position_in)
Game::Game() Game::Game()
: window({sf::VideoMode({ 1920u, 1080u }), "breakout"}) : window({sf::VideoMode({ 1920u, 1080u }), "breakout"})
{ {
window.setFramerateLimit(frameRate);
if (!ImGui::SFML::Init(window)) return; if (!ImGui::SFML::Init(window)) return;
if (!parseConfigFile()) return;
window.setFramerateLimit(framerate);
player.pos = playerStartPos; player.pos = playerStartPos;
playerHalfSize = playerSize / 2.f;
brickHalfSize = brickSize / 2.f;
tempCircle.setOrigin({ballRadius, ballRadius}); tempCircle.setOrigin({ballRadius, ballRadius});
ballMaxSpeed /= numPhysicsUpdates;
bricks.reserve(totalBricks); bricks.reserve(totalBricks);
bricks.emplace_back(sf::Vector2f{200, 100}); bricks.emplace_back(sf::Vector2f{200, 100});
@ -45,6 +51,65 @@ Game::Game()
ballsToAdd.emplace_back(playerStartPos.x, playerStartPos.y - 300); ballsToAdd.emplace_back(playerStartPos.x, playerStartPos.y - 300);
} }
bool Game::parseConfigFile()
{
std::ifstream configFile{"Config/game-config.txt"};
if(!configFile)
{
std::cerr << "ERROR: CANNOT OPEN 'game-config.txt'\n";
return false;
}
std::string inputBuff;
while(configFile >> inputBuff)
{
if (inputBuff == "framerate")
configFile >> framerate;
if (inputBuff == "bricksPerRow")
configFile >> rowSize;
if (inputBuff == "ballRadius")
configFile >> ballRadius;
if (inputBuff == "playerSpeed")
configFile >> playerSpeed;
if (inputBuff == "bricksPerColumn")
configFile >> columnSize;
if (inputBuff == "specialBrickCount")
configFile >> totalSpecialBricks;
if (inputBuff == "brickSize")
configFile >> brickSize.x >> brickSize.y;
if (inputBuff == "playerSize")
configFile >> playerSize.x >> playerSize.y;
if (inputBuff == "ballColor")
configFile >> ballColor.r >> ballColor.g >> ballColor.b;
if (inputBuff == "playerStartPos")
configFile >> playerStartPos.x >> playerStartPos.y;
if (inputBuff == "brickColor")
configFile >> brickColor.r >> brickColor.g >> brickColor.b;
if (inputBuff == "playerColor")
configFile >> playerColor.r >> playerColor.g >> playerColor.b;
if (inputBuff == "specialBrickColor")
configFile >> specialBrickColor.r >> specialBrickColor.g >> specialBrickColor.b;
if (inputBuff == "ballSpeed")
configFile >> ballMaxSpeed;
}
return true;
}
void Game::input() void Game::input()
{ {
while (const std::optional event = window.pollEvent()) while (const std::optional event = window.pollEvent())
@ -77,6 +142,10 @@ void Game::input()
case sf::Keyboard::Scan::F1: case sf::Keyboard::Scan::F1:
windowCollasped = !windowCollasped; windowCollasped = !windowCollasped;
break; break;
case sf::Keyboard::Scan::R:
resetGame();
break;
default: default:
break; break;
@ -106,11 +175,12 @@ void Game::input()
{ {
switch (MouseButtonPressed->button) switch (MouseButtonPressed->button)
{ {
case sf::Mouse::Button::Left: case sf::Mouse::Button::Left:
specialBricks.emplace_back((sf::Vector2f)MouseButtonPressed->position); specialBricks.emplace_back((sf::Vector2f)MouseButtonPressed->position);
break; break;
default:
break; default:
break;
} }
} }
@ -145,8 +215,8 @@ void Game::checkBallCollision()
for (auto& brick : bricks) for (auto& brick : bricks)
{ {
const sf::FloatRect brickBounds = {brick.pos, brickHalfSize}; const sf::FloatRect brickBounds = {brick.pos, brickHalfSize};
auto intersect = getOverlap(ballBounds, brickBounds); const auto intersect = getOverlap(ballBounds, brickBounds);
auto previousIntersect = getOverlap(previousBallBounds, brickBounds); const auto previousIntersect = getOverlap(previousBallBounds, brickBounds);
if (intersect.x > 0 && previousIntersect.x <= 0 && intersect.y > 0) if (intersect.x > 0 && previousIntersect.x <= 0 && intersect.y > 0)
{ {
@ -252,8 +322,8 @@ void Game::checkBallCollision()
const sf:: FloatRect playerBounds = {player.pos, playerHalfSize}; const sf:: FloatRect playerBounds = {player.pos, playerHalfSize};
const sf:: FloatRect previousPlayerBounds = {player.previousPos, playerHalfSize}; const sf:: FloatRect previousPlayerBounds = {player.previousPos, playerHalfSize};
auto intersect = getOverlap(ballBounds, playerBounds); const auto intersect = getOverlap(ballBounds, playerBounds);
auto previousIntersect = getOverlap(previousBallBounds, previousPlayerBounds); const auto previousIntersect = getOverlap(previousBallBounds, previousPlayerBounds);
// coming from x direction // coming from x direction
if (intersect.x > 0 && previousIntersect.x <= 0 && intersect.y > 0) if (intersect.x > 0 && previousIntersect.x <= 0 && intersect.y > 0)
@ -294,9 +364,9 @@ void Game::updateEntities()
const auto limit = ballsToAdd.size(); const auto limit = ballsToAdd.size();
for (int i = 0; i < limit; i++) for (size_t i = 0; i < limit; i++)
{ {
balls.emplace_back(ballsToAdd[i], velocityInRandomDir(ballMaxSpeed / numPhysicsUpdates)); balls.emplace_back(ballsToAdd[i], velocityInRandomDir(ballMaxSpeed));
ballsToAdd[i] = {0,0}; ballsToAdd[i] = {0,0};
} }
@ -326,7 +396,7 @@ void Game::movement()
ball.pos += ball.velocity; ball.pos += ball.velocity;
} }
int dir = player.right - player.left; const int dir = player.right - player.left;
player.previousPos = player.pos; player.previousPos = player.pos;
player.pos.x += (playerSpeed / numPhysicsUpdates) * dir; player.pos.x += (playerSpeed / numPhysicsUpdates) * dir;
@ -334,7 +404,6 @@ void Game::movement()
void Game::imgui() void Game::imgui()
{ {
ImGui::SFML::Update(window, clock.restart());
ImGui::Begin("menu"); ImGui::Begin("menu");
ImGui::SetWindowCollapsed(windowCollasped); ImGui::SetWindowCollapsed(windowCollasped);
@ -356,7 +425,7 @@ void Game::imgui()
ImGui::ColorEdit3("Player Color", playerColor.imgui()); ImGui::ColorEdit3("Player Color", playerColor.imgui());
ImGui::ColorEdit3("Ball Color", ballColor.imgui()); ImGui::ColorEdit3("Ball Color", ballColor.imgui());
ImGui::ColorEdit3("Brick Color", brickColor.imgui()); ImGui::ColorEdit3("Brick Color", brickColor.imgui());
ImGui::ColorEdit3("Special Brick Color", specialBrickColor.imgui()); ImGui::ColorEdit3("Special Brick Color", specialBrickColor.imgui());
ImGui::End(); ImGui::End();
} }
@ -400,13 +469,24 @@ void Game::render()
window.display(); window.display();
} }
void Game::resetGame()
{
bricks.clear();
specialBricks.clear();
balls.clear();
ballsToAdd.clear();
}
void Game::run() void Game::run()
{ {
while(window.isOpen()) while(window.isOpen())
{ {
ImGui::SFML::Update(window, clock.restart());
input(); input();
for (int i = 0; i <= numPhysicsUpdates; i++) for (size_t i = 0; i <= numPhysicsUpdates; i++)
{ {
updateEntities(); updateEntities();
@ -424,3 +504,27 @@ void Game::run()
ImGui::SFML::Shutdown(); ImGui::SFML::Shutdown();
} }
void Game::runNoImgui()
{
while(window.isOpen())
{
ImGui::SFML::Update(window, clock.restart());
input();
for (size_t i = 0; i <= numPhysicsUpdates; i++)
{
updateEntities();
movement();
collision();
}
checkEndGame();
render();
}
ImGui::SFML::Shutdown();
}

View File

@ -1,4 +1,7 @@
#include <Util.h> #include <Physics.h>
#include <SFML/Graphics.hpp>
#include <Random.h> #include <Random.h>
sf::Vector2f getOverlap(sf::FloatRect first, sf::FloatRect second) sf::Vector2f getOverlap(sf::FloatRect first, sf::FloatRect second)
@ -13,7 +16,7 @@ sf::Vector2f getOverlap(sf::FloatRect first, sf::FloatRect second)
return result; return result;
} }
sf::Vector2f velocityInRandomDir(float speed_in) sf::Vector2f velocityInRandomDir(const float speed_in)
{ {
const bool upOrDown{(bool)Random::get(0,1)}; const bool upOrDown{(bool)Random::get(0,1)};
@ -29,7 +32,7 @@ sf::Vector2f velocityInRandomDir(float speed_in)
} }
// used for debugging // used for debugging
sf::Vector2f velocityInDirection(float speed_in, sf::Angle angle_in) sf::Vector2f velocityInDirection(const float speed_in, const sf::Angle angle_in)
{ {
return sf::Vector2f{speed_in * std::cos(angle_in.asRadians()), speed_in * std::sin(angle_in.asRadians())}; return sf::Vector2f{speed_in * std::cos(angle_in.asRadians()), speed_in * std::sin(angle_in.asRadians())};
} }

View File

@ -2,6 +2,23 @@
int main(int argc, char* argv[]) int main(int argc, char* argv[])
{ {
bool useImgui{true};
Game game; Game game;
game.run();
for (int i = 0; i < argc; i++)
{
if (!strcmp(argv[i], "--noImgui"))
{
useImgui = false;
}
}
if (useImgui)
{
game.run();
}
else
{
game.runNoImgui();
}
} }