Fixed collision detection (game-breaking bug)
Fixed an issue with the ball occasionally clipping through the paddle/bricks or bouncing from a position inside the paddle/bricks This should never happen, as the ball should be updated to move in a different direction if the ball is clipping in the next frame This was being caused by a rounding error in the vertexWithinQuad function, where adding the compared volumes introduced a small imprecision and meant the test volume and original volume were not always exactly equal Cast the two areas as integers when comparing, such that only a discrepancy > 1px would be considered a collision (perfect since we are ultimately rendering bitmaps). Could also be solved by adding a percentage margin of error or increasing precision (both more costly)
This commit is contained in:
parent
a40944d189
commit
589b989b36
@ -175,8 +175,8 @@ int main(void) {
|
||||
* ----------------
|
||||
*/
|
||||
|
||||
char subSteps = 3; // Draw every N+1 frames, thereby calculating movement more precisely
|
||||
int targetFPS = 144; // Limit FPS to this value, to stop unneccessary calculations
|
||||
char subSteps = 2; // Draw every N+1 frames, thereby calculating movement more precisely
|
||||
int targetFPS = 60; // Limit FPS to this value, to stop unneccessary calculations
|
||||
|
||||
char moveX=0;
|
||||
|
||||
@ -192,8 +192,8 @@ int main(void) {
|
||||
ball theBall = {
|
||||
.x = 0,
|
||||
.y = 0,
|
||||
.vX = 0.4f,
|
||||
.vY = -3.0f,
|
||||
.vX = 1.5f,
|
||||
.vY = -5.0f,
|
||||
.initVX = theBall.vX,
|
||||
.initVY = theBall.vY,
|
||||
.radius = 4,
|
||||
@ -225,7 +225,6 @@ int main(void) {
|
||||
Uint32 tickrate=SDL_GetTicks()-timer;
|
||||
timer=SDL_GetTicks();
|
||||
int fps=1000/(tickrate+1);
|
||||
//printf("Time to draw: %u, fps: %i \r", tickrate, fps); fflush(stdout);
|
||||
|
||||
/*
|
||||
* ----------------
|
||||
@ -337,7 +336,7 @@ char vertexWithinQuad(coord point, coord *quad) {
|
||||
testArea += heronsFormula(point, quad[1], quad[2]);
|
||||
testArea += heronsFormula(point, quad[2], quad[3]);
|
||||
testArea += heronsFormula(point, quad[3], quad[0]);
|
||||
if (testArea == quadArea) {
|
||||
if ((int)testArea == (int)quadArea) {
|
||||
return 1;
|
||||
} else {
|
||||
return 0;
|
||||
@ -353,39 +352,44 @@ void updatePaddle(Uint32 tickrate, paddle *thePaddle, char moveX, int winWidth,
|
||||
void updateBall(Uint32 tickrate, ball *theBall, paddle *thePaddle, int winWidth, int winHeight, brick *bricks, int brickCount) {
|
||||
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);
|
||||
double paddleRY = 20 - (double)(winHeight / 2);
|
||||
|
||||
coord paddle[4] = {
|
||||
{.x = paddleRX, .y = paddleRY },
|
||||
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)
|
||||
// (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]) };
|
||||
if (vertexWithinQuad(ballN, paddle)) colliding = 1;
|
||||
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;
|
||||
|
||||
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
|
||||
} else if (theBall->x - theBall->radius > paddleRX + thePaddle->width) { // Right side collision
|
||||
theBall->vX *= -1.0;
|
||||
}
|
||||
else {
|
||||
} else { // Top or bottom collision
|
||||
theBall->vY *= -1.0;
|
||||
theBall->vX = ((ballNX - paddleRX - (double)(thePaddle->width / 2)) / ((double)thePaddle->width / 2))*0.5; // Sets X velocity to be proportional to the relative position of the ball and the paddle on collision
|
||||
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
|
||||
@ -429,6 +433,8 @@ void updateBall(Uint32 tickrate, ball *theBall, paddle *thePaddle, int winWidth,
|
||||
}
|
||||
}
|
||||
|
||||
// Collision with window boundaries
|
||||
|
||||
if (ballNX > winWidth / 2 || ballNX < (-1.0*winWidth/2)) { // Collision with walls
|
||||
theBall->vX *= -1.0;
|
||||
}
|
||||
@ -442,6 +448,8 @@ void updateBall(Uint32 tickrate, ball *theBall, paddle *thePaddle, int winWidth,
|
||||
theBall->vY = theBall->initVY;
|
||||
}
|
||||
|
||||
// Update the ball's position
|
||||
|
||||
theBall->x += theBall->vX * 0.1 * tickrate;
|
||||
theBall->y += theBall->vY * 0.1 * tickrate;
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user