- Home /
Predicting ball direction on collision
I am trying to have a aim mechanism for my pool game. I am trying to use LineRenderer and RayCast for that. The LineRenderer renders a line from Cue ball and when it hits any other ball, it shows the path of cue ball and renders another line for the path of the other ball. I just want to do it for the first degree of collision, means it should get rendered for just the first collision, so player can get to know the direction of both Cue ball and the aimed ball on hitting.
I've tried to use raycast and Physics.Reflect() and am successful in drawing lines. The problem is the angle and direction is not accurate. I've an idea about physics and maths, but don't know what am I missing here.
Here's my code. I've attached the script to a gameobject which has the LineRenderer component for rendering the Cue Ball aim.
[RequireComponent (typeof (LineRenderer))]
public class RayCastReflection : MonoBehaviour
{
//this game object's Transform
public Transform goTransform;
//the attached line renderer
private LineRenderer lineRenderer;
//List of all the linerenderer for balls other than Cue ball, to destroy them later.
private List<LineRenderer> lineList = new List<LineRenderer>();
private float hitAngle;
//a ray
private Ray ray;
//a RaycastHit variable, to gather informartion about the ray's collision
private RaycastHit hit;
//reflection direction
private Vector3 inDirection;
//the number of reflections
public int nReflections = 1;
//the number of points at the line renderer
private int nPoints;
public Transform mainCamera;
public bool isCueEnable;
public float dirx = 0;
public float diry = 0.35f;
public float dirz = 0;
void Awake ()
{
//get the attached LineRenderer component
lineRenderer = this.GetComponent<LineRenderer>();
}
void Update ()
{
//clamp the number of reflections between 1 and int capacity
nReflections = Mathf.Clamp(nReflections,1,nReflections);
//cast a new ray forward, from the current attached game object position
ray = new Ray(goTransform.position,goTransform.forward+ new Vector3(0,0.35f,0));
//represent the ray using a line that can only be viewed at the scene tab
//Debug.DrawRay(goTransform.position,(camera.forward+ new Vector3(0,0.35f,0)) * 100, Color.magenta);
//set the number of points to be the same as the number of reflections
nPoints = nReflections;
//make the lineRenderer have nPoints
lineRenderer.SetVertexCount(nPoints);
//Set the first point of the line at the current attached game object position
lineRenderer.SetPosition(0,goTransform.position);
for(int i=0;i<=nReflections;i++)
{
//If the ray hasn't reflected yet
if(i==0)
{
//Check if the ray has hit something
if(Physics.Raycast(goTransform.position,mainCamera.forward+new Vector3(0,0.35f,0) , out hit, 100))//cast the ray 100 units at the specified direction
{
//the reflection direction is the reflection of the current ray direction flipped at the hit normal
inDirection = Vector3.Reflect(ray.direction,hit.normal);
//cast the reflected ray, using the hit point as the origin and the reflected direction as the direction
ray = new Ray(hit.point,inDirection);
//Draw the normal - can only be seen at the Scene tab, for debugging purposes
Debug.DrawRay(hit.point, hit.normal*3, Color.red);
//represent the ray using a line that can only be viewed at the scene tab
Debug.DrawRay(hit.point, inDirection*100, Color.blue);
//Print the name of the object the cast ray has hit, at the console
//Debug.Log("Object name: " + hit.transform.name);
RenderBranch(hit.transform);
//if the number of reflections is set to 1
if(nReflections==1)
{
//add a new vertex to the line renderer
lineRenderer.SetVertexCount(++nPoints);
}
//Adjustment, so that the ray doesn't bounce off the table.
if(hit.point.y!=goTransform.position.y){
hit.point = new Vector3(hit.point.x,goTransform.position.y,hit.point.z);
}
//set the position of the next vertex at the line renderer to be the same as the hit point
lineRenderer.SetPosition(i+1,hit.point);
//test
Vector3 targetDir = inDirection - goTransform.position;
Vector3 forward = goTransform.forward;
hitAngle = Vector3.Angle(targetDir, forward);
//Debug.Log(hitAngle);
}
}
else // the ray has reflected at least once
{
//Check if the ray has hit something
if(Physics.Raycast(ray.origin,ray.direction, out hit, 100))//cast the ray 100 units at the specified direction
{
//the refletion direction is the reflection of the ray's direction at the hit normal
inDirection = Vector3.Reflect(inDirection,hit.normal);
//cast the reflected ray, using the hit point as the origin and the reflected direction as the direction
ray = new Ray(hit.point,inDirection);
//Draw the normal - can only be seen at the Scene tab, for debugging purposes
Debug.DrawRay(hit.point, hit.normal*3, Color.green);
//represent the ray using a line that can only be viewed at the scene tab
Debug.DrawRay(hit.point, inDirection*100, Color.black);
//Print the name of the object the cast ray has hit, at the console
//Debug.Log("Object name: " + hit.transform.name);
//add a new vertex to the line renderer
if(hit.point.y!=goTransform.position.y){
hit.point = new Vector3(hit.point.x,goTransform.position.y,hit.point.z);
}
lineRenderer.SetVertexCount(++nPoints);
//set the position of the next vertex at the line renderer to be the same as the hit point
lineRenderer.SetPosition(i+1,hit.point);
}
}
}
}
//To render the line renderer from the aimed ball.
void RenderBranch(Transform hitTransform){
if(hitTransform.gameObject.CompareTag("ball")){
LineRenderer line = hitTransform.gameObject.GetComponent<LineRenderer>();
if(!line){
line = hitTransform.gameObject.AddComponent<LineRenderer>();
lineList.Add(line);
}
RaycastHit hitRay = new RaycastHit();
Vector3 camForward = new Vector3(mainCamera.forward.x,mainCamera.forward.y,mainCamera.forward.z);
Physics.Raycast(hitTransform.position,-inDirection,out hitRay);
line.SetPosition(0,hitTransform.position);
Vector3 hitPoint = hitRay.point;
// Vector3 newVec = hitTransform.position-goTransform.position;
// Vector3 normalVec = Vector3.Cross(hitPoint,newVec);
//
// hitPoint = normalVec;
if(hitPoint.y!=goTransform.position.y){
hitPoint = new Vector3(hitPoint.x,goTransform.position.y,hitPoint.z);
}
line.SetPosition(1,hitPoint);
line.SetWidth(0.1f,0.1f);
foreach(LineRenderer l1 in lineList){
if(l1!=line || !isCueEnable)
Destroy(l1);
}
}else{
foreach(LineRenderer l1 in lineList){
Destroy(l1);
}
}
}
}