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;
}