Some movement and collision improvements
parent
47f1144fa7
commit
deddb6ae98
118
main.c
118
main.c
|
|
@ -14,8 +14,14 @@
|
||||||
|
|
||||||
#define BALL_RADIUS (VIRTUAL_WIDTH / 80.0)
|
#define BALL_RADIUS (VIRTUAL_WIDTH / 80.0)
|
||||||
#define BALL_BASE_SPEED 2.0f
|
#define BALL_BASE_SPEED 2.0f
|
||||||
|
#define BALL_VELOCITY ((Vector2){BALL_BASE_SPEED, BALL_BASE_SPEED})
|
||||||
#define BALL_MUL_SPEED 0.15f
|
#define BALL_MUL_SPEED 0.15f
|
||||||
|
|
||||||
|
#define BLOCK_ROWS 7
|
||||||
|
#define BLOCKS_PER_ROW 10
|
||||||
|
#define BLOCK_WIDTH (int)rint((float)VIRTUAL_WIDTH / (float)BLOCKS_PER_ROW) - 1
|
||||||
|
#define BLOCK_HEIGHT 25
|
||||||
|
|
||||||
#define LEN(arr) (sizeof arr / sizeof *arr)
|
#define LEN(arr) (sizeof arr / sizeof *arr)
|
||||||
|
|
||||||
typedef struct Player {
|
typedef struct Player {
|
||||||
|
|
@ -38,21 +44,41 @@ typedef struct Block {
|
||||||
bool isDestroyed;
|
bool isDestroyed;
|
||||||
} Block;
|
} Block;
|
||||||
|
|
||||||
void MovePaddle(Player *player) {
|
void BlocksReset(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};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void PaddleMove(Player *player) {
|
||||||
Vector2 mouseDelta = GetMouseDelta();
|
Vector2 mouseDelta = GetMouseDelta();
|
||||||
player->shape.x = Clamp(player->shape.x + mouseDelta.x, 0, VIRTUAL_WIDTH - PADDLE_WIDTH);
|
player->shape.x = Clamp(player->shape.x + mouseDelta.x, 0, VIRTUAL_WIDTH - PADDLE_WIDTH);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ResetBall(Ball *ball) {
|
void BallReset(Ball *ball) {
|
||||||
ball->velocityMultiplier = 1.0f;
|
ball->velocityMultiplier = 1.0f;
|
||||||
// Resetting ball's position
|
ball->velocity = BALL_VELOCITY;
|
||||||
ball->velocity = (Vector2){BALL_BASE_SPEED, BALL_BASE_SPEED};
|
|
||||||
ball->firstBounce = false;
|
ball->firstBounce = false;
|
||||||
ball->shape.x = VIRTUAL_WIDTH / 2.0f;
|
ball->shape.x = VIRTUAL_WIDTH / 2.0f;
|
||||||
ball->shape.y = VIRTUAL_HEIGHT / 2.0f;
|
ball->shape.y = (VIRTUAL_HEIGHT / 2.0f) + 20.0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void MoveBall(Ball *ball, Player *player) {
|
void BallChangeVelocity(Ball *ball, Vector2 force) {
|
||||||
|
ball->velocity = Vector2Multiply(ball->velocity, force);
|
||||||
|
ball->velocity = Vector2Normalize(ball->velocity);
|
||||||
|
ball->velocity = Vector2Multiply(ball->velocity, BALL_VELOCITY);
|
||||||
|
}
|
||||||
|
|
||||||
|
void BallMove(Ball *ball, Player *player) {
|
||||||
bool isColliding = CheckCollisionRecs(player->shape, ball->shape);
|
bool isColliding = CheckCollisionRecs(player->shape, ball->shape);
|
||||||
|
|
||||||
if (ball->shape.x < 0 || ball->shape.x + BALL_RADIUS > VIRTUAL_WIDTH) {
|
if (ball->shape.x < 0 || ball->shape.x + BALL_RADIUS > VIRTUAL_WIDTH) {
|
||||||
|
|
@ -62,11 +88,15 @@ void MoveBall(Ball *ball, Player *player) {
|
||||||
ball->velocity = Vector2Multiply(ball->velocity, (Vector2){1.0f, -1.0f});
|
ball->velocity = Vector2Multiply(ball->velocity, (Vector2){1.0f, -1.0f});
|
||||||
ball->velocityApplied = false;
|
ball->velocityApplied = false;
|
||||||
} else if (isColliding) {
|
} else if (isColliding) {
|
||||||
float direction = 1 - (ball->shape.x + (BALL_RADIUS / 2.0f)) / (player->shape.x + (PADDLE_WIDTH / 2.0f) + 1);
|
float paddleCenter = player->shape.x + (PADDLE_WIDTH / 2.0f);
|
||||||
float forceX = 1.0f; // direction > 0 ? 1.0f : -1.0f;
|
float ballCenter = ball->shape.x + (BALL_RADIUS / 2.0f);
|
||||||
float forceY = -1.0f; // + (direction * 10.0);
|
|
||||||
TraceLog(LOG_INFO, "%f %f %f", direction, forceX, forceY);
|
float direction = ball->velocity.x / BALL_BASE_SPEED;
|
||||||
ball->velocity = Vector2Multiply(ball->velocity, (Vector2){forceX, forceY});
|
float boost = (ballCenter / paddleCenter) - 1.0f;
|
||||||
|
float forceX = (boost * direction) > 0 ? 1.0f : -1.0f;
|
||||||
|
float forceY = -(1.5f - (fabs(boost) * 10.0));
|
||||||
|
forceY = Clamp(forceY, -1.4f, -0.8f);
|
||||||
|
BallChangeVelocity(ball, (Vector2){forceX, forceY});
|
||||||
|
|
||||||
// Add speed multiplier every bounce to increase difficulty
|
// Add speed multiplier every bounce to increase difficulty
|
||||||
if (!ball->velocityApplied) {
|
if (!ball->velocityApplied) {
|
||||||
|
|
@ -79,13 +109,13 @@ void MoveBall(Ball *ball, Player *player) {
|
||||||
// When first bouncing off the paddle increase the speed to normal
|
// When first bouncing off the paddle increase the speed to normal
|
||||||
if (!ball->firstBounce) {
|
if (!ball->firstBounce) {
|
||||||
ball->firstBounce = true;
|
ball->firstBounce = true;
|
||||||
ball->velocityMultiplier = 1.0f;
|
ball->velocityMultiplier = 1.5f;
|
||||||
}
|
}
|
||||||
} else if (ball->shape.y + BALL_RADIUS > VIRTUAL_HEIGHT - PADDLE_HEIGHT + (BALL_RADIUS / 2.0f)) {
|
} else if (ball->shape.y + BALL_RADIUS > VIRTUAL_HEIGHT - PADDLE_HEIGHT + (BALL_RADIUS / 2.0f)) {
|
||||||
// Death or Game Over
|
// Death or Game Over
|
||||||
if (player->lives > 0) {
|
if (player->lives > 0) {
|
||||||
player->lives -= 1;
|
player->lives -= 1;
|
||||||
ResetBall(ball);
|
BallReset(ball);
|
||||||
} else {
|
} else {
|
||||||
}
|
}
|
||||||
ball->velocityApplied = false;
|
ball->velocityApplied = false;
|
||||||
|
|
@ -100,6 +130,7 @@ void MoveBall(Ball *ball, Player *player) {
|
||||||
}
|
}
|
||||||
|
|
||||||
int main() {
|
int main() {
|
||||||
|
SetConfigFlags(FLAG_VSYNC_HINT);
|
||||||
InitWindow(0, 0, "Breakout");
|
InitWindow(0, 0, "Breakout");
|
||||||
ToggleFullscreen();
|
ToggleFullscreen();
|
||||||
|
|
||||||
|
|
@ -107,7 +138,8 @@ int main() {
|
||||||
const int MONITOR_WIDTH = GetMonitorWidth(CURRENT_MONITOR);
|
const int MONITOR_WIDTH = GetMonitorWidth(CURRENT_MONITOR);
|
||||||
const int MONITOR_HEIGHT = GetMonitorHeight(CURRENT_MONITOR);
|
const int MONITOR_HEIGHT = GetMonitorHeight(CURRENT_MONITOR);
|
||||||
|
|
||||||
SetTargetFPS(60);
|
int refreshRate = GetMonitorRefreshRate(CURRENT_MONITOR);
|
||||||
|
SetTargetFPS(refreshRate);
|
||||||
|
|
||||||
Camera2D camera = {0}; // Game world camera
|
Camera2D camera = {0}; // Game world camera
|
||||||
camera.zoom = 1.0f;
|
camera.zoom = 1.0f;
|
||||||
|
|
@ -119,48 +151,35 @@ int main() {
|
||||||
|
|
||||||
Ball ball = {
|
Ball ball = {
|
||||||
(Rectangle){VIRTUAL_WIDTH / 2.0f, VIRTUAL_HEIGHT / 2.0f, BALL_RADIUS, BALL_RADIUS},
|
(Rectangle){VIRTUAL_WIDTH / 2.0f, VIRTUAL_HEIGHT / 2.0f, BALL_RADIUS, BALL_RADIUS},
|
||||||
(Vector2){BALL_BASE_SPEED, BALL_BASE_SPEED},
|
BALL_VELOCITY,
|
||||||
1.0f,
|
1.0f,
|
||||||
false,
|
false,
|
||||||
false,
|
false,
|
||||||
};
|
};
|
||||||
|
BallReset(&ball);
|
||||||
|
|
||||||
Player player = {
|
Player player = {
|
||||||
(Rectangle){VIRTUAL_WIDTH / 2.0f, VIRTUAL_HEIGHT - PADDLE_HEIGHT - 10, PADDLE_WIDTH, PADDLE_HEIGHT},
|
(Rectangle){VIRTUAL_WIDTH / 2.0f, VIRTUAL_HEIGHT - PADDLE_HEIGHT - 10, PADDLE_WIDTH, PADDLE_HEIGHT},
|
||||||
PLAYER_LIVES, 0};
|
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];
|
Block blocks[BLOCK_ROWS * BLOCKS_PER_ROW];
|
||||||
|
BlocksReset(blocks);
|
||||||
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);
|
const int BLOCK_COUNT = LEN(blocks);
|
||||||
|
int brokenBlocks = 0;
|
||||||
|
|
||||||
while (!WindowShouldClose()) {
|
while (!WindowShouldClose()) {
|
||||||
if (IsKeyDown(KEY_R)) {
|
if (IsKeyDown(KEY_R)) {
|
||||||
ResetBall(&ball);
|
BallReset(&ball);
|
||||||
|
BlocksReset(blocks);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Keep before the cursor is disabled otherwise the paddle is stuck
|
// Keep before the cursor is disabled otherwise the paddle is stuck
|
||||||
MovePaddle(&player);
|
PaddleMove(&player);
|
||||||
|
|
||||||
DisableCursor();
|
DisableCursor();
|
||||||
|
|
||||||
MoveBall(&ball, &player);
|
BallMove(&ball, &player);
|
||||||
|
|
||||||
BeginTextureMode(RENDER_TEXTURE);
|
BeginTextureMode(RENDER_TEXTURE);
|
||||||
{
|
{
|
||||||
|
|
@ -180,10 +199,37 @@ int main() {
|
||||||
|
|
||||||
bool isColliding = CheckCollisionRecs(ball.shape, block->shape);
|
bool isColliding = CheckCollisionRecs(ball.shape, block->shape);
|
||||||
if (isColliding) {
|
if (isColliding) {
|
||||||
ball.velocity = Vector2Multiply(ball.velocity, (Vector2){1.0f, -1.0f});
|
float blockCenterX = block->shape.x + (BLOCK_WIDTH / 2.0f);
|
||||||
|
float blockCenterY = block->shape.y + (BLOCK_HEIGHT / 2.0f);
|
||||||
|
|
||||||
|
float ballCenterX = ball.shape.x + (BALL_RADIUS / 2.0f);
|
||||||
|
float ballCenterY = ball.shape.y + (BALL_RADIUS / 2.0f);
|
||||||
|
|
||||||
|
Vector2 dir = {ballCenterX - blockCenterX, ballCenterY - blockCenterY};
|
||||||
|
dir = Vector2Normalize(dir);
|
||||||
|
|
||||||
|
Vector2 force = {1.0f, -1.0f};
|
||||||
|
if (dir.y < 0 && dir.y > dir.x) {
|
||||||
|
force.y = -1.0f;
|
||||||
|
} else if (dir.x > 0 && dir.x > dir.y) {
|
||||||
|
force.x = -1.0f;
|
||||||
|
}
|
||||||
|
|
||||||
|
ball.velocity = Vector2Multiply(ball.velocity, force);
|
||||||
|
ball.velocityApplied = false;
|
||||||
block->color = BLACK;
|
block->color = BLACK;
|
||||||
block->isDestroyed = true;
|
block->isDestroyed = true;
|
||||||
player.score += 100;
|
player.score += 100;
|
||||||
|
brokenBlocks += 1;
|
||||||
|
|
||||||
|
if (brokenBlocks >= BLOCK_COUNT) {
|
||||||
|
BallReset(&ball);
|
||||||
|
BlocksReset(blocks);
|
||||||
|
player.score += 1000;
|
||||||
|
brokenBlocks = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
DrawRectangleRec(block->shape, block->color);
|
DrawRectangleRec(block->shape, block->color);
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue