I'm encountering an issue with my Brick Breaker game project. When the game ends, that is, when the number of clicks exceeds 10, a button appears and I exit. However, when I restart the game after exiting, the ball starts moving again according to the mouse position where I clicked the button or the position of the last click. However, this movement is not counted as a click.
Below, I've provided a summary including relevant code snippets from main.cpp and ball.cpp files. In the updateBall() function in ball.cpp, the position of the ball is updated based on mouse input. However, even when isGameOver is true, the position of the ball continues to be updated, leading to unexpected behavior.
If it's not enough here is Github Repo: https://github.com/OnurSevkiOkan/breakout-raylib (Im not sure is it okay to share github link, im new at stackoverflow :) )
main.cpp =>
#include <raylib.h>
#include <iostream>
#include <variables.h>
#include "ball.h"
#include "bricks.h"
#include "title_screen.h"
#include "gameplay_screen.h"
Ball ball;
Bricks brick;
TITLE_SCREEN title_screen;
GAMEPLAY_SCREEN gameplay_screen;
typedef enum GameScreen { LOGO = 0, TITLE, GAMEPLAY, ENDING } GameScreen;
int main(void)
{
GameScreen currentScreen = TITLE;
int framesCounter = 0;
bool isPlayButtonInitialized = false;
bool isExitButtonInitialized = false;
bool isGameOver = false;
InitWindow(SCREEN_WIDTH, SCREEN_HEIGHT, "Brick Breaker"); // Defines a window.
SetTargetFPS(target_FPS); // Sets the FPS to 60.
// Ininitalize bricks.
brick.InitializeBricks();
while (!WindowShouldClose())
{
switch (currentScreen)
{
case TITLE:
{
int button_state = title_screen.getBtnState();
if (button_state == 2)
{
currentScreen = GAMEPLAY;
ball.setBallPosition();
isGameOver = false;
}
} break;
case GAMEPLAY:
{
if (click_counter > 10)
{
isGameOver = true;
}
int ExitButton_State = gameplay_screen.getExitBtnState();
if (isExitButtonInitialized == true)
{
gameplay_screen.drawExitButton();
}
if (ExitButton_State == 2)
{
currentScreen = ENDING;
ball.setBallPosition();
brick.resetBricks();
}
} break;
case ENDING:
{
if (IsKeyPressed(KEY_ENTER) || IsGestureDetected(GESTURE_TAP))
{
currentScreen = TITLE;
}
} break;
default: break;
}
BeginDrawing();
ClearBackground(RAYWHITE);
switch (currentScreen)
{
case TITLE:
{
title_screen.drawPlayButton();
title_screen.drawTexts();
// Load play button texture when entering the title screen
if (!isPlayButtonInitialized && currentScreen == TITLE)
{
title_screen.initPlayButton();
isPlayButtonInitialized = true;
}
} break;
case GAMEPLAY:
{
brick.create_brick(ball);
ball.drawBall();
// To prevent the ball position change when the button is clicked
if (click_counter <= 10 && isGameOver == false && brick.isAllBricksGone() == false)
{
ball.updateBall();
}
ball.drawScore();
if (brick.isAllBricksGone() == true)
{
ball.setBallPosition();
DrawText("CONGRATULATIONS!", GetScreenWidth() / 2 - 150, GetScreenHeight() / 2 - 50, 30, WHITE);
if (!isExitButtonInitialized && currentScreen == GAMEPLAY)
{
gameplay_screen.initExitButton();
isExitButtonInitialized = true;
}
}
if (click_counter > 10)
{
isGameOver = true;
ball.setBallPosition();
DrawText("HaHaHaHA LOOOSER B!TCHES", GetScreenWidth() / 2 - 200, GetScreenHeight() / 2 - 50, 30, WHITE);
if (!isExitButtonInitialized && currentScreen == GAMEPLAY)
{
gameplay_screen.initExitButton();
isExitButtonInitialized = true;
}
}
} break;
case ENDING:
{
if (isExitButtonInitialized && currentScreen == ENDING)
{
gameplay_screen.unloadExitButtonTexture();
isExitButtonInitialized = false;
click_counter = 0;
}
DrawRectangle(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT, BLUE);
DrawText("ENDING SCREEN", 20, 20, 40, DARKBLUE);
DrawText("PRESS ENTER or TAP to RETURN to TITLE SCREEN", 120, 220, 20, DARKBLUE);
} break;
default: break;
}
EndDrawing();
}
// Unload resources
return 0;
}
ball.cpp =>
#include "ball.h"
#include <raylib.h>
#include <math.h>
#include "variables.h"
#include "title_screen.h"
#include <string>
#include <bricks.h>
TITLE_SCREEN ts;
Vector2 ball_position = { 300, 750 }; // Initial ball position.
Texture2D ball_texture; // Texture for the ball.
Bricks bricks;
Vector2 cursorPos;
// Velocity vector for ball movement
Vector2 ball_velocity = { 0, 0 };
void Ball::InitializeTexture()
{
// Load the ball texture.
ball_texture = LoadTexture("resources/ball.png");
}
Rectangle buttonBounds = ts.getButtonBounds();
void Ball::drawBall()
{
ClearBackground(BLACK);
DrawLine(0, 760, GetScreenWidth(), 760, RED);
/*DrawTexturePro(ball_texture, Rectangle{0, 0, (float)ball_texture.width, (float)ball_texture.height},
Rectangle{ ball_position.x, ball_position.y, 30, 30 }, // Adjust the size as needed
Vector2{ 15, 15 }, 90, WHITE); // Apply rotation
*/
DrawCircle(ball_position.x, ball_position.y, 10, WHITE);
}
void Ball::updateBall()
{
static bool clicked = false;
// Update ball position
if (IsMouseButtonPressed(MOUSE_BUTTON_LEFT) && !clicked)
{
Vector2 cursorPos = GetMousePosition();
clicked = true;
ball_velocity.x = cursorPos.x - ball_position.x;
ball_velocity.y = cursorPos.y - ball_position.y;
float magnitude = sqrt(ball_velocity.x * ball_velocity.x + ball_velocity.y * ball_velocity.y);
if (magnitude != 0) {
ball_velocity.x /= magnitude;
ball_velocity.y /= magnitude;
}
// Set the velocity based on the normalized direction
ball_velocity.x *= BALL_SPEED;
ball_velocity.y *= BALL_SPEED;
click_counter++;
}
if (clicked)
{
// Update the ball position with the velocity
ball_position.x += ball_velocity.x * GetFrameTime();
ball_position.y += ball_velocity.y * GetFrameTime();
// Check collision with vertical edges of the screen and reverse direction if needed
if (ball_position.x >= GetScreenWidth() - ball_texture.width || ball_position.x <= 0)
{
ball_velocity.x *= -1;
}
// Check collision with horizontal edges of the screen and reverse direction if needed
if (ball_position.y <= 0)
{
ball_velocity.y *= -1;
}
if (ball_position.y >= GetScreenHeight() - ball_texture.height - 150)
{
ball_position = {300,750};
clicked = false;
}
}
}
//These functions used to control ball from bricks.cpp
Vector2 Ball::getPosition()
{
return ball_position;
}
Vector2 Ball::getSpeed() {
return ball_velocity;
}
float Ball::getSpeedX()
{
return ball_velocity.x;
}
float Ball::getSpeedY()
{
return ball_velocity.y;
}
void Ball::setSpeed(Vector2 speed) // Used to change direction when there is a collision.
{
ball_velocity = speed;
}
void Ball::deleteTexture() // Unloads texture if you use one.
{
UnloadTexture(ball_texture);
}
void Ball::drawScore()
{
std::string scoreText = "Click Time: ";
// std::string scoreText = std::to_string(click_counter);
scoreText.append(std::to_string(click_counter));
DrawText(scoreText.c_str(), GetScreenWidth() / 2 - 65, GetScreenHeight() / 2 - 420, 20, WHITE);
}
void Ball::setBallPosition()
{
ball_position = { 300,750 };
}
I tried adding isGameOver checks but i still can't fix the problem when player reachs the maximum click amount(10).
I solved the problem with changing the velocity of ball to {0,0}.
I created a function that resets the ball and called it when isGameOver is equal to true:
void Ball::resetBall()
{
ball_position = { 300, 750 }; // Reset ball position
ball_velocity = { 0, 0 }; // Reset ball velocity
clicked = false; // Reset click flag
}