129 lines
5.4 KiB
C
129 lines
5.4 KiB
C
#ifdef _WIN32
|
|
#include <SDL.h>
|
|
#else
|
|
#include <SDL2/SDL.h>
|
|
#endif
|
|
#include "include/structs.h"
|
|
#include "include/utilityFunctions.h"
|
|
|
|
void updatePaddle(Uint32 tickrate, paddle *thePaddle, char moveX, int winWidth, int winHeight) {
|
|
thePaddle->x += moveX * 0.5 * tickrate;
|
|
if (thePaddle->x < 0 - (thePaddle->width / 2)) thePaddle->x = 0 - (thePaddle->width / 2);
|
|
if (thePaddle->x > winWidth - (thePaddle->width / 2)) thePaddle->x = winWidth - (thePaddle->width / 2);
|
|
}
|
|
|
|
void updateBall(Uint32 tickrate, ball *theBall, paddle *thePaddle, int winWidth, int winHeight, brick *bricks, int brickCount, int *playerLives) {
|
|
if (theBall->stickToPaddle == 0) {
|
|
double ballNX = theBall->x + theBall->vX * 0.1 * tickrate; // Calculates the position of the ball's centre on the next step
|
|
double ballNY = theBall->y + theBall->vY * 0.1 * tickrate;
|
|
|
|
double paddleRX = thePaddle->x - (double)(winWidth / 2); // Converts paddle X/Y to coordinates relative to the center of the window as the ball
|
|
double paddleRY = 20 - (double)(winHeight / 2); // (Default is absolute, offset from the top left corner of window)
|
|
|
|
coord paddleQ[4] = {
|
|
{ .x = paddleRX,.y = paddleRY }, // Sets up a quad (coord array) to pass to vertexWithinQuad function later
|
|
{ .x = paddleRX,.y = paddleRY - thePaddle->height },
|
|
{ .x = paddleRX + thePaddle->width,.y = paddleRY - thePaddle->height },
|
|
{ .x = paddleRX + thePaddle->width,.y = paddleRY },
|
|
};
|
|
|
|
// Collision with paddle
|
|
// (Testing each vertex of ball against paddle quad)
|
|
|
|
char colliding = 0;
|
|
int mults[4] = { -1,-1,1,1 };
|
|
|
|
for (int i = 0, j = 3; i < 4; i++, j++) {
|
|
coord ballN = { .x = ballNX + (theBall->radius*mults[i % 4]),.y = ballNY + (theBall->radius*mults[j % 4]) }; // Constructs pairs of coordinates referring to each vertex of the ball
|
|
if (vertexWithinQuad(ballN, paddleQ)) colliding = 1;
|
|
}
|
|
|
|
if (colliding) {
|
|
if (theBall->isColliding == 0) {
|
|
|
|
theBall->isColliding = 1; // This keeps track of any current attepmts to 'solve' collision
|
|
// Without this flag, if the ball ends up within another object and moving slow enough that on the next frame it has not escaped the object,
|
|
// it will repeatedly have its velocity multiplied by -1 and get stuck, effectively moving only along one axis. With this flag,
|
|
// the game will ignore subsequent collisions, until it is no longer colliding. Note this does not solve the same problem where two objects
|
|
// are very close to each other and on exiting one object it enters another, in which case the ball will move through the other objects
|
|
|
|
if (theBall->x + theBall->radius < paddleRX) { // Left side collision
|
|
theBall->vX *= -1.0;
|
|
}
|
|
else if (theBall->x - theBall->radius > paddleRX + thePaddle->width) { // Right side collision
|
|
theBall->vX *= -1.0;
|
|
}
|
|
else { // Top or bottom collision
|
|
theBall->vY *= -1.0;
|
|
theBall->vX = ((ballNX - paddleRX - (double)(thePaddle->width / 2)) / ((double)thePaddle->width / 2))*theBall->initVX; // Sets X velocity to be proportional to the relative position of the ball and the paddle on collision
|
|
}
|
|
}
|
|
else {
|
|
// Already solving a collision
|
|
}
|
|
}
|
|
else {
|
|
theBall->isColliding = 0;
|
|
}
|
|
|
|
// Collision with bricks
|
|
// (Testing each vertex of ball against every brick)
|
|
|
|
for (int i = 0; i < brickCount; i++) {
|
|
colliding = 0;
|
|
|
|
if (bricks[i].destroyed == 0) {
|
|
coord brick[4] = {
|
|
{ .x = bricks[i].x - (winWidth / 2),.y = bricks[i].y },
|
|
{ .x = bricks[i].x - (winWidth / 2),.y = bricks[i].y - bricks[i].height },
|
|
{ .x = bricks[i].x - (winWidth / 2) + bricks[i].width,.y = bricks[i].y - bricks[i].height },
|
|
{ .x = bricks[i].x - (winWidth / 2) + bricks[i].width,.y = bricks[i].y },
|
|
};
|
|
|
|
for (int j = 0, k = 3; j < 4; j++, k++) {
|
|
coord ballN = { .x = ballNX + (theBall->radius*mults[j % 4]),.y = ballNY + (theBall->radius*mults[k % 4]) };
|
|
if (vertexWithinQuad(ballN, brick)) colliding = 1;
|
|
}
|
|
|
|
if (colliding) {
|
|
if (theBall->x + theBall->radius < bricks[i].x - (winWidth / 2)) { // Left side collision
|
|
theBall->vX *= -1.0;
|
|
}
|
|
else if (theBall->x - theBall->radius > bricks[i].x - (winWidth / 2) + bricks[i].width) { // Right side collision
|
|
theBall->vX *= -1.0;
|
|
}
|
|
else {
|
|
theBall->vY *= -1.0;
|
|
}
|
|
bricks[i].destroyed = 1;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
// Collision with window boundaries
|
|
|
|
if (ballNX > winWidth / 2 || ballNX < (-1.0*winWidth / 2)) { // Collision with walls
|
|
theBall->vX *= -1.0;
|
|
}
|
|
if (ballNY > winHeight / 2) { // Collision with ceiling
|
|
theBall->vY *= -1.0;
|
|
}
|
|
if (ballNY < (-1.0*winHeight / 2)) { // Collision with floor
|
|
theBall->x = 0;
|
|
theBall->y = 0;
|
|
theBall->vX = theBall->initVX;
|
|
theBall->vY = theBall->initVY;
|
|
*playerLives -= 1;
|
|
}
|
|
|
|
// Update the ball's position
|
|
|
|
theBall->x += theBall->vX * 0.1 * tickrate;
|
|
theBall->y += theBall->vY * 0.1 * tickrate;
|
|
}
|
|
else {
|
|
theBall->x = thePaddle->x - (double)(winWidth / 2) + (thePaddle->width) / 2;
|
|
theBall->y = 26 - (double)(winHeight / 2);
|
|
}
|
|
} |