I'm hitting a wall with the last few steps of breakout, so all help appreciated.
When the pre-written updateScoreboard function is called (after the ball hits a brick), the program freezes and I get a segmentation fault (core dumped). Here's my code.
Also more generally, how does one go about debugging a segmentation fault? Is there any way to get hints about what's going wrong?
// prototypes
void initBricks(GWindow window);
GOval initBall(GWindow window);
GRect initPaddle(GWindow window);
GLabel initScoreboard(GWindow window);
void updateScoreboard(GWindow window, GLabel label, int points);
GObject detectCollision(GWindow window, GOval ball);
GLabel scoreboard;
int main(void)
{
// seed pseudorandom number generator
srand48(time(NULL));
// instantiate window
GWindow window = newGWindow(WIDTH, HEIGHT);
// instantiate bricks
initBricks(window);
// instantiate ball, centered in middle of window
GOval ball = initBall(window);
// instantiate paddle, centered at bottom of window
GRect paddle = initPaddle(window);
// instantiate scoreboard, centered in middle of window, just above ball
GLabel label = initScoreboard(window);
// number of bricks initially
int bricks = COLS * ROWS;
// number of lives initially
int lives = LIVES;
// number of points initially
int points = 0;
// initial velocity
double velocity_x = drand48() * 2;
double velocity_y = 2;
// keep playing until game over
while (lives > 0 && bricks > 0)
{
// tracks cursor
GEvent event = getNextEvent(MOUSE_EVENT);
// detect collision
GObject object = detectCollision(window, ball);
// move ball
move(ball, velocity_x, velocity_y);
// bounce off left or right edge of window
if ((getX(ball) + getWidth(ball) >= WIDTH) || (getX(ball) <= 0))
{
velocity_x = -velocity_x;
}
// bounce off top or bottom edge of window
if (getY(ball) <= 0)
{
velocity_y = -velocity_y;
}
// pause game and lose life if hits bottom edge
if (getY(ball) + getHeight(ball) >= HEIGHT)
{
lives--;
// pause the game untill mouse click, move ball to center
waitForClick();
addAt(window, ball, (WIDTH / 2) - RADIUS, (HEIGHT / 2) - RADIUS );
}
// if object is hit
if (object != NULL)
{
// bounce object off paddle
if (object == paddle)
{
if (velocity_y > 0)
velocity_y = -velocity_y;
}
// bounce object off of bricks and delete bricks
else if (strcmp(getType(object), "GRect") == 0)
{
removeGWindow(window, object);
velocity_y = -velocity_y;
points++;
updateScoreboard(window, scoreboard, points);
}
}
// linger before moving again
pause(10);
if (event != NULL)
{
// ensure paddle follows cursor
double x = getX(event) - (PADDLE_WIDTH / 2);
setLocation(paddle, x, HEIGHT - PADDLE_HEIGHT - 60);
}
}
// wait for click before exiting
waitForClick();
// game over
closeGWindow(window);
return 0;
}
/**
* Initializes window with a grid of bricks.
*/
void initBricks(GWindow window)
{
// build rows of bricks
int spacer = (WIDTH / (COLS + 1)) / COLS;
int brick_width = WIDTH / (COLS + 1);
char* color[] = {"RED", "ORANGE", "YELLOW", "GREEN", "BLUE"};
for (int n = 0, ybrick = 30; n < ROWS; n++, ybrick = ybrick + 23)
{
for (int i = 0, xbrick = 2 * spacer; i < COLS; i++, xbrick = xbrick + brick_width + spacer)
{
// instantiate a brick
GRect brick = newGRect(xbrick, ybrick, brick_width, 15);
setFilled(brick, true);
setColor(brick, color[n]);
add(window, brick);
}
}
}
/**
* Instantiates ball in center of window. Returns ball.
*/
GOval initBall(GWindow window)
{
// Instantiates ball
GOval ball = newGOval((WIDTH / 2) - RADIUS, (HEIGHT / 2) - RADIUS, RADIUS * 2, RADIUS * 2);
setFilled(ball, true);
add(window, ball);
return ball;
}
/**
* Instantiates paddle in bottom-middle of window.
*/
GRect initPaddle(GWindow window)
{
// instantiates paddle
GRect paddle = newGRect((WIDTH - PADDLE_WIDTH) / 2, HEIGHT - PADDLE_HEIGHT - 60, PADDLE_WIDTH, PADDLE_HEIGHT);
// fills paddle
setFilled(paddle, true);
// adds paddle to window
add(window, paddle);
return paddle;
}
/**
* Instantiates, configures, and returns label for scoreboard.
*/
GLabel initScoreboard(GWindow window)
{
// Instantiates scoreboard
GLabel scoreboard = newGLabel("");
setFont(scoreboard, "SanSerif-36");
add(window, scoreboard);
setLocation(scoreboard, (getWidth(window) - getWidth(scoreboard)) / 2, (getHeight(window) - getHeight(scoreboard)) / 2);
setLabel(scoreboard, "0");
return scoreboard;
}
/**
* Updates scoreboard's label, keeping it centered in window.
*/
void updateScoreboard(GWindow window, GLabel label, int points)
{
// update scoreboard
char s[12];
sprintf(s, "%i", points);
setLabel(label, s);
// center label in window
double x = (getWidth(window) - getWidth(label)) / 2;
double y = (getHeight(window) - getHeight(label)) / 2;
setLocation(label, x, y);
}
/**
* Detects whether ball has collided with some object in window
* by checking the four corners of its bounding box (which are
* outside the ball's GOval, and so the ball can't collide with
* itself). Returns object if so, else NULL.
*/
GObject detectCollision(GWindow window, GOval ball)
{
// ball's location
double x = getX(ball);
double y = getY(ball);
// for checking for collisions
GObject object;
// check for collision at ball's top-left corner
object = getGObjectAt(window, x, y);
if (object != NULL)
{
return object;
}
// check for collision at ball's top-right corner
object = getGObjectAt(window, x + 2 * RADIUS, y);
if (object != NULL)
{
return object;
}
// check for collision at ball's bottom-left corner
object = getGObjectAt(window, x, y + 2 * RADIUS);
if (object != NULL)
{
return object;
}
// check for collision at ball's bottom-right corner
object = getGObjectAt(window, x + 2 * RADIUS, y + 2 * RADIUS);
if (object != NULL)
{
return object;
}
// no collision
return NULL;
}