diff --git a/main.c b/main.c index 3d84b80..233aaa7 100644 --- a/main.c +++ b/main.c @@ -7,14 +7,17 @@ #define FONT_SIZE 30 +#define PLAYER_LIVES 2 #define PADDLE_SPEED 4.0 -#define PADDLE_WIDTH VIRTUAL_WIDTH / 8.0 -#define PADDLE_HEIGHT VIRTUAL_HEIGHT / 30.0 +#define PADDLE_WIDTH (VIRTUAL_WIDTH / 8.0) +#define PADDLE_HEIGHT (VIRTUAL_HEIGHT / 30.0) -#define BALL_RADIUS VIRTUAL_WIDTH / 80.0 +#define BALL_RADIUS (VIRTUAL_WIDTH / 80.0) #define BALL_BASE_SPEED 2.0f #define BALL_MUL_SPEED 0.15f +#define LEN(arr) (sizeof arr / sizeof *arr) + typedef struct Player { Rectangle shape; int lives; @@ -29,22 +32,41 @@ typedef struct Ball { bool velocityApplied; } Ball; +typedef struct Block { + Rectangle shape; + Color color; + bool isDestroyed; +} Block; + void MovePaddle(Player *player) { Vector2 mouseDelta = GetMouseDelta(); player->shape.x = Clamp(player->shape.x + mouseDelta.x, 0, VIRTUAL_WIDTH - PADDLE_WIDTH); } +void ResetBall(Ball *ball) { + ball->velocityMultiplier = 1.0f; + // Resetting ball's position + ball->velocity = (Vector2){BALL_BASE_SPEED, BALL_BASE_SPEED}; + ball->firstBounce = false; + ball->shape.x = VIRTUAL_WIDTH / 2.0f; + ball->shape.y = VIRTUAL_HEIGHT / 2.0f; +} + void MoveBall(Ball *ball, Player *player) { bool isColliding = CheckCollisionRecs(player->shape, ball->shape); - if (ball->shape.x - BALL_RADIUS < 0 || ball->shape.x + BALL_RADIUS > VIRTUAL_WIDTH) { + if (ball->shape.x < 0 || ball->shape.x + BALL_RADIUS > VIRTUAL_WIDTH) { ball->velocity = Vector2Multiply(ball->velocity, (Vector2){-1.0f, 1.0f}); ball->velocityApplied = false; - } else if (ball->shape.y - BALL_RADIUS < 0) { + } else if (ball->shape.y < 0) { ball->velocity = Vector2Multiply(ball->velocity, (Vector2){1.0f, -1.0f}); ball->velocityApplied = false; } else if (isColliding) { - ball->velocity = Vector2Multiply(ball->velocity, (Vector2){1.0f, -1.0f}); + float direction = 1 - (ball->shape.x + (BALL_RADIUS / 2.0f)) / (player->shape.x + (PADDLE_WIDTH / 2.0f) + 1); + float forceX = 1.0f; // direction > 0 ? 1.0f : -1.0f; + float forceY = -1.0f; // + (direction * 10.0); + TraceLog(LOG_INFO, "%f %f %f", direction, forceX, forceY); + ball->velocity = Vector2Multiply(ball->velocity, (Vector2){forceX, forceY}); // Add speed multiplier every bounce to increase difficulty if (!ball->velocityApplied) { @@ -63,10 +85,7 @@ void MoveBall(Ball *ball, Player *player) { // Death or Game Over if (player->lives > 0) { player->lives -= 1; - ball->velocityMultiplier = 1.0f; - // Resetting ball's position - ball->shape.x = VIRTUAL_WIDTH / 2.0f; - ball->shape.y = VIRTUAL_HEIGHT / 2.0f; + ResetBall(ball); } else { } ball->velocityApplied = false; @@ -91,7 +110,6 @@ int main() { SetTargetFPS(60); Camera2D camera = {0}; // Game world camera - // camera.offset = (Vector2){SCREEN_WIDTH / 2.0f, SCREEN_HEIGHT / 2.0f}; camera.zoom = 1.0f; const RenderTexture2D RENDER_TEXTURE = LoadRenderTexture(VIRTUAL_WIDTH, VIRTUAL_HEIGHT); @@ -108,24 +126,68 @@ int main() { }; Player player = { - (Rectangle){VIRTUAL_WIDTH / 2.0f, VIRTUAL_HEIGHT - PADDLE_HEIGHT - 10, PADDLE_WIDTH, PADDLE_HEIGHT}, 3, 0}; + (Rectangle){VIRTUAL_WIDTH / 2.0f, VIRTUAL_HEIGHT - PADDLE_HEIGHT - 10, PADDLE_WIDTH, PADDLE_HEIGHT}, + PLAYER_LIVES, 0}; + + const int BLOCK_ROWS = 7; + const int BLOCKS_PER_ROW = 15; + const int BLOCK_WIDTH = VIRTUAL_WIDTH / (float)BLOCKS_PER_ROW; + const int BLOCK_HEIGHT = 20; + Block blocks[BLOCK_ROWS * BLOCKS_PER_ROW]; + + for (int i = 0; i < BLOCK_ROWS; i++) { + for (int j = 0; j < BLOCKS_PER_ROW; j++) { + int id = i + (j * BLOCK_ROWS); + int blockX = j * (BLOCK_WIDTH + 1); + int blockY = 10 + i * (BLOCK_HEIGHT + 1); + + int hue = (id % BLOCK_ROWS) * 400; + Color color = ColorFromHSV(hue, 1.0f, 1.0f); + + blocks[id] = (Block){(Rectangle){blockX, blockY, BLOCK_WIDTH, BLOCK_HEIGHT}, color, false}; + } + } + + const int BLOCK_COUNT = LEN(blocks); while (!WindowShouldClose()) { + if (IsKeyDown(KEY_R)) { + ResetBall(&ball); + } + // Keep before the cursor is disabled otherwise the paddle is stuck MovePaddle(&player); DisableCursor(); MoveBall(&ball, &player); - // TraceLog(LOG_INFO, "%.0fx%.0f", ball.shape.x, ball.shape.y); BeginTextureMode(RENDER_TEXTURE); { ClearBackground(BLACK); DrawRectangleRec(ball.shape, RAYWHITE); + // DrawRectangle(ball.shape.x + BALL_RADIUS / 2.0f, ball.shape.y + BALL_RADIUS / 2.0f, 5, 5, RED); DrawRectangleRec(player.shape, RAYWHITE); + // DrawRectangle(player.shape.x + PADDLE_WIDTH / 2.0f, player.shape.y, 5, 5, RED); + + for (int i = 0; i < BLOCK_COUNT; i++) { + Block *block = &blocks[i]; + if (block->isDestroyed) { + continue; + } + + bool isColliding = CheckCollisionRecs(ball.shape, block->shape); + if (isColliding) { + ball.velocity = Vector2Multiply(ball.velocity, (Vector2){1.0f, -1.0f}); + block->color = BLACK; + block->isDestroyed = true; + player.score += 100; + } + + DrawRectangleRec(block->shape, block->color); + } } EndTextureMode();