Ball passing through gap between blocks

Started by
9 comments, last by FirstStep 7 years, 10 months ago

I was trying to add some breakable and unbreakable block on my simple breakout game. But everytime the ball hit the gap between two blocks the ball just pass through it.

passing_through.jpg

I dont know if the collision between the ball and the block is the problem cause the code is just for checking the Box - Circle collision


private bool circleCollision(Ball ball, Blocks block)
        {
            Vector2 center = ball.getRadius();


    
            Vector2 AABB_Half_Extents = new Vector2(block.Width / 2,block.Height / 2);
            Vector2 aabb_center = new Vector2(block.Position.X + AABB_Half_Extents.X,
                block.Position.Y + AABB_Half_Extents.Y);




         
            Vector2 difference = center - aabb_center;




            
            Vector2 clamped = Vector2.Clamp(difference,-AABB_Half_Extents,AABB_Half_Extents);
       
           
            Vector2 closest = aabb_center + clamped;
          




            difference = closest - center;


            if(difference.Length() < ball.BallRadius)
            {
        
                return true;


            }
            return false;




        }

Does anyone have any idea why is it passing through the gap of the the blocks? Its suppose the ball back.

Advertisement

Don't know, but the first line looks weird; how is a radius a 2D vector?


Vector2 center = ball.getRadius();

Edit:

Otherwise, setup a breakpoint there, and step through the code to check the computed values.

Since the conclusion of the code differs from your idea, the code must somewhere deviate from what you consider correct.

Don't know, but the first line looks weird; how is a radius a 2D vector?


Vector2 center = ball.getRadius();

This is how i get the radius


    public  Vector2 getRadius()
        {
            Vector2 center;
            center.X = Position.X + BALL_RADIUS;
            center.Y = Position.Y + BALL_RADIUS;

            return center;

        }

The BALL_RADIUS is just a constant number of 15f

This is how i get the radius


    public  Vector2 getRadius()
        {
            Vector2 center;
            center.X = Position.X + BALL_RADIUS;
            center.Y = Position.Y + BALL_RADIUS;

            return center;

        }

The BALL_RADIUS is just a constant number of 15f

So the name of the function is a bit misleading

- you should return a float or double if you want to get the main radius value

- you should return a point2D if you want to return the new ball position

- you should return a vector2D if you want to return the ball radius vector (makes sense only when the ball is moving in a direction)

But more importantly the vector maths calculation above is wrong.

You added a scalar quantity to a point position, and I'm not sure what you end up with anymore because it becomes directionless. Normally you want to add a vector to a point to get a new point position

Below is a simple vector maths algorithm :-

If the ball is moving , then the direction of the moving ball is normalised to get the unit_vector

unit_vector * ball_radius = ball_radius_vector

- unit_vector.x * ball_radius = ball_radius_vector.x

- unit_vector.y * ball_radius = ball_radius_vector.y

ball_centre_point_position + unit_vector * ball_radius = ball_surface_point_position

ball_centre_point_position + ball_radius_vector = ball_surface_point_position

But adding a scalar quantity directly the way you did in your reply is meaningless and not correct because BALL_RADIUS has no direction.

Even though your user-name is different from OP's, you seem to be replying as if you are the OP

This is how i get the radius

If you are OP then your getRadius() function is wrong and might be the source of the bug and the algorithm i wrote above might help fix it.

If you are not the OP, then thats an incorrect code advice that you have given

can't help being grumpy...

Just need to let some steam out, so my head doesn't explode...

If you are not the OP, then thats an incorrect code advice that you have given

I am not, the code is the code I saw from some OpenGL tutorial and implemented it to my own. If you think about it, (0,0) always start at the top-left of sprite. adding some constant number will move the point somewhere in the circle. Im not a math savvy person but I like things that are simpler to understand. But I guess yours are much better.

Here is my output

show.png. The dot is place to show the center of ball

Also I followed a lot of tutorial and accepted some ideas. The Direction will always be between 1 and 0 because of the way how I move the ball. This is how


Position += (Direction * (float)dt.ElapsedGameTime.TotalSeconds) * Speed

This is the code I found from pluralsight tutorial. I find it easy to understand as I can set the speed and change the direction instantly. Thats why I see no reason to normalize it since it is just there to change the direction of the ball. Some tutorial do is like this which is normally from Pong tutorial.


Position += position * dt;

Although its simpler I find the first code easier for me to understand.

Found the problem. When I hit the gap between blocks, the block set the direction to opposite direction of Y. So what happens is first the first block set the block to bounce back, soon after that the other block set the direction to the opposite of Y(this time instead of ball going downwards, it set the ball going up).

Ha, double bounce thus :)

Great that you found the problem.

Ha, double bounce thus :)

Great that you found the problem.

Though I found the problem, can you give me some tips on how to avoid this kind of things? Since the collision checking occurs for every block, how to determine which of the block was hit first or which of the block has the greatest part of the ball that hits it? Was thinking of like if 75% of the ball where on the other block that would just set the ball bounce and reject the other block's setting of the ball's Y direction. But if for example the ball hit exactly in the middle then 50% will be on the first block and 50% will be on the 2nd block. That problem will occur again.

Sure, let's see.

There are two ways to do this, I think.

1. Use the x coordinate of the center of the ball to decide which block gets to bounce it.

This assumes blocks do not overlap nor that holes exist between them. The only sane way to do that is to define eg the left side is part of the block, and the right side is not. Left edge of a block X, and the right side of block X-1 (which is at the left of block X) are on top of each other. You may want to give a block an integer width to make this happen without rounding errors.

In this way, there is exactly one block where "left side of block" <= "center x of ball" < "right side of block", and thus its y direction is modified one time.

2. Postpone reversal.

Do what you do now, but instead of actually reversing the Y, just set a boolean flag "direction must be reversed". If more than one block does that, no harm is done, since setting a flag twice has the same effect. After you have done all blocks, inspect the flag. If it says "reverse direction", reverse the direction.

The above assumes you only bounce from top or bottom. If you also bounce from the side, "reverse the direction" becomes ambiguous. Instead you may want to say how it should bounce (bounce at bottom, bounce at left, etc), rather than just "reverse". Bouncing from the same side twice is still fine then, I think the only corner case you have left then is bouncing from the side and the bottom at exactly the same moment. If that can happen, you may want to code a special case for that, as this is one case where you do want a double reversal (I think).

Since you're only checking against AABBs, create an AABB that encloses the start and end positions of the ball for your dt. Every brick intersected by that is a candidate. That's your broad phase.

Calculate the time of impact (use FLOAT_MAX for misses) for each block, then pick the one with the lowest time.

Once you find that you advance the ball to that point in time, apply the effects of the impact, then integrate again with the remaining dt, doing however many impacts are necessary until the dt is consumed.
void hurrrrrrrr() {__asm sub [ebp+4],5;}

There are ten kinds of people in this world: those who understand binary and those who don't.

This topic is closed to new replies.

Advertisement