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

View File

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

View File

@ -26,13 +26,16 @@ Player::Player(sf::Vector2f position_in)
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 (!parseConfigFile()) return;
lives.setPosition({10, static_cast<float>(window.getSize().y - 40)});
window.setFramerateLimit(framerate);
player.pos = playerStartPos;
@ -43,12 +46,49 @@ Game::Game()
ballMaxSpeed /= numPhysicsUpdates;
bricks.reserve(totalBricks);
bricks.emplace_back(sf::Vector2f{200, 100});
specialBricks.reserve(totalSpecialBricks);
balls.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()
@ -67,17 +107,14 @@ bool Game::parseConfigFile()
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 == "brickCount")
configFile >> totalBricks;
if (inputBuff == "specialBrickCount")
configFile >> totalSpecialBricks;
@ -107,6 +144,9 @@ bool Game::parseConfigFile()
configFile >> ballMaxSpeed;
}
if (totalSpecialBricks > totalBricks)
totalSpecialBricks = totalBricks;
return true;
}
@ -176,7 +216,7 @@ void Game::input()
switch (MouseButtonPressed->button)
{
case sf::Mouse::Button::Left:
specialBricks.emplace_back((sf::Vector2f)MouseButtonPressed->position);
//specialBricks.emplace_back((sf::Vector2f)MouseButtonPressed->position);
break;
default:
@ -218,16 +258,17 @@ void Game::checkBallCollision()
const auto intersect = getOverlap(ballBounds, brickBounds);
const auto previousIntersect = getOverlap(previousBallBounds, brickBounds);
// coming from x directon
if (intersect.x > 0 && previousIntersect.x <= 0 && intersect.y > 0)
{
brick.alive = false;
ball.velocity.x *= -1;
if (ball.pos.x < brick.pos.x)
{
{// from the left
ball.pos.x -= intersect.x;
}
else
{
{// from the right
ball.pos.x += intersect.x;
}
}
@ -238,11 +279,11 @@ void Game::checkBallCollision()
brick.alive = false;
ball.velocity.y *= -1;
if (ball.pos.y < brick.pos.y)
{
{// from the top
ball.pos.y -= intersect.y;
}
else
{
{// from the bottom
ball.pos.y += intersect.y;
}
}
@ -262,11 +303,11 @@ void Game::checkBallCollision()
spawnExtraBall = true;
ball.velocity.x *= -1;
if (ball.pos.x < brick.pos.x)
{
{// from the left
ball.pos.x -= intersect.x;
}
else
{
{// from the right
ball.pos.x += intersect.x;
}
}
@ -278,11 +319,11 @@ void Game::checkBallCollision()
spawnExtraBall = true;
ball.velocity.y *= -1;
if (ball.pos.y < brick.pos.y)
{
{// from the top
ball.pos.y -= intersect.y;
}
else
{
{// from the bottom
ball.pos.y += intersect.y;
}
}
@ -293,7 +334,6 @@ void Game::checkBallCollision()
}
}
//wall collide
if (ballBounds.position.y + ballBounds.size.y > window.getSize().y)
{
@ -378,13 +418,15 @@ void Game::checkEndGame()
if (balls.empty())
{
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)
{
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::SetWindowCollapsed(windowCollasped);
ImGui::SetWindowCollapsed(true);
ImGui::Text("Controls:");
ImGui::Indent();
ImGui::Text("A/D or arrow keys: move left and right");
@ -434,6 +476,8 @@ void Game::render()
{
window.clear();
lives.setString("Lives: " + std::to_string(player.lives));
window.draw(lives);
tempRect.setOrigin(brickHalfSize);
tempRect.setSize(brickSize);
for (auto& brick : bricks)
@ -476,6 +520,7 @@ void Game::resetGame()
balls.clear();
ballsToAdd.clear();
setupLevel();
}
void Game::run()
@ -510,6 +555,7 @@ void Game::runNoImgui()
while(window.isOpen())
{
ImGui::SFML::Update(window, clock.restart());
input();
for (size_t i = 0; i <= numPhysicsUpdates; i++)