0
\$\begingroup\$

Background

I've been making my own game from scratch.

I've made my own collision system and there's a situation I'm having an issue with.


Problem

+

Pictured:

  • a ball going in one direction and changing direction when it hits the green segment.

I have the trajectory's angle in correlation with [relative to?] OX axes and trajectory's angle (in correlation with)[relative to?] the green segment.


Question

How do I update the initial trajectory angle with the OX to produce the bounce behaviour?

\$\endgroup\$
  • \$\begingroup\$ I've submitted an edit to your question to attempt to make it clearer - could you check it please? \$\endgroup\$ – Natalo77 Mar 25 at 14:15
  • \$\begingroup\$ Your question is not clear. You need to read several of the countless tutorials on balls bouncing against wall segments. You should be using vector mathematics - maybe in the form of a 3rd-party vector library - to calculate trajectories. \$\endgroup\$ – Engineer Mar 26 at 10:23
2
\$\begingroup\$

This is not done with angles.

This is done with vectors. Well, actually you could do it with angles...

In any case, the ball has a velocity vector at the instant of collision, and will have a new velocity vector from the collision resolution. There are a few ways we can go about getting that new velocity vector:

  • You can use vector projection to extract the components, and use them to construct the new velocity.
  • You can express the orientation as a transformation matrix, the flipping as another transformation matrix, compose them... and that is a bounce transformation matrix.
  • You can throw trigonometry at it.

I suggest the first path. It is the one that matches intuition more closely. Also optimizes well. Although, I will not be doing that in this answer.


What intuition?

Consider the simple case. If the ball were bouncing with a vertical wall, all you would do is flip the x axis of the velocity vector. If it were bouncing to an horizontal floor, all you would do is flip the y axis of the velocity vector. That is you flip the component that is normal to collision. We still need to do that, but with arbitrary orientations.

Basically, I'm saying that the collision flips the velocity along the normal of the surface, but not tangentially to the surface. The component that was going towards the obstacles is flipped so it goes away instead. In order words... it bounces.

Thus, the new velocity vector, will be the original velocity vector with the component normal to the collision flipped. Perhaps multiplied by some elasticity factor. But that is beyond the scope of the question.


As I was saying, you need to break the velocity vector into components. One component goes along the normal at the point of collision, the other goes tangent. Then you flip the normal component sign, compose it with the tangent component and that gives you the new velocity vector.

In case it is not clear, the components of the vector add up to the vector.

We have the velocity vector v, and the normal vector n. Then the velocity component along the normal is v⊥n (v projected on n) and the tangent component is v - v⊥n. Because the components add up to the vector.

Knowing that, we get new velocity vector by flipping v⊥n, which gives us -v⊥n and adding the other component (v - v⊥n). That is, v' = -v⊥n + v - v⊥n = v - v⊥n - v⊥n = v - 2*v⊥n.


Of course, to actually implement this, we a projection function. Assuming you do not have a library that offers such function, you can implement it like this:

v⊥a = (a/|a|)*(v·a)/|a|

Where |a| is the length of a, and · denotes dot product.

You can find this formula in any vector algebra or analytic geometry book. I will not explain how to derive it here.

As you probably know, |a| would be just Pythagoras, and · is the sum of the products of the components:

|a| = sqrt(a.x * a.x + a.y * a.y /*+ a.z * a.z*/)
a·b = a.x * b.x + a.y * b.y /*+ a.z * b.z*/

That is enough information to write some code:

//This code has not been optimized whatsoever

Vector Add(Vector a, Vector b)
{
    return Vector(a.x + b.x, a.y + b.y/*, a.z + b.z*/);
}

Vector Mult(Vector a, float s)
{
    return Vector(a.x * s, a.y * s/*, a.z * s*/);
}

float Dot(Vector a, Vector b)
{
    return a.x * b.x + a.y * b.y /*+ a.z * b.z*/;
}

float Norm(Vector a)
{
    return sqrt(a.x * a.x + a.y * a.y /*+ a.z * a.z*/);
}

Vector Normalize(Vector a)
{
    return Mult(a, 1/Norm(a));
}

Vector Project(Vector v, Vector a)
{
    return Mult(Normalize(a), Dot(v, a)/Norm(a));
}

Vector Bounce(Vector v, Vector n)
{
    return Add(v, Mult(Project(v, n), -2));
}

What angles?

| improve this answer | |
\$\endgroup\$
  • \$\begingroup\$ This is a very interesting idea . I will try to use this one now .I was using the velocity vector as you expected and i found his angle with the OX axes . imgur.com/a/6IYViJR I know the angle between this velocity vector and the surface it collides to and i was modifying this alpha angle to get a new alpha angle to use it again when another surface comes up. Initially i had the velocity vector just to move the center of the circle . \$\endgroup\$ – Michael Mar 24 at 10:29
  • \$\begingroup\$ on this line return Normalize(a) * Mult(Dot(v, a), 1/Norm(a)); Your subprogram Mult has as parameters a vector and a value but you use it here with 2 float values. If possible can you correct this? :D \$\endgroup\$ – Michael Mar 25 at 12:14
  • \$\begingroup\$ @Michael Oh, I did mix up my products when transcribing the formula. Fixed. Perhaps you can find useful How to Work With Arbitrarily Oriented Vectors (this time I looked there to double check). About optimizing the code, see SIMD and FMA. You may also find useful Performance Programming: Theory, Practice and Case Studies. I usually just tell people to use a library. \$\endgroup\$ – Theraot Mar 25 at 13:00

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.