Hello all,

I am writing a Breakout type game in C++ and I've come across a problem.

I've drawn the bricks, bat, and a ball to the screen as well as programmed the movement of the bat and ball, however, collision detection is kicking my butt. I've looked up sample source code and tried to implement it into my own with no results. Can anyone take a look at my code and give me some pointers please.

#include <iostream>
#include <string>
using namespace std;
#include <SDL.h>

const int screenWidth = 640;
const int screenHeight = 480;
const int ballSize = 10;
const int batWidth = 60;
const int batHeight = 10;
const int brickWidth = 60;
const int brickHeight = 10;
int score = 0;

class CApp
{
public:
    CApp()
    {
        m_bulletImage = SDL_LoadBMP("bullet.bmp");
    }
    ~CApp()
    {
        SDL_FreeSurface(m_bulletImage);
    }
    SDL_Surface* m_bulletImage;
};

CApp* app = NULL;

class CBall
{
public:
    CBall()
    {
        m_x= 0;
        m_y= 0;
        m_velx= 2;
        m_vely = 2;
    }
    virtual ~CBall() 
    {
    }
    void randomize()
    {
        m_x = (float)(rand()%(screenWidth-10));
        m_y = (float) (rand()%(screenHeight-10));
        m_velx = (float) ((rand()%2001)-1000)/1000.0f;
        m_vely = (float) ((rand()%2001)-1000)/1000.0f;
    }
    void getRect(SDL_Rect& rect)
    {
        rect.x = (int) m_x;
        rect.y = (int) m_y;
        rect.w = app->m_bulletImage->w;
        rect.h = app->m_bulletImage->h;
    }
    virtual void draw(SDL_Surface* screen)
    {    
        SDL_Rect rect;
        getRect(rect);
        SDL_BlitSurface(app->m_bulletImage,NULL,screen,&rect);
        //SDL_FillRect(screen,&rect,SDL_MapRGB(screen->format,0,255,0));
    }
    virtual void move()
    {
        m_x += m_velx;
        m_y += m_vely;
        if (m_y<0)
        {
            m_y =0;
            m_vely = -m_vely;
        }
        if (m_x<0) 
        {
            m_x =0;
            m_velx = -m_velx;
        }
        if (m_y>screenHeight-ballSize) 
        {
            m_y = screenHeight-ballSize;
            m_vely = -m_vely;
        }
        if (m_x>screenWidth-ballSize) 
        {
            m_x = screenWidth-ballSize;
            m_velx = -m_velx;
        }
    }
    float m_x;
    float m_y;
    float m_velx;
    float m_vely;

    SDL_Surface* m_image;
};

class CBat
{
public:
    CBat()
    {
        m_x=0;
        m_y=440;
    }
    void getRect(SDL_Rect& rect)
    {
        rect.x = m_x;
        rect.y = m_y;
        rect.w = batWidth;
        rect.h = batHeight;
    }
    void move()
    {
        SDL_Event event;
        while (SDL_PollEvent(&event))
        {
            switch (event.type)
            {
                case SDL_MOUSEMOTION:
                case SDL_MOUSEBUTTONDOWN:
                {
                    SDL_MouseButtonEvent* mEvent = 
                        (SDL_MouseButtonEvent*)&event;
                    m_x = mEvent->x;
                    break;
                }
            }
        }
        if (m_x<0) m_x =0;
        if (m_x>screenWidth-batWidth) m_x = screenWidth-batWidth;
    }
    void draw(SDL_Surface* screen)
    {
        SDL_Rect rect;
        rect.x = m_x;
        rect.y = m_y;
        rect.w = batWidth;
        rect.h = batHeight;

        SDL_FillRect(screen,&rect,SDL_MapRGB(screen->format,0,0,255));
    }

    int m_x;
    int m_y;
};

class CBrick
{
public:
    CBrick()
    {
        m_x=50;
        m_y=50;
    }

    void getRect(SDL_Rect& rect)
    {
        rect.x = m_x;
        rect.y = m_y;
        rect.w = brickWidth;
        rect.h = brickHeight;
    }

    void draw(SDL_Surface* screen)
    {
        SDL_Rect rect;
        rect.x = m_x + 10;
        rect.y = m_y + 5;
        rect.w = brickWidth;
        rect.h = brickHeight;

        SDL_FillRect(screen,&rect,SDL_MapRGB(screen->format,255,255,0));
    }

    int m_x;
    int m_y;


};
/** Make it so you have a ball bouncing around the screen. You can 
just draw your ball as a block for the time being.

Your ball should have position an (x,y) coordinate, and velocity.
Each time step you should change your balls position by the 
velocity.

ie

ballX += ballVelX;
ballY += ballVelY;

Thats how it moves under its own steam!

When the ball hits the edge of the screen you need to push the ball
back onto the screen (like with the player) and negate the velocity 
in the appropriate direction. If it hits the left or right edges
of the screen you negate x velocity, and similarly for the top 
or bottom you negate the v velocity.
*/

/** Wrap up your ball functionality into a class.
Your class will need at least 2 methods. 
1) To update the balls position
2) To render the ball 

Why make the ball a class?
It will simplify main greatly
It will make it simple to have loads of balls 
*/

bool collides(const SDL_Rect& a,const SDL_Rect& b)
{
    if ((a.x > b.x + b.w)||
            (a.y > b.y + b.h)||
            (b.x > a.x + a.w)||
            (b.y > a.y + a.h)) return false;
    return true;
}

int main(int argc,char* argv[])
{
    if (SDL_Init(SDL_INIT_VIDEO) <0)
    {
        cout << "Unable to init SDL:"<<SDL_GetError();
        return -1;
    }

    CApp theApp;
    app = &theApp;

    SDL_Surface* screen = SDL_SetVideoMode(screenWidth,screenHeight,32,SDL_SWSURFACE);
    bool bQuit = false;

    int lastTime = SDL_GetTicks();


    // Initalizes a bat, ball, and bricks
    CBat bat1;
    CBall ball;
    CBrick brick[100];


    // Draws the bricks to the screen
    for (int x=0;x<10;x++)
    {
        for (int y=0;y<10;y++)
        {
            int brickno = y * 10 + x;
            brick[brickno].m_x = x * (brickWidth + 2);
            brick[brickno].m_y = y * (brickHeight + 2);
        }
    }

    ball.randomize();

    while (!bQuit)
    {
        // Rendering part of the game
        SDL_FillRect(screen,NULL,SDL_MapRGB(screen->format,0,0,0));

        bat1.draw(screen);        
        ball.draw(screen);
        for (int i=0; i < 100; i++)
        {
            brick[i].draw(screen);
        }

        // Update part of the game

        int currentTime = SDL_GetTicks();

        int x=0;
        int y=0;

        while (currentTime-lastTime>10)
        {
            SDL_Event event;

            bat1.move();
            ball.move();
            
            SDL_Rect bat1Rect;
            bat1.getRect(bat1Rect);

            SDL_Rect ballRect;
            ball.getRect(ballRect);

            if (collides(ballRect,bat1Rect)&&
                ball.m_vely>0)
            {
                ball.m_vely = -ball.m_vely;
            }

            lastTime += 10;
        }

        SDL_UpdateRect(screen,0,0,640,480);
    }


    return 0;
}

Recommended Answers

All 2 Replies

I've added this bit of code:

SDL_Rect brickRect;
            brick->getRect(brickRect);

            if (collides(ballRect,bat1Rect)&&
                ball.m_vely>0)
            {
                ball.m_vely = -ball.m_vely;
            }

            if (collides(ballRect,brickRect))
            {
                ball.m_vely = -ball.m_vely;
            }

but it is only detecting collision with the top left brick. What am I doing wrong????

Please be a bit more specific, since this is nor pure C++ but SDL mixed along with it, and also due to the lengthy code it becomes difficult for us to pin point the problem.

What exactly happens, does the ball go through the bricks, what do you mean by the collision occurs only with the top brick , which part of your code is concerned with collision ( mark it with red or blue ) ?

Be a bit more specific.

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.