Archived

This topic is now archived and is closed to further replies.

2D Breakout collision problem

This topic is 5265 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

Yo, Since I consider 2d collision detection one of my weak spots, I decided to code a Breakout game but I''ve run into problems. I''ve been following this tutorial, for a simple rectangle overlap collision (1st bit of code) I''ve intergrated it with my code successfully. However, the ball''s current behaviour is that it bounces off the bat correctly, but about 1.5 units (roughly the height of the bat) above the bat. After seeing several other examples, I was wondering, should I take into account the ball speed? Here''s some useful code. Note that I check for collision after I update the ball, and that both are called every frame.
bool BatBallCollide(BBALL *ball,BBAT* bat)
{
 float left1,left2;
 float right1,right2;
 float top1,top2;
 float bottom1,bottom2;
 
 left1=ball->GetX();
 right1=left1+ball->GetWidth();
 top1=ball->GetY();
 bottom1=top1+ball->GetHeight();
 
 left2=bat->GetX();
 right2=left2+bat->GetWidth();
 top2=bat->GetY();
 bottom2=top2+bat->GetHeight();
 
 if (bottom1<top2) return false;
 if (top1>bottom2) return false;
 
 if (right1<left2) return false;
 if (left1>right2) return false;
 
 return true;
}
And my current updating/rendering function:
void RenderScene()
{
ball.Update();
bat.Update(); 

if (BatBallCollide(&ball,&bat))
{
 ball.SetYDir(-ball.GetYDir());
}

glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glLoadIdentity();

DrawBlocks();
ball.Draw();
bat.Draw();
}
Cheers for any help CloudNine

Share this post


Link to post
Share on other sites
I''ve thought some time now about making a Breakout clone myself, and have figured out a way of doing col detection (I''m not sure if it would work, but it seems ok to me). I would have a bool array with all of the pixels of the playscreen, with either 1 for a pixel that contains a wall/brick/bat, or 0 for empty. Every time the ball moves, a function checks if any of the pixels in the ball overlap the mentioned array. If they do, I move the ball back again, find the average coordinate of those pixels that overlapped...whatever it was..., find the angle between the middle of the ball and that coordinate (which would then be the angle between the ball and the wall/brick/bat), and through this equation:

newAngle = wallAngle + (wallAngle - oldAngle) + 180

I find the new direction of the ball.

For example, I have a ball that is 16x16 pixels. I find that pixels (7, 0) and (8, 0) collide with something. The direction of the ball is 60 degrees (0 degrees is to the right), or straight upwards. The average coordinate will be (7.5, 0), and the angle between this and the middle (7.5, 7.5) is 90.

newAngle = 90 + (90 - 60) + 180 = 300.

I hope I made myself clear, any questions are welcome.

Share this post


Link to post
Share on other sites
This is how I detect collisions in my old version of breakout


import java.awt.*;

public class collisions
{

make_layout mk_layout;
drawStick my_stick;
drawBall my_ball;
breakout ping;
drawMap map_it;

boolean init,check_hit;
int[] priority = {0,2,4,6,1,3,5,7};

/**********************************/
/* priority */
/* 4 */
/* 3 __ 5 */
/* / \ */
/* 2 |ball| 6 */
/* \__/ */
/* 1 7 */
/* 0 */
/**********************************/
int xRange,yRange,
e,count_tiles,
right_b,y_limit;

collisions(breakout ping){
this.ping = ping;
}

public void manage_coll(){

if(!init){
mk_layout = ping.layout;
my_stick = ping.my_stick;
my_ball = ping.my_ball;
map_it = ping.map_it;
right_b = ping.getSize().width -ping.radius;
y_limit = ping.yLimit-ping.radius;
count_tiles =0;
init = true;
}

check_hit = false;

switch((xRange=(my_ball.xCoords[6]-2)/(map_it.width +2))){
case 0: xRange = 1; break;
case 13: xRange = 12;break;
}

for(int a =0; a<map_it.rows; a++)
for(int i=xRange-1; i<xRange+1; i++){
if(map_it.exist<A href=''http://[i]!=0)

for(int s =0; s<8; s++){
e = priority[s];
if(my_ball.xCoords[e] >= map_it.xTiles[a][i])
if(my_ball.xCoords[e] <= map_it.xTiles[a][i] + map_it.width)
if(my_ball.yCoords[e] >= map_it.yTiles[a][i])
if(my_ball.yCoords[e] <= map_it.yTiles[a][i] + map_it.height){

switch(e){
case 0: my_ball.ball_ySpeed = -abs(my_ball.ball_ySpeed); break;
case 1: my_ball.ball_ySpeed = -abs(my_ball.ball_ySpeed);
my_ball.ball_xSpeed = abs(my_ball.ball_xSpeed); break;
case 2: my_ball.ball_xSpeed = abs(my_ball.ball_xSpeed); break;
case 3: my_ball.ball_ySpeed = abs(my_ball.ball_ySpeed);
my_ball.ball_xSpeed = abs(my_ball.ball_xSpeed); break;
case 4: my_ball.ball_ySpeed = abs(my_ball.ball_ySpeed); break;
case 5: my_ball.ball_ySpeed = abs(my_ball.ball_ySpeed);
my_ball.ball_xSpeed = -abs(my_ball.ball_xSpeed); break;
case 6: my_ball.ball_xSpeed = -abs(my_ball.ball_xSpeed); break;
case 7: my_ball.ball_ySpeed = -abs(my_ball.ball_ySpeed);
my_ball.ball_xSpeed = -abs(my_ball.ball_xSpeed); break;
}

map_it.exist[a][i]-= 1;
if(map_it.exist[a][i] <=0){
mk_layout.my_score +=10;
count_tiles++;
ping.clip[0].play();
}
else
ping.clip[1].play();

i = xRange+1;
a = map_it.rows;
s = 8;
}
}
}

if(my_ball.xBall <= ping.radius){
my_ball.ball_xSpeed = abs(my_ball.ball_xSpeed);
ping.clip[1].play();
}

if(my_ball.xBall >= right_b){
my_ball.ball_xSpeed = -abs(my_ball.ball_xSpeed);
ping.clip[1].play();
}

if(my_ball.yBall <= ping.radius){
my_ball.ball_ySpeed = abs(my_ball.ball_ySpeed);
ping.clip[1].play();
}

if(my_ball.yBall >=y_limit){
my_ball.ball_ySpeed = -abs(my_ball.ball_ySpeed);

if(my_ball.num_of_balls>0){
my_ball.num_of_balls--;
lose_scene();
if(my_ball.num_of_balls!=0)
ping.clip[2].play();
}
if(my_ball.num_of_balls==0)
ping.clip[3].play();
}

if(my_ball.xBall >= my_stick.stick_xLocation)
if(my_ball.xBall <= my_stick.stick_xLocation +my_stick.stick_width)
if(my_ball.yCoords[0] >= my_stick.stick_yLocation )
if(my_ball.yCoords[0] <= my_stick.stick_yLocation + (ping.radius>>1)){
my_ball.ball_ySpeed = -(int)(2 + 2*Math.random());

if(my_ball.ball_xSpeed<0)
my_ball.ball_xSpeed = -abs((int)(2 + 2*Math.random()));
else
my_ball.ball_xSpeed = abs((int)(2 + 2*Math.random()));
ping.clip[1].play();
}

if(count_tiles == map_it.score_limit)
ping.load_new_map();

my_ball.yBall+= my_ball.ball_ySpeed;
my_ball.xBall+= my_ball.ball_xSpeed;
}

public int abs(int a){
return (a>0) ? a : -a;
}

public void lose_scene(){
my_stick.stick_xLocation = my_stick.stick_xLocation_init;
my_ball.xBall = my_ball.xBall_init;
my_ball.yBall = my_ball.yBall_init;
ping.start = false;
mk_layout.start.enable();
mk_layout.pause.disable();
}
}



http://www.realityflux.com/abba/Breakout.html

Keep in mind that this was my very early attempt to clone the said game, now I can substitue all that cheating with real physics

Share this post


Link to post
Share on other sites
It looks like I''ll have to start storing the angle of the ball.

I''m using OpenGL, without an orthonogal matrix, so I''m not sure if I can check for pixels on a screen, without using glCopyTex2D and going through all the pixels on that texture.

It''s turning out to be harder than it looks.

CloudNine

Share this post


Link to post
Share on other sites
quote:
Original post by CloudNine
It looks like I'll have to start storing the angle of the ball.

I'm using OpenGL, without an orthonogal matrix, so I'm not sure if I can check for pixels on a screen, without using glCopyTex2D and going through all the pixels on that texture.

It's turning out to be harder than it looks.

CloudNine


I don't know OpenGL much (I'll be using SDL), but I don't think it would be necessary to do that. Instead, you can make the array while you are loading the level, and just remove the block and bar/bat's pixels as you destroy blocks and move the bat. I think that would be fast enough.

The reason why I didn't want just the 45, 135, 225 and 315 angles for my ball is that my bar/bat/whatever you call it will have rounded edges, like this:

/^^^^^^\
\________/

So if the ball hits the edge, it will get a more steep or gentle angle.
I'll store the x and y coordinates of the ball in a float and use cos/sin angle to calculate the new position each time it moves.

[edited by - Goldfish on August 17, 2003 6:48:49 AM]

Share this post


Link to post
Share on other sites
In that case, my way of doing it will just be more complicated and CPU-demanding. Consider having such a feature, though, ''cos I think it''ll look much cooler

Check out Arkanoid 2, it''s a really cool Breakout clone.

Share this post


Link to post
Share on other sites
I'll check it out sometime

I don't really understand why it works like that. Is there anything really wrong with the code?

It might be that I'll have to get the absolute value of both collision positions. I'll try that and see if it works

No such luck

I notice when I move the bat far away from the ball, the ball gets to the height of the bat, does a little jiggle and carries on in roughly the same direction.

[edited by - CloudNine on August 17, 2003 12:42:14 PM]

Share this post


Link to post
Share on other sites
It just looks like your''re up for some old-fashioned debugging. Go through the code yourself and find out what''s causing the bug.

Share this post


Link to post
Share on other sites
I made my 2d-colissionsystem as such:

Store the "radii''s" ie, the length from the center of the object to the left/right edge and from the center of the object to the top/bottom. Each frame you test the two objects radii''s against eachother, if BOTH the x and the y radii''s overlap, there is a colission. This is only for bounding boxes though but that seems to be what you want? You will get pixel-perfect colissions with this unless the speed is so great the ball will "move through" the bat.

This also eliminates this error:



|-------|
| |
|----------------|
| | | |
| | | |
| | | |
|----------------|
| |
|-------|



Ok these objects got no vertices inside eachother, some systems would not recognize a colission in this.

Share this post


Link to post
Share on other sites