47

I need to brush up my trigonometry and hope you can help here with a simple mathematical model. Here is my model so far in the image attached. I am aware that the frame animation has other problems when the ball is moving very fast, but for now I just need to calculate ballDx and ballDy. It is also possible that ballDx = 0 (vertical movement only), but when the ball deflects ballDx may get a different value.

2D collision between ball and the corner edge of a solid unmovable object

Lumis
  • 964
  • 1
  • 9
  • 21

4 Answers4

46

Note: All of the following assumes the ball's surface is frictionless (so it won't start spinning or rebound differently because it is).

At the moment of collision, the ball will be touching the corner. When solid objects collide, a force will act along the so called surface normal, i.e. perpendicular to the surface at the point of collision.

Since it's a ball, perpendicular to the surface is towards to ball's center. Ok, so we know the direction of the force, what about its magnitude? Assuming an elastic collision (and that the rectangle can't move), the ball must rebound at the same velocity it impacted with.

Let (nDx, nDy) be the velocity after collision, (oDx, oDy) the velocity before collision, and (x,y) the position of the ball at the point of collision. Let's further assume the corner the ball collides with is at (0,0).

Expressing our insights as formulae, we have:

(nDx, nDy) = (oDx, oDy) + c * (x, y)
length (nDx, nDy) = length (oDx, oDy)

Which is equivalent to:

nDx = oDx + c * x
nDy = oDy + c * y
nDx^2 + nDy^2 = oDx^2 + oDy^2

Substituting the first two equations in the last one, we get:

(oDx + c * x)^2 + (oDy + c * y)^2 = oDx^2 + oDy^2

Expanding using the binomial thorem

(a+b)^2 = a^2 + 2ab + b^2 

yields:

oDx^2 + 2 * oDx * c * x + (c * x) ^ 2 + oDy^2 + 2 * oDy * c * y + (c * y) ^ 2 = oDx^2 + oDy^2
2 * oDx * c * x + 2 * oDy * c * y + (c * x) ^ 2 + (c * y) ^ 2 = 0
(2 * oDx * x + 2 * oDy * y) * c + (x^2 + y^2) * c^2 = 0

This quadratic equation for c has two solutions, one of which is 0. Obviously, that's not the solution we are interested in, as generally the direction of the ball will change as a result of the collision. To get the other solution, we divide both sides by c and get:

(2 * oDx * x + 2 * oDy * y) + (x^2 + y^2) * c = 0

That is:

 c = -(2 * oDx * x + 2 * oDy * y) / (x^2 + y^2)

To summarize, we have:

c = -(2 * oDx * x + 2 * oDy * y) / (x^2 + y^2)
nDx = oDx + c * x
nDy = oDy + c * y

Edit: In code:

if (collision) {
    float x = ballX - cornerX;
    float y = ballY - cornerY;
    float c = -2 * (ballDx * x + ballDy * y) / (x * x + y * y);
    ballDx = ballDx + c * x;
    ballDy = ballDy + c * y;
}

A few implementation considerations: While you can approximate (x,y) with the ball's position after the simulation step, this approximation will change the angle of deflection and hence be very noticeable, so your simulation steps need to be very fine (perhaps such that the ball doesn't move more than 1/20 of its diamater per step). For a more accurate solution, you could compute the time the collision occurs, and split that simulation step at that time, i.e. do a partial step until the point of collision, and another partial step for the remainder of the step.

Edit 2: Computing the point of impact

Let r be the radius, (x0, y0) the position and (dx, dy) the velocity of the ball at the beginning of the simulation step. For simplicity, let's further assume that the corner in question is located at (0,0).

We know:

(x,y) = (x0, y0) + (dx, dy) * t

We want

length(x,y) = r

That is

(x0 + dx * t) ^ 2 + (y0 + dy * t) ^ 2 = r^2
x0^2 + 2 * x0 * dx * t + dx^2 * t^2 + y0^2 + 2 * y0 * dy * t + dy^2 * t^2 = r ^ 2
(dx^2 + dy^2) * t^2 + (2 * x0 * dx + 2 * y0 * dy) * t + (x0^2 + y0^2 - r^2) = 0
\____  _____/         \____________  ___________/       \_______  ________/
     \/                            \/                           \/
     a                             b                            c

That is a quadratic equation in t. If its discriminant

D = b^2 - 4 * a * c

is negative, it has no solutions, i.e. the ball will never hit the corner on its present course. Otherwise, its two solutions are given by

t1 = (-b - sqrt(D)) / (2 * a)
t2 = (-b + sqrt(D)) / (2 * a)

We are interested in the time the collision started, which is the earlier time t1.

Your method would become:

    // compute a,b,c and D as given above

    if (D >= 0) {
        t = (-b - sqrt(D)) / (2 * a);
        if (0 < t && t <= ts) {
            // collision during this timestep!

            x = x + t * dx;
            y = y + t * dy;
            ts = ts - t;

            // change dx and dy using the deflection formula 
        }
    }

    x = x + ts * dx;
    y = y + ts * dy;
meriton
  • 726
  • 5
  • 6
  • 1
    this deserve +1 – dynamic Apr 10 '11 at 17:09
  • 1
    Feel free to upvote, then :-) – meriton Apr 10 '11 at 17:52
  • +1 for making a math-retard giggle at the simplicity of the simplified binomial (?) formula – Zaky German Apr 10 '11 at 21:00
  • You did translate the coordinates such that the corner to be deflected from is located at (0,0)? – meriton Apr 10 '11 at 22:39
  • If we assume the ball is immediately below the corner, i.e. x = 0 and y = 1, I get c = -2 oDy, and thus nDx = oDx and nDy = oDy - 2 * oDy = -oDy as expected. – meriton Apr 10 '11 at 22:43
  • To translate the coordinates I just need to ballX = ballX -cornerX and the same for ballY, right? – Lumis Apr 10 '11 at 23:06
  • Yes; I added a code example now. – meriton Apr 10 '11 at 23:17
  • It is working! I had another condition in code which was moving the ball and confusing the issue, but after turning it into comments, it is all fine now. Thank you, this is really simple and fast! – Lumis Apr 10 '11 at 23:57
  • 3
    You say very early that At the moment of collision, the ball will be touching the corner but I don't see a justification of this approximation (and it must be an approximation because it's not true - the ball is touching in two places, neither of which is the corner). – Peter Taylor Apr 11 '11 at 12:28
  • 1
    @Peter Taylor: You did notice that the OP has drawn the ball outside the rectangle, and the collision detection formula given in the question assumes this, too? You gotta think outside the box here :-) – meriton Apr 11 '11 at 21:35
  • @meriton, I saw the "area of impact" and assumed that it was two figures rather than one. All clear now. Thanks. – Peter Taylor Apr 11 '11 at 21:37
  • @meriton, this solution is very sensitive to the frame animation, i.e. a ball fired with the same speed and direction at the corner bounces with different angle depending on the ball’s original distance from the corner, which should not happen. I think that a vector-angle type of calculation would depend less on the impact-position of the ball and more on its trajectory. – Lumis Apr 12 '11 at 10:52
  • @meriton, also there is a strange behaviour when bouncing 90 degree to the right or left like there is a concentration of angle distribution there for about 3 ballX whole values, and then suddenly when ballX is changed just by one more unit the angle becomes drastically different. – Lumis Apr 12 '11 at 10:52
  • @meriton, I guess these are the things you warned about in your last paragraph. – Lumis Apr 12 '11 at 11:05
  • Most likely. Have you tried my suggested solution? – meriton Apr 12 '11 at 18:54
  • If I know the maximum speed of the ball, I know how deep the ball can penetrate the corner, and if this is shorter than the ball's diameter, the collision detection, as it is now, would still work. Then I need to find the ballX/ballY at the moment of collision and only then use your formula, so I would virtually move the ball back a bit. Not sure how to calculate the position of the ball at the theoretical moment of impact and how can time you mentioned help me here. – Lumis Apr 13 '11 at 13:31
  • See my edited answer. – meriton Apr 13 '11 at 19:14
  • 1
    Love this answer, but it could use some $\LaTeX$ markup of the math. – Martin Wickman Apr 13 '11 at 20:44
  • @meriton, how do you define the initial value of 'ts' in ts = ts - t ? Or what 'ts' represents in a computer program? – Lumis Apr 13 '11 at 23:08
  • Oops, sorry. ts stands for time step, the time between two position updates of the ball. – meriton Apr 14 '11 at 17:32
  • @meriton: As I show below there is a simpler way to derive these results leveraging the graphics libraries, by transforming into a more convenient frame of reference. – Pieter Geerkens Aug 24 '18 at 11:55
13

Here's a visual way of looking at a problem.

The original problem set is circle vs. rectangle (gray in the image below). This is equivalent to point vs. rounded rect (shown in black).

So this is a multi-part problem. You're testing your point collision vs. 4 lines (extruded out from the edge of the box by the radius of the original circle) and 4 circles (at the corners of the rectangle with the same radius of the original circle).

With the rough velocity in your original image, the point will hit the bottom right corner circle. All you have to do is figure out the point on the corner circle that you would hit, calculate the angle of that, and reflect off of it.

enter image description here

I'll leave the derivation of that as an exercise to the reader.

Tetrad
  • 30,124
  • 12
  • 94
  • 143
2

I'm working on a game and also stuck here. But I guess it goes this way:

enter image description here

There's another view My problem is that I don't know how to quickly calculate the new dx, dy (to me using traditional math requires too many calculations).

Pikalek
  • 12,372
  • 5
  • 43
  • 51
Risa
  • 117
  • 5
  • My point of view is different to the one in the 2nd link, because I don't think the new velocity vector depends on the center of the block like that. My brother told me the ball will bounce back to the old direction (dx = -dx && dy = - dy) but I don't think so. – Risa Apr 10 '11 at 12:06
  • If the ball hits the corner and ballX distance from cornerX is smaller than 1/4 of ballW then it will bounce back, otherwise it will deflect forward to the right. This is a simple model I am using at the moment, which is not fine tuned to find exact angle. – Lumis Apr 10 '11 at 12:22
0

Kinematics is all about choosing the correct, as in most convenient for calculations, frame of reference.

Here we will first define the transformation T that resolves our axes into components parallel (x') and perpendicular (y') to a line between the centre of the ball and the corner. The inverse transformation T* will restore our original coordinate system.

In this new frame of reference, by reflection (and the time and space symmetry of physics), we have the velocity transformation of contact M (a point impulse) as that which reverses the x' component and leaves unchanged the y' component. In matrix terms this is the diagonal matrix with -1 and 1 on the diagonal.

Then the velocity after the collision is simply: V' = T* . M . T . Vo.

The time of impact t is then just the solution for (T . Do) + (X . T . Vo) (t) = r where X is the X-axis projection operator and r is the radius of the ball. Rearranged, we obtain
t = ( r - (T . Do) ) / ( (X . T . Vo) (t) )

This has the distinct advantage of burying all the complex mathematics in rigorously written, tested, and debugged standard graphics libraries. This solution is also identical for 2D and 3D situations - just switch graphics library. Finally, it highlights that one should first think about appropriate frames of reference before tackling any physics problem. There is always the NIH temptation, but in truth that is just a recipe for bugs when more succinct solutions are available.

Pieter Geerkens
  • 2,111
  • 12
  • 17