# Thread: Collisions -> half working...

1. ## Collisions -> half working...

I am working on making an attempt at coding the collisions for breakout/brick breaker. I have already looked at the Bouncy Ball demo from dday. However, mine differs from that as I'm testing for bounces off every side of the brick. I have the Top/Bottom working great, however, my Right/Left code doesn't seem to work at all. When moving right/left and hitting the left/right side of a brick, instead of bouncing, the ball just moves right through it...

It works like this:
If the ball is moving down, I test to see if the top + height of the ball moves past the top of a brick, if it does I test the brick's left and left+width to see if the ball is within that brick.
If the ball is moving up, I test to see if the top of the ball moves past a brick's top + height, if it does, the same test to see if it's within that bricks left/width.
If the ball is moving right, I test to see if the left + width of the ball moves past the left side of a brick, if it does, I test to see if the ball is within the bricks top and top + height.
If the ball is moving left, I test the left of the ball if and if it moves past the left + width of a brick I test the same top and top + height to see if it is within that.

Maybe I just need a second pair of eyes to spot something that I overlooked...

*For code purposes, I removed the code of hitting the paddle, bouncing off the side, and normal movement
Code:
```private bool Collision(List<Bricks> _Bricks, int newX, int newY)
{
bool Result = false;
List<int> index = new List<int>();
bool movedY = false;
bool movedX = false;
int newMovementY = 100000;
int newMovementX = 100000;
bool hitY = false;
bool hitX = false;
int hitMovementY = 10000000;
int hitMovementX = 10000000;
int newYTop = 1000000;
int newXLeft = 1000000;
bool alreadyMoved = false;
for (int i = 0; i < _Bricks.Count; i++)
{
if (_Bricks[i].Visible)
{
if (ballYDir == YDirection.Down)
{
newMovementY = newY - (_Bricks[i].Top - (Top + Height));
if ((newMovementY < newY) && (Top < _Bricks[i].Top) && (newMovementY > newY * -1)) //200 - (190 + 8 + 3) = -1 < 4 ---- 3 + -1 = 2 (movement before the collision)
{
//hit vertically
if ((Left + Width + newMovementY >= _Bricks[i].Left) && (Left < _Bricks[i].Left + _Bricks[i].Width)) //test the x-axis still to make sure this is in line
{
hitY = true;
newYTop = _Bricks[i].Top - Height;
hitMovementY = newMovementY;
if (!index.Contains(i))
index.Add(i);
}
}
}
else
{
newMovementY = (_Bricks[i].Top + _Bricks[i].Height) - (Top + newY);
if (newMovementY > newY)// 200 + 50 = 250 - (252 + - 4) = 248 ----- 200 + 50 - 248 = 2 (movement before the collision)
{
//hit vertically
if ((Left + Width + newMovementY >= _Bricks[i].Left) && (Left < _Bricks[i].Left + _Bricks[i].Width) && (newMovementY < newMovementY * -1) && (newMovementY < 0)) //test the x-axis still to make sure this is in line
{
hitY = true;
newYTop = _Bricks[i].Top + _Bricks[i].Height;
hitMovementY = newMovementY;
if (!index.Contains(i))
index.Add(i);
}
}
}
if (ballXDir == XDirection.Right)
{
newMovementX = (Left + Width - _Bricks[i].Left); //(197 + 4) - 200 = 1
if ((newMovementX < newX)  && (newMovementX > newX * -1))
{
//hit horizontally
if ((Top >= _Bricks[i].Top) && (Top + Height <= _Bricks[i].Top + _Bricks[i].Height))
{
hitX = true;
newXLeft = _Bricks[i].Left - Width;
hitMovementX = newMovementX;
if (!index.Contains(i))
index.Add(i);
}
}
}
else
{
newMovementX = (_Bricks[i].Left + _Bricks[i].Width) - (Left + newMovementX); // 202 - 4 = 188 - (139  + 50) =   -1       150 + 50 = 200 - (202 - 4) = 200 - 198 = 2
if ((newMovementX > newX) && (newMovementX < newX * -1))
{
//hit horizontally
if ((Top >= _Bricks[i].Top) && (Top + Height <= _Bricks[i].Top + _Bricks[i].Height))
{
hitX = true;
newXLeft = _Bricks[i].Left + _Bricks[i].Width;
hitMovementX = newMovementX;
if (!index.Contains(i))
index.Add(i);
}
}
}

}
}
//after testing all the bricks, move the ball accordingly
if (hitY || hitX)
{
if (hitMovementY < 0) hitMovementY *= -1;
if (hitMovementX < 0) hitMovementX *= -1;
if (hitMovementY == hitMovementX)
{
//collision detected in the same amount of pixel moves on both axis', change both y/x directions
if (!alreadyMoved)
{
alreadyMoved = true;
Top = newYTop;
if (ballYDir == YDirection.Up)
ballYDir = YDirection.Down;
else
ballYDir = YDirection.Up;
Left = newXLeft;
if (ballXDir == XDirection.Right)
ballXDir = XDirection.Left;
else
ballXDir = XDirection.Right;

Result = true;
}
}
else if (hitMovementY < hitMovementX)
{
//collision detected vertically before horizontally
if (!alreadyMoved)
{
alreadyMoved = true;
Top = newYTop;
if (ballYDir == YDirection.Up)
ballYDir = YDirection.Down;
else
ballYDir = YDirection.Up;
if (ballXDir == XDirection.Left)
Left -= hitMovementY;
else
Left += hitMovementY;
}
}
else
{
//collision detected horizontally before vertically
if (!alreadyMoved)
{
alreadyMoved = true;
Left = newXLeft;
if (ballYDir == YDirection.Up)
Top -= hitMovementX;
else
Top += hitMovementX;
if (ballXDir == XDirection.Left)
ballXDir = XDirection.Right;
else
ballXDir = XDirection.Left;
}
}
}
else
{
//attempt collision detection with paddle

//else, move the ball normally

}
//now destroy the bricks that the ball hit...
if (index.Count > 0)
{
for (int i = 0; i < index.Count; i++)
{
if (_Bricks[index[i]].Breakable)
{
//_Bricks[i].Destroy();
//_Bricks[i].Visible = false;
}
}
Result = true;
}
else
Result = false;
return Result;
}```

2. ## Re: Collisions -> half working...

That was one of the issues that I never addressed in my version. I just used the copout of IntersectsWith. What I'll do is revisit the game and try to come up with a better design and post it back here for you(and of course update my version).

3. ## Re: Collisions -> half working...

Hey dday, I was writing up a reply to this thread when you replied. You might like to know that I fiddled with it a little this morning and think I got it figured out...

Well after not coding the entire weekend, I went back to look at this with a fresh, cleared mind. I added a bunch of random bricks in my client area, so that it would be easier to debug. I noticed I had the top and top+height checking was somewhat backwards on the left/right collision methods. I switched those around and all seems to be working well so far.

Here is the modified right/left sections:
Code:
```if (ballXDir == XDirection.Right)
{
newMovementX = (Left + Width - _Bricks[i].Left); //(197 + 4) - 200 = 1
if ((newMovementX < newX)  && (newMovementX > newX * -1))
{
//hit horizontally
if ((Top + Height >= _Bricks[i].Top) && (Top <= _Bricks[i].Top + _Bricks[i].Height))
{
hitX = true;
newXLeft = _Bricks[i].Left - Width;
hitMovementX = newMovementX;
if (!index.Contains(i))
index.Add(i);
}
}
}
else
{
newMovementX = (_Bricks[i].Left + _Bricks[i].Width) - (Left + newX); // 202 - 4 = 198 - (139  + 50) =   -1       150 + 50 = 200 - (202 - 4) = 200 - 198 = 2
if ((newMovementX > newX) && (newMovementX < newX * -1))
{
//hit horizontally
if ((Top <= _Bricks[i].Top + _Bricks[i].Height) && (Top + Height >= _Bricks[i].Top))
{
hitX = true;
newXLeft = _Bricks[i].Left + _Bricks[i].Width;
hitMovementX = newMovementX;
if (!index.Contains(i))
index.Add(i);
}
}
}```
EDIT: I'm now pondering the bouncing mechanics itself. Does anyone think that there should be more to it than just inverting the x/y directions? I've played one before where the speed of the paddle when hitting the ball would help determine the speed of the ball and the angle off of the paddle. Maybe too advanced though for now...

4. ## Re: Collisions -> half working...

If anyone is interested, I figured out a way to send the ball on different angles based on where it hits the paddle. I divided the paddle into 13 sections. To preface this decision, I am originally moving the ball based on the same x and y movements: x and y both being 4 (4 pixels).

Once the paddle is divided into sections, I am testing the middle position of the ball, and wherever that lands based on the divided sections, I am switching the sectional position of the paddle and changing the x and y pixel movements. These new x and y movements are the passed into the next movement.

Code:
```//paddle collision?
int sectionWidth = (p.Width / 13);
int ballMiddle = Left + (Width / 2);
int sectionHit = 0;
if (ballYDir == YDirection.Down)
{
newMovementY = newY - (p.Top - (Top + Height));
if ((newMovementY < newY) && (Top < p.Top) && (newMovementY > newY * -1))
{
//hit vertically
if ((Left + Width + newMovementY >= p.Left) && (Left < p.Left + p.Width)) //test the x-axis still to make sure this is in line
{
hitY = true;
newYTop = p.Top - Height;
hitMovementY = newMovementY;
for (int i = 0; i < 13; i++)
{
if ((ballMiddle > p.Left + (sectionWidth * i)) && (ballMiddle < p.Left + (sectionWidth * i) + sectionWidth))
{
sectionHit = i;
break;
}
}

}
}
}
if (hitY)
{
if (!alreadyMoved)
{
alreadyMoved = true;
switch (sectionHit)
{
case 0:
ballYDir = YDirection.Up;
ballXDir = XDirection.Left;
OMBricks.toMoveX = 4;
OMBricks.toMoveY = 2;
break;
case 1:
ballYDir = YDirection.Up;
ballXDir = XDirection.Left;
OMBricks.toMoveX = 4;
OMBricks.toMoveY = 3;
break;
case 2:
ballYDir = YDirection.Up;
ballXDir = XDirection.Left;
OMBricks.toMoveX = 4;
OMBricks.toMoveY = 4;
break;
case 3:
ballYDir = YDirection.Up;
ballXDir = XDirection.Left;
OMBricks.toMoveX = 3;
OMBricks.toMoveY = 4;
break;
case 4:
ballYDir = YDirection.Up;
ballXDir = XDirection.Left;
OMBricks.toMoveX = 2;
OMBricks.toMoveY = 4;
break;
case 5:
ballYDir = YDirection.Up;
ballXDir = XDirection.Left;
OMBricks.toMoveX = 1;
OMBricks.toMoveY = 4;
break;
case 6:
ballYDir = YDirection.Up;
ballXDir = XDirection.Left;
OMBricks.toMoveX = 0;
OMBricks.toMoveY = 4;
break;
case 7:
ballYDir = YDirection.Up;
ballXDir = XDirection.Right;
OMBricks.toMoveX = 1;
OMBricks.toMoveY = 4;
break;
case 8:
ballYDir = YDirection.Up;
ballXDir = XDirection.Right;
OMBricks.toMoveX = 2;
OMBricks.toMoveY = 4;
break;
case 9:
ballYDir = YDirection.Up;
ballXDir = XDirection.Right;
OMBricks.toMoveX = 3;
OMBricks.toMoveY = 4;
break;
case 10:
ballYDir = YDirection.Up;
ballXDir = XDirection.Right;
OMBricks.toMoveX = 4;
OMBricks.toMoveY = 4;
break;
case 11:
ballYDir = YDirection.Up;
ballXDir = XDirection.Right;
OMBricks.toMoveX = 4;
OMBricks.toMoveY = 3;
break;
case 12:
ballYDir = YDirection.Up;
ballXDir = XDirection.Right;
OMBricks.toMoveX = 4;
OMBricks.toMoveY = 2;
break;
}
}
}```
My only gripe with this is I'm sort of stuck with the 4x4 pixel movements for all decisions. My animations move the amount of pixels based on a float speed, so I shouldn't theoretically have many problems since I can increase or decrease the speed as needed. Although, I foresee some future modifications where the pixel movements will originally be higher, but then scaled back so I have options to increase those as well.

Anyone else with some ideas?

5. ## Re: Collisions -> half working...

I would normally use Singles for positions, velocities and speed, that way you can have consistent speed at the various angles.
Your ball is technically moving faster on the diagonals than it is when going straight along an axis.
Given a speed and an angle you want to travel, you can use Sin and Cos to calculate the magnitude of X and Y that is added to the position each frame to move along that path.
I'll just quote from an old post I did on another forum about 12 years ago.
Essentially, Sin and Cos is the ratio of X/Distance (sine) or Y/Distance (cosine), for a
particular angle, distance being the distance traveled over a period of time. This distance corresponds to the hypotenuse of a Right Triangle, which is why we're using Sin and Cos. Thus giving an Angle, you can find the ratio of how much X changes in relation to Y.

The ratio (the values returned) will always be between the values of 0.0 and 1.0. Therefore, if you want to move something 5 pixels at 20 degrees, you move it 5*sin(20) in X and 5*cos(20) in Y.

Therefore the basic calculation for a relative move is:
RelX = distance * sin(Angle)
RelY = distance * cos(Angle)

So when you bounce the ball and determine the angle you want to travel, at that point, convert the angle into your X and Y increment values and continue adding them to your ball's position until you bounce
off of something else.
The person was having some issues understanding the use of Sin and Cos, so I did go on to say he could do as you have done, divide the paddle into sections and have fixed X and Y deltas based on where you hit the paddle.

{edit}: I should mention since there are probably more Math oriented people familiar with Sin and Cos, that the relationship of Sin and Cos and Angle to X and Y is dependent on what your definition of where 0 degrees is (which axis), and the direction of rotation of the angle (is positive angle clockwise, or counter(anti-)clockwise).
In my case, where I first used Sin,Cos and angles to do meaningful work was in relation to RADAR displays, and the references were to compass headings, with 0 degrees being straight up along the Y axis, and 90 degrees being East along the X axis, so angle increases clockwise. My definitions above were based on those references, and I think of an object moving across a map with North being up along the Y axis.
But the math oriented people, who actually remember Sin and Cos from their math classes, tend to get a little sick (perhaps sea sick), because their frame of reference is 0 degrees is along the X axis, to the right, and the angle increases counterclockwise, so 90 degrees is straight up along the positive Y axis.
Of course, to add to the confusion, Windows graphics defaults to 0,0 being at the top and the Y axis is positive going down, not up, so is a third variation of coordinate system compared to map or math.
So, be aware, as you read various points on the subject, that you need to understand the frame of reference used.
{/edit}

In my implementation, what I did was not have a fixed direction off the paddle, but add a bias to the current angle (once reflected), but soon realized that if you consistently hit near the edge of the paddle you could end up with a very shallow angle so watch the ball go back an forth, slowly making its way up the screen. So, while I still added the bias, I limited the angle so it would never exceed + or - 70 degrees, reference to the perpendicular from the center of the paddle.

You could take your paddle values as you have them, and not worry about the Sin/Cos stuff, but scale the values back so that 4 = 1.0 and scale all the numbers based on that.
Code:
```                           case 0:
ballYDir = YDirection.Up;
ballXDir = XDirection.Left;
OMBricks.toMoveX = 1.0; //4;
OMBricks.toMoveY = 0.5; //2;
break;
case 1:
ballYDir = YDirection.Up;
ballXDir = XDirection.Left;
OMBricks.toMoveX = 1.0;  //4;
OMBricks.toMoveY = 0.75; //3;
break;
case 2:
ballYDir = YDirection.Up;
ballXDir = XDirection.Left;
OMBricks.toMoveX = 1.0; //4;
OMBricks.toMoveY = 1.0; // 4;
...```
Then you could use a speed of 4.0, and multiply the toMoveX and toMoveY by that speed to replicate what your game is currently doing. Then to speed up or slow down, you could just change the speed value.
Again, to get smoother movement, you need to have all the values as single, so they can accumulate fractionally. The position will be rounded to the nearest pixel when drawn, but the positions themselves will have subpixel resolution.

6. ## Re: Collisions -> half working...

Wow passel, impressive!

FYI: The animations are already calculated on a time based movement. I am using a framework that provides a built in Animation class that does this. So, when I move an object, regardless of pixels/floats, it's already smooth, so I'm not re-inventing the wheel on that and what is currently implemented is working exactly as expected. I really appreciate the explanation though, as it's a lot more clear now.

I have taken the Speed variable into account since reading your post. Awesome way to provide slower/faster movements and it was a relatively easy modification to add. In fact, I'm now also dynamically calculating new Single Point x/y amounts based off of initial x/y Single Point amounts in the case statements. Flows much better than hard coding the new amounts.

I'm really intrigued about the angle method for bouncing off of the paddle though. I'll have to look more into that.

7. ## Re: Collisions -> half working...

12 years ago someone was wanting to write a pong game, so I just threw together an example (was new to the forum so wrote a lot more code examples off the top of my head back then). It was just a quick example of some possibilites quickly thrown together using a button control for the ball and paddles.
The method I tried to use for timing turned out to not be consistent on various machines, so really needs to be replaced.
I tracked down that 12 year old post and downloaded the code to relook at it. Its written with vb6, so I assume as you're using C#, it wouldn't be of much use to you.

8. ## Re: Collisions -> half working...

Now comes improvement time. I am currently basing my collision off of the outside bounding rectangle of the ball. I'd like to change that to coincide with the ball itself. I've read over this time and again: StackOverflow_Circle_Rectangle_Collision and understand it somewhat. My current collision already takes the direction of ball movement into account to determine which side(s) are hit on bricks on a "predicted" ball move.

As we can see here in this picture:
- the ball is 25x25
- the ball is moving at a rate of 4 pixels right and 4 pixels down
- the "pink" rectangle indicates the rectangle before the move
- the "brown" rectangle indicates the calculated ball placement after the 4 pixels right and 4 pixels down, and shows how the ball would look in the rectangle
- the "3" and "2" will not be known and need to be figured out (they are the amount of pixels the ball is inside the rectangle on any intersection. With knowing these, I can determine where the ball would bounce off from. In this picture, the ball would bounce off the top of the rectangle.

What am I looking for:
How to calculate if either any of the left or top of the rectangle is inside the circle (the "3" and "2" in the picture). This will be for any 2 directions the ball is moving in relation to the corners the ball might be able to realistically touch:
- ball moving right/down, test the left/top of rectangle
- ball moving right/up, test the left/bottom of rectangle
- ball moving left/down, test the right/top of rectangle
- ball moving left/up, test the right/bottom of the rectangle

I'm currently implementing some trial and error based off the link above and some other searches I've done. I'm now just posting this in case someone would like to chime in. I'll be at this for a while, so I'll be updating this thread with anything useful.

9. ## Re: Collisions -> half working...

Passel, I must've been in the midst of writing my post when you posted. I've been idling through my words and thoughts and whatnot for damn near 2 hours now. Yes, I'm using C# (I thought I tagged the thread as that on creation). I've read some VB6 code before but never wrote any of it myself. I still appreciate the explanations you've given above as they've helped me understand more of what is going on.

10. ## Re: Collisions -> half working...

I have since attempted to change my ball to move based on an Angle property. From debugging, I noticed some things that seemed different from the calculations above in Passel's old quoted post.

I keep an integer property named Angle on my Ball class now. Then, when moving the ball:
Code:
```Single newPixelsToMove = PixelsToMove * Speed;
double angle = Math.PI * Angle / 180;
double test = Math.Sin(angle);
double test2 = Math.Cos(angle);
var RelY = (newPixelsToMove * test) * -1;
var RelX = newPixelsToMove * test2;```
Some explanations:
- newPixelsToMove is the current maximum of the pixel movement (IE: in my testing as per above posts, PixelsToMove = 1.0F and Speed = 4.0F, so newPixelsToMove = 4.0F)
- Angle is my property and is an integer (holds values 0 - 359)
- I had to 'recalculate' a new angle according to MSDN. This is because Math.Sin/Math.Cos were calculating based on radians and not degrees if passing the integer Angle. With the calculated angle, I am getting the correct values of it calculating based on degrees
- The test/test2 variables are separated so I can see what the variables held while debugging
- I used var's because I wasn't sure how calculating Singles multiplied by doubles would turn out, and I could see the true calculated values
- I switched the RelX and RelY variables from your posting. I am assuming this is because the different angles I tested made the most sense when thinking about 0-89 in the top right, 91-179 in the top-left, so counter clockwise around starting at 0 on the x-axis
- I also inverted the RelY variable. I am assuming this is because of the same issue as the point above when thinking about how the angles/grid are laid out

Using the new var's RelY/RelX, I pass those converted to integers into my Move/Collision methods. WOW! Changing the angles slightly doesn't have much effect since the conversions to integers are still at a 1 pixel round, but I can change the angle freely now to change the direction of the ball. No more hard coding the X/Y pixel movements!!!

I imagine all of the calculations could probably be more efficient. But I'm happy that it's working...

Thanks so much Passel for the initial spark! Now back to my collisions...

11. ## Re: Collisions -> half working...

As for the collision testing, what I've done in the past to simplify things when colliding a circle various objects, i.e. paddle, wall, bricks, is to have a test against a collision box that surrounds the object or insets from the gaming area, based on the radius of the ball.
I also track the position of the ball by its center, not the upper left corner.
It looks like you indicate a diameter of 25, so the radius from the center of the center pixel to the outside would be 12.5 pixels. Perhaps we don't count the center pixel and call it a 12 pixel radius (or 13 if you prefer).
If I had a wall on the left at X = 0, then I would set my LeftWall collision test value to 0 + 12, so when the ball's position (center) reach 12 or less, it bounced off the left.
Likewise, if the rightwall was 500, then the rightWall collision test value would be 500-12, so would bounce when the ball's position reached 488 or more.
Likewise, for a brick, each would have a virtual collision box around them, so the bricks collision box would essentially be 24 pixels wider and taller than the brick itself (12 pixels on all sides).
So, when you move the ball you just test if the balls position is inside the collision rectangle, and since the collision rectangles overlap, it could easily be in more than one.
At that point, it is fairly easy to just test the X value of the ball position against the X values of the sides of the collision box (deltaX) to see which side of the brick the ball is closest to.
Do the same for the Y values of top and bottom to see which horizontal side of the brick the ball is closest to.
Then compare the deltaX against the deltaY and whichever is smaller is the side I considered hit.

12. ## Re: Collisions -> half working...

Here is something I worked up pretty quickly that would check which side of the brick the ball hit:
Code:
```'Iterate through each brick in the yard
For Each item As Brick In bricks
'Check if the ball hit the brick
If player.Bounds.IntersectsWith(item.Bounds) Then
'If it did then get each side of the rectangle
Dim topSide As Rectangle = New Rectangle(item.Location, New Size(item.Width, item.Height \ 2))
Dim bottomSide As Rectangle = New Rectangle(New Point(item.Location.X, item.Height), New Size(item.Width, item.Height \ 2))
Dim leftSide As Rectangle = New Rectangle(item.Location, New Size(item.Width \ 2, item.Height))
Dim rightSide As Rectangle = New Rectangle(New Point(item.Right, item.Location.Y), New Size(item.Width \ 2, item.Height))

'Check if it hit the top or bottom side
If player.Bounds.IntersectsWith(topSide) OrElse player.Bounds.IntersectsWith(bottomSide) Then

'If it hit the top or bottom side then check if a corner was hit
If player.Bounds.IntersectsWith(leftSide) OrElse player.Bounds.IntersectsWith(rightSide) Then
'If a corner was hit then reverse both the horizontal and vertical movements
player.HorizontalMove = -player.HorizontalMove
player.VerticalMove = -player.VerticalMove
Else
'IF just a side was hit then reverse just the vertical movement
player.VerticalMove = -player.VerticalMove
End If

'Do the same thing only for the left and right sides
ElseIf player.Bounds.IntersectsWith(leftSide) OrElse player.Bounds.IntersectsWith(rightSide) Then
If player.Bounds.IntersectsWith(topSide) OrElse player.Bounds.IntersectsWith(bottomSide) Then
player.HorizontalMove = -player.HorizontalMove
player.VerticalMove = -player.VerticalMove
Else
player.HorizontalMove = -player.HorizontalMove
End If
End If
End If
Next```
Screw checking the Sin and Cosine because it if it hits a side then all you need to do is reverse direction.

13. ## Re: Collisions -> half working...

Screw checking the Sin and Cosine because it if it hits a side then all you need to do is reverse direction.

Did you do this in your bouncy ball game? If you did, I bet it plays a lot better

I am already beyond any attempts of going to back to not using Sin/Cos, so I am continuing forward. I am doing quite well so far, but still lots of glitchy collisions happening, and debugging certainly is a chore when trying to capture certain collisions. However, with that said, I think I came up with the right combination of wall/brick collisions to determine resolving which collision would happen, or which multiple collisions, if there are multiple intersections based on the next movement of the ball. I still have to add in the paddle collision to this, but since the paddle is shaped a little differently, I am currently determining options...

14. ## Re: Collisions -> half working...

I haven't implemented it yet, but I am in the process of rewriting it.

15. ## Re: Collisions -> half working...

I am almost there. Some really glitchy movements atm, but it's coming together nicely. It's hard to pinpoint where or why the movement isn't correct as there are tons of points to check. I actually took the time to draw out all the different directions, and plotted how the angle changes based on if the ball needs to move in the opposite x, y, or both directions. I have a feeling there some inconsistencies in determine the collisionDistancesX and collisionDistancesY, however, I'll scour the code in the next few days in an attempt to pinpoint where it happens.

****
EDIT: I have fixed up quote a few of the jagged/glitchy movements, I must've felt a little motivated. However, I did encounter one issue:

In this example, the next ball move is calculated as 3 pixels right, 2 pixels down. It looks to me like that movement should barely bounce the ball of the left side of the brick so that the ball moves left, but continues downwards. What happened when debugging was that the "right" moving collision wasn't detected at all, but the "down" movement collision was. Therefore, as the modified code stands, the next movement sends the ball up and right when I need it to be sent down and left.
****

Here is some updated code:
Code:
```        private void Collision(List<Bricks> _Bricks, int newX, int newY, Paddle p)
{
int totalBrickScore = 0;
List<int> index = new List<int>();
//int newMovementY = 100000;
//int newMovementX = 100000;
//bool hitY = false;
//bool hitX = false;
//int hitMovementY = 10000000;
//int hitMovementX = 10000000;
//int newYTop = 1000000;
//int newXLeft = 1000000;
//bool alreadyMoved = false;

int circleRadius = Width/2;
int circleCenterX = Left + circleRadius;
int circleCenterY = Top + circleRadius;
int circleCenterXNew = circleCenterX + newX;
int circleCenterYNew = circleCenterY + newY;
int collisionDistanceX = 99999999;
int collisionDistanceY = 99999999;
List<BallBrickCollision> _Collisions = new List<BallBrickCollision>();

//test collisions against walls
if (ballXDir == XDirection.Right)
{
if (circleCenterXNew >= OM.Host.ClientArea[0].Left + OM.Host.ClientArea[0].Width - circleRadius)
{
//bounce left
collisionDistanceX = circleCenterXNew - (OM.Host.ClientArea[0].Left + OM.Host.ClientArea[0].Width - circleRadius);
}
}
else
{
if (circleCenterXNew <= OM.Host.ClientArea[0].Left + circleRadius)
{
//bounce right
collisionDistanceX = (OM.Host.ClientArea[0].Left + circleRadius) - circleCenterXNew;
}
}
if (ballYDir == YDirection.Down)
{
if (Top >= OM.Host.ClientArea[0].Top + OM.Host.ClientArea[0].Height)
{
//too far down, lose life
return 0;
}
}
else
{
if (circleCenterYNew <= OM.Host.ClientArea[0].Top + circleRadius)
{
//bounce down
collisionDistanceY = (OM.Host.ClientArea[0].Top + circleRadius) - circleCenterYNew;
}
}
if (collisionDistanceX == 99999999 && collisionDistanceY == 99999999)
{
//same movements towards wall, no collisions with the walls
}
else
{
//collision has occured, but on which side of wall?
if (collisionDistanceX == collisionDistanceY)
{
//same distance, must've hit a corner?
_Collisions.Add(new BallBrickCollision(null, true, collisionDistanceX, true, collisionDistanceY));
}
else if (collisionDistanceX < collisionDistanceY)
{
//hit side before top/bottom
_Collisions.Add(new BallBrickCollision(null, true, collisionDistanceX, false, collisionDistanceY));
}
else
{
//hit top/bottom before side
_Collisions.Add(new BallBrickCollision(null, false, collisionDistanceX, true, collisionDistanceY));
}
}

//test collisions against paddle

//test collisions against bricks
for (int i = 0; i < _Bricks.Count; i++)
{
if ((_Bricks[i].Visible) && (!_Bricks[i].isDestroying))
{
collisionDistanceX = 99999999;
collisionDistanceY = 99999999;
Rectangle brickCollisionBox = new Rectangle(_Bricks[i].Left - circleRadius, _Bricks[i].Top - circleRadius, _Bricks[i].Width + Width, _Bricks[i].Height + Height);
if (ballXDir == XDirection.Right)
{
// -->
if ((circleCenterXNew >= brickCollisionBox.Left) && ((circleCenterYNew <= brickCollisionBox.Top) && (circleCenterYNew >= brickCollisionBox.Top + brickCollisionBox.Height)))
{
//touches or collides with left of brick by how much
collisionDistanceX = circleCenterXNew - brickCollisionBox.Left;
}
}
else
{
// <--
if ((circleCenterXNew <= brickCollisionBox.Left + brickCollisionBox.Width) && ((circleCenterYNew <= brickCollisionBox.Top) && (circleCenterYNew >= brickCollisionBox.Top + brickCollisionBox.Height)))
{
//touches or collides with right of brick
collisionDistanceX = brickCollisionBox.Left + brickCollisionBox.Width - circleCenterXNew;
}
}
if (ballYDir == YDirection.Down)
{
// ||V
if ((circleCenterYNew >= brickCollisionBox.Top) && (circleCenterYNew < brickCollisionBox.Top + brickCollisionBox.Height) && ((circleCenterXNew >= brickCollisionBox.Left) && (circleCenterXNew <= brickCollisionBox.Left + brickCollisionBox.Width)))
{
//***** PROBLEM HERE **********
//touches or collides with top of brick
collisionDistanceY = circleCenterYNew - brickCollisionBox.Top;
}
}
else
{
// ||^
if ((circleCenterYNew <= brickCollisionBox.Top + brickCollisionBox.Height) && (circleCenterYNew > brickCollisionBox.Top)  && ((circleCenterXNew >= brickCollisionBox.Left) && (circleCenterXNew <= brickCollisionBox.Left + brickCollisionBox.Width)))
{
//touches or collides with bottom of brick
collisionDistanceY = brickCollisionBox.Top + brickCollisionBox.Height - circleCenterYNew;
}
}

if (collisionDistanceX == 99999999 && collisionDistanceY == 99999999)
{
//same movements towards brick, no collisions with this brick
}
else
{
//collision has occured, but on which side of brick?
if (collisionDistanceX == collisionDistanceY)
{
//same distance, must've hit a corner?
_Collisions.Add(new BallBrickCollision(_Bricks[i], true, collisionDistanceX, true, collisionDistanceY));
}
else if (collisionDistanceX < collisionDistanceY)
{
//hit side before top/bottom
_Collisions.Add(new BallBrickCollision(_Bricks[i], true, collisionDistanceX, false, collisionDistanceY));
}
else
{
//hit top/bottom before side
_Collisions.Add(new BallBrickCollision(_Bricks[i], false, collisionDistanceX, true, collisionDistanceY));
}
}
}
}
//test collision with paddle now
if (_Collisions.Count > 0)
{
//there was a collision
int lowestCollisionValue = 99999;
for (int i = 0; i < _Collisions.Count; i++)
{
if (_Collisions[i].CollisionDistanceX < lowestCollisionValue)
lowestCollisionValue = _Collisions[i].CollisionDistanceX;
if (_Collisions[i].CollisionDistanceY < lowestCollisionValue)
lowestCollisionValue = _Collisions[i].CollisionDistanceY;
}
//now we have the LOWEST possible collision factor
bool angledChanged = false;
for (int i = 0; i < _Collisions.Count; i++)
{
if ((_Collisions[i].CollisionDistanceX == lowestCollisionValue) && (_Collisions[i].CollisionDistanceY == lowestCollisionValue))
{
if(_Collisions[i].Brick != null)
_Collisions[i].Brick.Hit = true;
Top += _Collisions[i].CollisionDistanceY;
Left += _Collisions[i].CollisionDistanceX;
if (!angledChanged)
{
angledChanged = true;
Angle += 180; //complete opposite
}
}
else if (_Collisions[i].CollisionDistanceX == lowestCollisionValue)
{
//change x direction
if (_Collisions[i].Brick != null)
_Collisions[i].Brick.Hit = true;
Top += _Collisions[i].CollisionDistanceX;
Left += _Collisions[i].CollisionDistanceX;
if (!angledChanged)
{
angledChanged = true;
if (Angle < 90)
{
Angle = 180 - Angle;
}
else if (Angle < 180)
{
Angle = 180 - Angle;
}
else if (Angle < 270)
{
Angle = 360 - Angle - 180;
}
else if (Angle < 360)
{
Angle = 180 + (360 - Angle);
}
}
}
else if (_Collisions[i].CollisionDistanceY == lowestCollisionValue)
{
//change y direction
if (_Collisions[i].Brick != null)
_Collisions[i].Brick.Hit = true;
Top += _Collisions[i].CollisionDistanceY;
Left += _Collisions[i].CollisionDistanceY;
if (!angledChanged)
{
angledChanged = true;
if (Angle < 90)
{
Angle = 360 - Angle;
}
else if (Angle < 180)
{
Angle = 180 + (180 - Angle);
}
else if (Angle < 270)
{
Angle = 180 - (Angle - 180);
}
else if (Angle < 360)
{
Angle = 360 - Angle;
}
}
}
}
}
else
{
//no collisions with walls, paddles, or bricks, just move normally now...
Top += newY;
Left += newX;
}
}```

16. ## Re: Collisions -> half working...

I just wanted to mention that I've updated my game because of this thread. I am having some issues with the collision too, so I'm interested in seeing some new ways.

17. ## Re: Collisions -> half working...

Good job dday! I like your level generation, very easy. I have my level generation via code to maximize all sorts of different scenarios.

Some things doable via code:
- Bricks at any X,Y starting location
- Bricks with any size width/height
- Bricks with any amount of "levels" (number of hits)

Using this approach I made a sort of upside down "stacked" pyramid. The point (bottom brick) is above 2 more, slightly higher up and spaced out, then 3, 4, 5, and so on... This creates an effect that looks like from the point (bottom) to the base (top) tilts downward. Not true 3d, but good enough for a 2d plane and my experience level.

EDIT: Oh ya, what issues are you having? I haven't scoured the code yet or tried it myself, but I might be able to 'recognize' some scenarios if they happen to be like what happened to me.

Also, I forgot to mention that for the time being, my collision is working well enough that it's playable. I'll post some updated code in the next few days in case anyone is interested.

18. ## Re: Collisions -> half working...

In some cases it will recognize collision with the wrong side. For example, if it hit the top and it took to long to register and it gets to the conditional statement where it checks the right side and at the time(because of the lag) it will regrister that it hit the right side so it'll change horizontal movement rather than vertical movement.

19. ## Re: Collisions -> half working...

Do you move the ball at a faster rate than the width and/or height of the minimum width and/or height of any brick? That would cause the issue. Or do you happen to move the ball before the collision check? In my case I do the collision check based on the predicted movement of the ball before actually moving the ball... Hope that might help a little. I'll check the collision code this weekend and report back.

20. ## Re: Collisions -> half working...

That's a good point, I think that the collision check is after the ball move.

21. ## Re: Collisions -> half working...

I'm now back to reworking the paddle collision. I have all of the brick and wall collisions working out great. I originally sliced the paddle into 13 sections and changed the x/y movement based on where it hit. Since I've changed all the movement to be calculated from an angle the ball is moving on, I need to change the balls angle based on where it hit the paddle. Passel made a good point above about the ball slowly creeping up, and with that, I'm setting the angle that the ball can bounce off the paddle anywhere from 20 - 160. Because of having 140 different angles we can send the ball on (or condensed to say 70), it doesn't seem feasible to split the paddle up into that many "slices" and test where the ball hits. Of course, that might be the only option, as currently I"m just inverting the "y" axis which provides no control.

Code:
```//test collisions against paddle
if (ballYDir == YDirection.Down)
{
if ((circleCenterYNew >= p.Top - circleRadius) && (circleCenterXNew > p.Left - circleRadius) && (circleCenterXNew < p.Left + p.Width + circleRadius))
{
collisionDistanceY = circleCenterYNew - (p.Top - circleRadius);
_Collisions.Add(new BallBrickCollision(null, false, collisionDistanceX, true, collisionDistanceY, p));
}
}

if (_Collisions.Count > 0)
{
//there was a collision
int lowestCollisionValue = 99999;
for (int i = 0; i < _Collisions.Count; i++)
{
if (_Collisions[i].CollisionDistanceX < lowestCollisionValue)
lowestCollisionValue = _Collisions[i].CollisionDistanceX;
if (_Collisions[i].CollisionDistanceY < lowestCollisionValue)
lowestCollisionValue = _Collisions[i].CollisionDistanceY;
}
//now we have the LOWEST possible collision factor
bool angledChanged = false;
for (int i = 0; i < _Collisions.Count; i++)
{
if ((_Collisions[i].CollisionDistanceX == lowestCollisionValue) && (_Collisions[i].CollisionDistanceY == lowestCollisionValue))
{
//both directions hit

}
else if (_Collisions[i].CollisionDistanceX == lowestCollisionValue)
{
//change x direction
... code here ...
}
else if (_Collisions[i].CollisionDistanceY == lowestCollisionValue)
{
//change y direction
if (_Collisions[i].Brick != null)
_Collisions[i].Brick.Hit = true;
Top += _Collisions[i].CollisionDistanceY;
Left += _Collisions[i].CollisionDistanceY;
if (!angledChanged)
{
angledChanged = true;
if(_Collisions[i].p != null)
{
//here the paddle was hit
//for now, just let the normal y axis change run until we can determine where the ball hits the paddle at
}
if (Angle < 90) //once the paddle "hit" is figured, this becomes "else if"
{
Angle = 360 - Angle;
}
else if (Angle < 180)
{
Angle = 180 + (180 - Angle);
}
else if (Angle < 270)
{
Angle = 180 - (Angle - 180);
}
else if (Angle < 360)
{
Angle = 360 - Angle;
}
}
}
}
}
else
{
//no collisions with walls, paddles, or bricks, just move normally now...
Top += newY;
Left += newX;
}```
Besides this, all of my other collision checks are working great. Thanks Passel and dday9!!!

22. ## Re: Collisions -> half working...

Originally Posted by detlion1643
... and with that, I'm setting the angle that the ball can bounce off the paddle anywhere from 20 - 160. Because of having 140 different angles we can send the ball on (or condensed to say 70), it doesn't seem feasible to split the paddle up into that many "slices" and test where the ball hits. ...
I guess your paddle angle logic is probably close to what my was for a "wall type" paddle bounce, just reflecting the angle to reverse direction.
And you don't have to necessarily have to hit test against a lot of slices of the paddle, just calculate a difference and apply that to the angle.
I had a vertical paddle (two player pong), and my angle references are also different, but I think you'll get the picture and can adjust.
So, to calculate a straight reflection, my code was like this, for a ball moving to the right stiking the paddle and bouncing back to the left.

Ball_Angle = 270 + (90 - Ball_Angle)

In my angle orientation, 80 degrees would be moving to the right, from lower left toward upper right (compass heading, ENE (east by north east), aka heading 10 degrees north of straight east (east is along the X-axis).
So, 90 - 80 give you that 10 degrees relative angle above the X-axis, and 270 + 10 will give 280, which is 10 degrees relative above straight West, so a simple reflective bounce.

Now, to modify the straight bounce, by where the ball hit the paddle, since I used the center of the ball for its position, and the center of the paddle for its position, I just had to subtract the balls Y position (in your case, X position) from the paddle's Y position

Bounce_Angle_Mod = The_Paddle.Y - Ball.Y

If the Ball was above the center of the paddle, the Angle_Mod would be positive, and if below the center, would be negative.
Each pixel of offset from the center was treated as 1 degree of additional reflection added to the straight reflection, so this would increase or decrease the resulting bounce angle, and not be a variable fixed angle based on where the paddle was hit.
Of course, since the angle is additive (or subtractive) and not a fixed angle off of a given paddle position is the reason for having to have a limit check.
You could always go the other way, and not care what the input angle is, just simply do the offset from paddle center calculation and use that value as somthing to multiply by a value to give an a fixed angle relative to where you hit the paddle. I can see that as also being a reasonable paradigm for how the paddle reacts to the ball. That way, you would possibly have a more deterministic projection of which way the ball was going to travel off the paddle, i.e. it doesn't matter at what angle the ball came in, if it hit the center of the paddle, it would bounce straight up off the paddle, if it hit anywhere along the paddle to the right of center, it would bounce to the right a variable angle that changed based on how far out the paddle it hit, likewise, hitting the paddle on the left size would always bounce at a range of fixed angles to the left.
But, while that might be more predictable, it could also look "unrealistic" if once doesn't except the "rules" of how the paddle works.

In my case, I simply added (actually subtracted in the ball moving right to left case) the Angle_Mod to the straight reflection to change the angle more subtlely, so ball hitting in the center, bounce straight as you do now, and either made the bounce angle shallower or steeper depending on which side of the paddle center it hit.

Ball_Angle = 270 + (90 - Ball_Angle) - Bounce_Angle_Mod
'then some code to limit angle if outside range +-70 (i.e. limit to 200 to 340 degrees) which is 270 +- 70.

Got to go, can't explain it any more for now, hopefully not confusing.

23. ## Re: Collisions -> half working...

Passel, thanks again for the great response!

Describing out in great detail really put it into perspective for me. It's not confusing (well the simplified approach anyways). I chose to go with the left side of the paddle angling the ball back to the left side and vice versa for the right side. This works well enough based on the angle approach without "slicing" the paddle and looping. I even took into account the angles of the ball moving side to side more so than it should. I'm sure it could be better, but I think this thread has drawn out enough onto collisions by now and the evolution of the pixel movements to a more elegant angle movement.

If anyone is interested:
Code:
```if (_Collisions[i].p != null)
{
int ballHalf = Left + Width / 2;
int paddleHalf = p.Left + p.Width / 2;
int whereHit = ballHalf - paddleHalf;
double paddleAngles = p.Width / 2 / 45;
double angleChange = whereHit * paddleAngles;
if (90 - (int)Math.Round(angleChange) > 160)
Angle = 160;
else if (90 - (int)Math.Round(angleChange) < 20)
Angle = 20;
else
Angle = 90 - (int)Math.Round(angleChange);
}```

#### Posting Permissions

• You may not post new threads
• You may not post replies
• You may not post attachments
• You may not edit your posts
•

Featured

Click Here to Expand Forum to Full Width