added basic level loading and proper player life system

This commit is contained in:
Joseph Aquino 2025-09-23 23:00:51 -04:00
parent 110af2c12a
commit 0fc6c50009
3 changed files with 80 additions and 33 deletions

View File

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

View File

@ -69,10 +69,14 @@ private:
bool parseConfigFile(); bool parseConfigFile();
void setupLevel();
private: private:
sf::Clock clock; sf::Clock clock;
sf::RenderWindow window; sf::RenderWindow window;
sf::Font font;
sf::Text lives;
Player player; Player player;
std::vector<Ball> balls; std::vector<Ball> balls;
@ -88,10 +92,8 @@ private:
sf::Vector2f playerStartPos{}; sf::Vector2f playerStartPos{};
sf::Vector2f brickHalfSize{}; sf::Vector2f brickHalfSize{};
sf::Vector2f playerHalfSize{}; sf::Vector2f playerHalfSize{};
int rowSize{}; unsigned int totalSpecialBricks{};
int columnSize{}; unsigned int totalBricks{};
int totalSpecialBricks{};
int totalBricks{rowSize * columnSize};
unsigned int framerate{}; unsigned int framerate{};
float playerSpeed{}; float playerSpeed{};
float ballRadius{}; float ballRadius{};
@ -102,4 +104,5 @@ private:
Color specialBrickColor{}; Color specialBrickColor{};
bool windowCollasped{false}; bool windowCollasped{false};
static constexpr unsigned int numPhysicsUpdates{4}; static constexpr unsigned int numPhysicsUpdates{4};
}; };

View File

@ -26,13 +26,16 @@ Player::Player(sf::Vector2f position_in)
Game::Game() Game::Game()
: window({sf::VideoMode({ 1920u, 1080u }), "breakout"}) : window({sf::VideoMode({ 1920u, 1080u }), "project-breakout"})
, font("assets/fonts/ChakraPetch-Regular.ttf")
, lives(font)
{ {
if (!ImGui::SFML::Init(window)) return; if (!ImGui::SFML::Init(window)) return;
if (!parseConfigFile()) return; if (!parseConfigFile()) return;
lives.setPosition({10, static_cast<float>(window.getSize().y - 40)});
window.setFramerateLimit(framerate); window.setFramerateLimit(framerate);
player.pos = playerStartPos; player.pos = playerStartPos;
@ -43,12 +46,49 @@ Game::Game()
ballMaxSpeed /= numPhysicsUpdates; ballMaxSpeed /= numPhysicsUpdates;
bricks.reserve(totalBricks); bricks.reserve(totalBricks);
bricks.emplace_back(sf::Vector2f{200, 100});
specialBricks.reserve(totalSpecialBricks); specialBricks.reserve(totalSpecialBricks);
balls.reserve(10); balls.reserve(10);
ballsToAdd.reserve(10); ballsToAdd.reserve(10);
ballsToAdd.emplace_back(playerStartPos.x, playerStartPos.y - 300); setupLevel();
ballsToAdd.emplace_back(playerStartPos.x, playerStartPos.y - 50);
}
void Game::setupLevel()
{
const unsigned int specialBrickInterval = totalBricks / totalSpecialBricks;
constexpr float xSpacing = 20.f;
constexpr float ySpacing = 20.f;
const float xOffset = brickSize.x + xSpacing;
const float yOffset = brickSize.y + ySpacing;
const unsigned int numRows = window.getSize().x / xOffset;
const unsigned int numColumns = (window.getSize().y - 300)/ yOffset;
unsigned int row{};
unsigned int column{};
for (size_t i = 0; i < totalBricks; i++)
{
if (row >= numRows)
{
row = 0;
column++;
}
if (column >= numColumns)
break;
if (i % specialBrickInterval == 0)
{
specialBricks.emplace_back(sf::Vector2f{(row * xOffset) + xSpacing + brickHalfSize.x, (column * yOffset) + ySpacing + brickHalfSize.y});
}
else
{
bricks.emplace_back(sf::Vector2f{(row * xOffset) + xSpacing + brickHalfSize.x, (column * yOffset) + ySpacing + brickHalfSize.y});
}
row++;
}
} }
bool Game::parseConfigFile() bool Game::parseConfigFile()
@ -67,17 +107,14 @@ bool Game::parseConfigFile()
if (inputBuff == "framerate") if (inputBuff == "framerate")
configFile >> framerate; configFile >> framerate;
if (inputBuff == "bricksPerRow")
configFile >> rowSize;
if (inputBuff == "ballRadius") if (inputBuff == "ballRadius")
configFile >> ballRadius; configFile >> ballRadius;
if (inputBuff == "playerSpeed") if (inputBuff == "playerSpeed")
configFile >> playerSpeed; configFile >> playerSpeed;
if (inputBuff == "bricksPerColumn") if (inputBuff == "brickCount")
configFile >> columnSize; configFile >> totalBricks;
if (inputBuff == "specialBrickCount") if (inputBuff == "specialBrickCount")
configFile >> totalSpecialBricks; configFile >> totalSpecialBricks;
@ -107,6 +144,9 @@ bool Game::parseConfigFile()
configFile >> ballMaxSpeed; configFile >> ballMaxSpeed;
} }
if (totalSpecialBricks > totalBricks)
totalSpecialBricks = totalBricks;
return true; return true;
} }
@ -176,7 +216,7 @@ 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: default:
@ -218,16 +258,17 @@ void Game::checkBallCollision()
const auto intersect = getOverlap(ballBounds, brickBounds); const auto intersect = getOverlap(ballBounds, brickBounds);
const auto previousIntersect = getOverlap(previousBallBounds, brickBounds); const auto previousIntersect = getOverlap(previousBallBounds, brickBounds);
// coming from x directon
if (intersect.x > 0 && previousIntersect.x <= 0 && intersect.y > 0) if (intersect.x > 0 && previousIntersect.x <= 0 && intersect.y > 0)
{ {
brick.alive = false; brick.alive = false;
ball.velocity.x *= -1; ball.velocity.x *= -1;
if (ball.pos.x < brick.pos.x) if (ball.pos.x < brick.pos.x)
{ {// from the left
ball.pos.x -= intersect.x; ball.pos.x -= intersect.x;
} }
else else
{ {// from the right
ball.pos.x += intersect.x; ball.pos.x += intersect.x;
} }
} }
@ -238,11 +279,11 @@ void Game::checkBallCollision()
brick.alive = false; brick.alive = false;
ball.velocity.y *= -1; ball.velocity.y *= -1;
if (ball.pos.y < brick.pos.y) if (ball.pos.y < brick.pos.y)
{ {// from the top
ball.pos.y -= intersect.y; ball.pos.y -= intersect.y;
} }
else else
{ {// from the bottom
ball.pos.y += intersect.y; ball.pos.y += intersect.y;
} }
} }
@ -262,11 +303,11 @@ void Game::checkBallCollision()
spawnExtraBall = true; spawnExtraBall = true;
ball.velocity.x *= -1; ball.velocity.x *= -1;
if (ball.pos.x < brick.pos.x) if (ball.pos.x < brick.pos.x)
{ {// from the left
ball.pos.x -= intersect.x; ball.pos.x -= intersect.x;
} }
else else
{ {// from the right
ball.pos.x += intersect.x; ball.pos.x += intersect.x;
} }
} }
@ -278,11 +319,11 @@ void Game::checkBallCollision()
spawnExtraBall = true; spawnExtraBall = true;
ball.velocity.y *= -1; ball.velocity.y *= -1;
if (ball.pos.y < brick.pos.y) if (ball.pos.y < brick.pos.y)
{ {// from the top
ball.pos.y -= intersect.y; ball.pos.y -= intersect.y;
} }
else else
{ {// from the bottom
ball.pos.y += intersect.y; ball.pos.y += intersect.y;
} }
} }
@ -293,7 +334,6 @@ void Game::checkBallCollision()
} }
} }
//wall collide //wall collide
if (ballBounds.position.y + ballBounds.size.y > window.getSize().y) if (ballBounds.position.y + ballBounds.size.y > window.getSize().y)
{ {
@ -378,13 +418,15 @@ void Game::checkEndGame()
if (balls.empty()) if (balls.empty())
{ {
player.lives--; player.lives--;
ballsToAdd.emplace_back(sf::Vector2f{player.pos.x, player.pos.y - 500}); ballsToAdd.emplace_back(sf::Vector2f{player.pos.x, player.pos.y - 50});
} }
if (player.lives <= 0) if (player.lives <= 0)
{ {
player.lives = 3;
resetGame();
ballsToAdd.emplace_back(sf::Vector2f{player.pos.x, player.pos.y - 50});
} }
} }
@ -406,7 +448,7 @@ void Game::imgui()
{ {
ImGui::Begin("menu"); ImGui::Begin("menu");
ImGui::SetWindowCollapsed(windowCollasped); ImGui::SetWindowCollapsed(true);
ImGui::Text("Controls:"); ImGui::Text("Controls:");
ImGui::Indent(); ImGui::Indent();
ImGui::Text("A/D or arrow keys: move left and right"); ImGui::Text("A/D or arrow keys: move left and right");
@ -434,6 +476,8 @@ void Game::render()
{ {
window.clear(); window.clear();
lives.setString("Lives: " + std::to_string(player.lives));
window.draw(lives);
tempRect.setOrigin(brickHalfSize); tempRect.setOrigin(brickHalfSize);
tempRect.setSize(brickSize); tempRect.setSize(brickSize);
for (auto& brick : bricks) for (auto& brick : bricks)
@ -476,6 +520,7 @@ void Game::resetGame()
balls.clear(); balls.clear();
ballsToAdd.clear(); ballsToAdd.clear();
setupLevel();
} }
void Game::run() void Game::run()
@ -510,6 +555,7 @@ void Game::runNoImgui()
while(window.isOpen()) while(window.isOpen())
{ {
ImGui::SFML::Update(window, clock.restart()); ImGui::SFML::Update(window, clock.restart());
input(); input();
for (size_t i = 0; i <= numPhysicsUpdates; i++) for (size_t i = 0; i <= numPhysicsUpdates; i++)