0

As the title says the detectCollision function is working properly but the ball is not bouncing off the paddle. I stuck on a printf in the "if(object == paddle)" func and it shows that it is detecting the collion, but the ball's velocity is not being reversed as instructed. I am at a loss, especially since it bounces off the brick no problem.

//
// breakout.c
//
// Computer Science 50
// Problem Set 3
//

// standard libraries
#define _XOPEN_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>

// Stanford Portable Library
#include <spl/gevents.h>
#include <spl/gobjects.h>
#include <spl/gwindow.h>

// height and width of game's window in pixels
#define HEIGHT 600
#define WIDTH 400

// number of rows of bricks
#define ROWS 5

// number of columns of bricks
#define COLS 10

// radius of ball in pixels
#define RADIUS 10

// lives
#define LIVES 3

// paddle
#define PADDLE_WIDTH 70
#define PADDLE_HEIGHT 20
#define PADDLE_X 160
#define PADDLE_Y 550

// 1st brick location
#define BRICK_X (SPACE / 2)
#define BRICK_Y 100

// height and width of brick
#define BRICK_W ((WIDTH - (SPACE * (COLS))) / COLS)
#define BRICK_H ((HEIGHT / 10) / ROWS)

// space size
#define SPACE 5

// number of rows of bricks
#define ROWS 5

// number of columns of bricks
#define COLS 10

// ball height and width
#define BALL_W 50
#define BALL_H 50

// Ball Initial Velocity 
#define BALL_V_X 2.3
#define BALL_V_Y 2.7



// 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);

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;

    // Ball initial velocity
    double velocity_x = BALL_V_X;
    double velocity_y = BALL_V_Y;

    // keep playing until game over
    while (lives > 0 && bricks > 0)
    {

        // Listen of mouse move
        GActionEvent move_paddle = getNextEvent(MOUSE_EVENT);

        if(move_paddle != NULL)
        {
            if(getEventType(move_paddle) == MOUSE_MOVED)
            {
                // Move Paddle
                double x = getX(move_paddle) - (PADDLE_WIDTH / 2);
                double y = PADDLE_Y;
                setLocation(paddle, x, y);        
            }
        }

        // Move Ball
        move(ball, velocity_x, velocity_y);

        // detect collision
        GObject object = detectCollision(window, ball);

        if (object != NULL)
        {
            if (object == paddle)
            {
                velocity_y = -velocity_y;
                printf("you hit paddle\n");
            }
            else if (strcmp(getType(object), "GRect") == 0)
            {
                velocity_y = -velocity_y;
                printf("you hit brick\n");
            }
            else if (strcmp(getType(object), "GLabel") == 0)
            {
                //TODO ignore?
            }
        }     
        // bounce off sides    
        if(getX(ball) >= (WIDTH - BALL_W))
        {
            velocity_x = -velocity_x;
        }
        if(getX(ball) <= 0)
        {
            velocity_x = -velocity_x;
        }

        // TODO when ball hits ground, undo comments
        if(getY(ball) >= (HEIGHT - BALL_H))
        {
            velocity_y = -velocity_y; 
            printf("you hit the ground\n"); 
        }

        pause (20);
    }     

    // wait for click before exiting
    waitForClick();

    // game over
    closeGWindow(window);
    return 0;
}

/**
 * Initializes window with a grid of bricks.
 */
void initBricks(GWindow window)
{    
    for(int j = 0; j < ROWS; j++)
    {
        for(int i = 0; i < COLS; i++)
        {            
            GRect brick = newGRect(BRICK_X + (BRICK_W * i) + (SPACE * i), (BRICK_Y + (BRICK_H * j) + (SPACE * j)), BRICK_W, BRICK_H);
            if (j == 0)
            {
            setColor(brick, "Red");
            }
            if (j == 1)
            {
            setColor(brick, "Orange");
            }
            if (j == 2)
            {
            setColor(brick, "Yellow");
            }            
            if (j == 3)
            {
            setColor(brick, "Green");
            }            
            if (j == 4)
            {
            setColor(brick, "Cyan");
            }

            setFilled(brick, true);
            add(window, brick);          
        }
    }

}

/**
 * Instantiates ball in center of window.  Returns ball.
 */
GOval initBall(GWindow window)
{
    GOval ball = newGOval((((WIDTH - BALL_W)) / 2), (((HEIGHT - BALL_H)) / 2), BALL_W, BALL_H);
    add(window, ball);

    return ball;
}

/**
 * Instantiates paddle in bottom-middle of window.
 */
GRect initPaddle(GWindow window)
{   
    GRect paddle = newGRect(PADDLE_X, PADDLE_Y, PADDLE_WIDTH, PADDLE_HEIGHT);
    setColor(paddle, "BLUE");
    setFilled(paddle, true);

    add(window, paddle);

    return paddle;
}

/**
 * Instantiates, configures, and returns label for scoreboard.
 */
GLabel initScoreboard(GWindow window)
{
    // TODO
    return NULL;
}

/**
 * Updates scoreboard's label, keeping it centered in window.
 */
void updateScoreboard(GWindow window, GLabel label, int points)
{
    // update label
    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;
}

// Remove brick when hit
//void removeGWindow(GWindow gw, GObject gobj)
//{
    //TODO
//}
0

Your problem might be here:

// TODO when ball hits ground, undo comments
        if(getY(ball) >= (HEIGHT - BALL_H)

Your ball will "hit" the paddle when getY(ball) at 550 (PADDLE_Y). With HEIGHT set to 600 and BALL_H set to 50, getY(ball) will always be >= (HEIGHT - BALL_H). So it's going to execute the "ball hits the ground" code and velocity_y = -velocity_y; which flips y again.

  • That's for when the ball hits the ground (still unfinished) not the paddle. The detect collision with paddle is a few line above that. if(object == paddle) And as I've said, the actual detection works as proven by the printf I stuck on,, it says you've hit the paddle, but the ball continues through it instead of bouncing off. – CS50_on_the_go Dec 16 '15 at 8:42
  • I've edited the answer. You are flipping velocity_y a second time in the "hits the ground" code. – DinoCoderSaurus Dec 17 '15 at 1:22
  • Yea, that's not it. I just did that so that I didn't have to reset the program everytime it hit the ground. The code was a work in progress and it was just there temporarily. Either way I deleted it and tried it out just in case, it wasn't it. My guess is it has to have been something to do with scope but I just can't figure it out what's off. – CS50_on_the_go Dec 17 '15 at 9:00
0

@DinoCoderSaurus - Your comment made me review my code, specifically paying attention to the position of the paddle and ball. I realized that I created a BALL_H and BALL_W instead of using the radius already given in the PSET. There was a misalignment since some of the code was using the RADIUS and others were using the BALL_H and BALL_W. But your comment made me experiment by moving up the paddle high enough the ball would completely clear it before hitting the ground, what happened was that it bounced when it was halfway through the paddle, which pointed me to the real problem. Thanks for the comment, wouldn't of figured it out without it!

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .