1
votes

I'm trying to make a Billiard game and I wanna calculate the direction on which the Cue Ball(white ball) will be moving after it hits another ball.

Visuals

As you can see I wanna calculate the angle/direction in which the RAY hits the ball and the angle/direction on which the raycast will change its direction into. I need the angle to display as a Vector3 variable so I can use it on the linerenderer(3).

I already calculated the direction that the ball that gets hit will go.

If you could help me on this that would be great!

Current code:

RaycastHit hitz;
if (Physics.SphereCast(transform.position, 0.8f, location - transform.position, out hitz, Mathf.Infinity, lmm2))
{

    lineRenderer2 = hitz.collider.GetComponentInChildren<LineRenderer>();
    lineRenderer2.SetVertexCount(2);

    if (!Input.GetKey(KeyCode.Mouse0))
        lineRenderer2.SetPosition(0, hitz.point);

    if (!Input.GetKey(KeyCode.Mouse0))
       {
           Vector3 start = hitz.point;
           Vector3 end = start + (-hitz.normal * 4);

           if (lineRenderer2)
           {
               if (!Input.GetKey(KeyCode.Mouse0))
                   lineRenderer2.SetPosition(1, end);
           }

           if(lineRenderer3)
           {
               anglelel = Vector3.Angle(hitz.normal, hitz.point);
               Vector3 cross = Vector3.Cross(hitz.normal, hitz.point);
               if(cross.y > 0)
               {

                    tzt = Quaternion.AngleAxis(90f, hitz.normal) *realStick.transform.forward;
               }
              if (cross.y < 0)
               {
                  anglelel = -anglelel;
                  tzt = Quaternion.AngleAxis(270f, hitz.normal) * realStick.transform.forward;
               }
               Vector3 start2 = hitz.point;
               Vector3 end2 = start2 + ((tzt) * 5f);
               lineRenderer3.SetPosition(0, hitz.point);
               lineRenderer3.SetPosition(1, end2);
           }
        }
}

Thank you for your time.

Edit:

This part of the code has been changed to this one, currently makign some progress but still, it's not good enough. Before

if(lineRenderer3)
        {
            Vector3 start2 = hitz.point;
            //THIS IS WHERE I'M CURRENTLY STUCK AT
            Vector3 end2 = start2 + (hitz.point * 0.7f); 
            lineRenderer3.SetPosition(0, hitz.point);
            lineRenderer3.SetPosition(1, end2);
         }

After

if(lineRenderer3)
{
     anglelel = Vector3.Angle(hitz.normal, hitz.point);
     Vector3 cross = Vector3.Cross(hitz.normal, hitz.point);
     if(cross.y > 0)
     {

          tzt = Quaternion.AngleAxis(90f, hitz.normal) *realStick.transform.forward;
     }
      if (cross.y < 0)
      {
          anglelel = -anglelel;
          tzt = Quaternion.AngleAxis(270f, hitz.normal) * realStick.transform.forward;
       }
       Vector3 start2 = hitz.point;
       Vector3 end2 = start2 + ((tzt) * 5f);
       lineRenderer3.SetPosition(0, hitz.point);
       lineRenderer3.SetPosition(1, end2);
  }
1
This is more a physics problem than strictly a game coding one. If you're trying to visualize the outcome of applying a force at that point on the cue ball, you'll need to perform calculations using its physical attributes, and not just things like face normals. Here's the concept to get you started - you'll need to translate it into code though: physics.stackexchange.com/questions/43232/…Serlite
Not quite what I was looking for. The problem that they're talking about is in a 2D space, while my game is in 3D.Ssiro
Your game is rendered in 3D, but unless your billiard table isn't flat, all the physics can be simplified to 2D since they all will remain on the XZ plane.Serlite
Just curious, is the phsyx engine not working this out properly for you? or are you trying to make some type of visualizer?Xander Luciano
@XanderLuciano Based on his usage of line renderers, he's likely trying to provide a visualization of predicted ball trajectories.Serlite

1 Answers

4
votes

Let's take this piece by piece. First off, this is a classic Physics 101 problem. The angle 2 billiard balls make on impact is a perfect 90 degree angle. Note how the green and blue vector in the following picture make a right angle:

Physics of a pool ball

Now, you should also notice that from the point of contact to the center of both balls is normal to the surface of both balls. This means that in unity, we can use the hit.normal to get the direction of travel for the ball we hit. We just need to invert it by doing: -1 * hit.normal

Now, to get the direction the cue ball travels, we just need to rotate the previous vector 90 degrees. We can do this with a quaternion. We create a 90degree rotation about the up direction (or whatever direction is normal to the pool table) by doing: Quaternion.AngleAxis(-90, Vector3.up)

We can then calculate the angle between the original vector of travel and the angle the cue ball will travel at by doing Vector3.Angle(-1 * cue.up, rotate90 * hit.normal)

Let's look at this visual example from my test scene:

Unity pool table

I color coded the vectors in unity to match the diagram above. The only difference you may notice is the black vector, which represents our hit.normal.

Here's the code:

public class Main : MonoBehaviour {
    public Transform cue,cueBallPostHit;
    public int dist = 10;
    public Color red,green,blue;

    RaycastHit hit;
    float scale,ballAngle;
    Quaternion rotate90;
    Vector3 cueBallHitPosition;

    void Start () {
        rotate90 = Quaternion.AngleAxis(-90, Vector3.up);
    }

    void FixedUpdate () {
        if(Physics.SphereCast(cue.position, .5f, cue.up, out hit, dist))
        {
            // Calculate variables
            cueBallHitPosition = hit.point + (.5f * hit.normal);
            scale = (cue.position - hit.point).magnitude;
            ballAngle = Vector3.Angle(-1 * cue.up, rotate90 * hit.normal);
            print(ballAngle);

            // Cue Ball Direction and normal
            Debug.DrawLine(cue.position, cueBallHitPosition, red);
            Debug.DrawRay(cueBallHitPosition, hit.normal, Color.black);
            // Ball direction
            Debug.DrawRay(hit.point + (-.5f * hit.normal), -1 * hit.normal * scale, blue);
            // Cue Ball Direction
            Debug.DrawRay(cueBallHitPosition, rotate90 * hit.normal * scale, green);

            // Visual for where the ball will hit
            cueBallPostHit.position = cueBallHitPosition;
        }
        else
        {
            Debug.DrawRay(cue.position, cue.up * dist, blue);
            cueBallPostHit.position = cue.position + (2 * cue.up);
        }
    }
}

Hopefully that should be enough to help you get started in the right direction, but if you have questions, let me know and I'll add some more explanations.