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.
-
24\$\begingroup\$ Is this what they call a "corner case"? \$\endgroup\$– Andrew GrimmCommented Apr 11, 2011 at 2:30
-
2\$\begingroup\$ Definitely, as things go, soon we may employ the theory of relativity to solve it – the problem is getting mass(ive). \$\endgroup\$– LumisCommented Apr 13, 2011 at 23:18
4 Answers
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;
-
1
-
1\$\begingroup\$ Feel free to upvote, then :-) \$\endgroup\$– meritonCommented Apr 10, 2011 at 17:52
-
3\$\begingroup\$ 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). \$\endgroup\$ Commented Apr 11, 2011 at 12:28 -
1\$\begingroup\$ @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 :-) \$\endgroup\$– meritonCommented Apr 11, 2011 at 21:35
-
1\$\begingroup\$ Love this answer, but it could use some $\LaTeX$ markup of the math. \$\endgroup\$ Commented Apr 13, 2011 at 20:44
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.
I'll leave the derivation of that as an exercise to the reader.
I'm working on a game and also stuck here. But I guess it goes this way:
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).
-
\$\begingroup\$ 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. \$\endgroup\$– RisaCommented Apr 10, 2011 at 12:06
-
\$\begingroup\$ 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. \$\endgroup\$– LumisCommented Apr 10, 2011 at 12:22
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.