Monday 10 June 2013

Unity3d Car Game Tutorial-10 (Adding Collision Avoidance Property To AI Cars Using Raycasting)

In this post of our tutorial series we will be looking into how o introduce the Collision Avoidance property to the AI cars that we added to our game in one of the previous posts. To do this we will be using a technique called as Raycasting.

Right so, the first question that comes to our minds is, what exactly is raycasting?
When I searched for its general definition, I found this, "Ray casting is the use of ray-surface intersection tests to solve a variety of problems in computer graphics." 
If the above definition doesn't clarify your doubts on raycasting, then here is the simplest possible line that I could think of to explain what is this Raycasting.
"Raycasting, as the name says is casting of rays, from a particular host object, along the 3d space, to detect possible collisions of the host object with the surrounding objects, having a so called Collider."

So hopefully that cleared some of the doubts, if not all. I promise to clear the rest of the doubts as we move on with this post.

To detect the collisions of the AICar with the surroundings, we will be using this raycasting. So how can we implement this raycasting?
The answer to this question lies in the script that we will be seeing now (Note that we will be using c# scripting in this tutorial, for a change. The reason is not only the change, but the scripting in c# lets you understand the code better.).

Create a c# script and name it as (say) Raycasting.

Now we will establish a direction(say along the 'x axis') for this ray to be casted along, this is done using the following statement:                                                                                                   
Vector3 forward = transform.TransformDirection(Vector3.forward) ;

Next we have to decide where this ray should start from, and for this application we want the ray to start  from the object which this script will be attached to i.e. the AICar. We do this using the following statement:
if(Physics.Raycast(transform.position, transform.forward,  5)) ---(1)          

  • This statement returns true if the ray is hitting a collider, else it returns a false.                                   
  • The '5' in the statement is the distance for which the ray is casted, from the object with the script.

Now we will use the  Debug.DrawRay to let us help visualize the casted ray, infact we will use the following statement:
Debug.DrawRay(transform.position, transform.forward*5, Color.green); ---(2)                                
which is pretty much self explanatory.

You might see that the rays casted are at the ground level, if you want to raise the rays above the ground you might want to do something like this:                                                                              
Vector3 strt;                                                                                                                                        
strt = transform.position;                                                                                                               
strt.y += .7f;                                                                                                                                     
What I did was to declare a new variable of type Vector3 and change the position of the transform i.e. transform.position        
                                                                                                          
- Now (1) and (2) would become                                                                                                                 if(Physics.Raycast(strt , transform.forward,  5)) ---(3)                                                                                       Debug.DrawRay(strt, transform.forward*5, Color.green); ---(4)       

Now we have casted a ray, what is remaining is we have to check if this ray is colliding with any of the colliders in the surroundings of the object to which this script is attached. To do that we use the following statements:                                                                                              
RaycastHit  hit;                                                                                                                                                
if(Physics.Raycast(strt,transform.forward, out hit, 5)) {                                                                            
if(hit.collider.gameObject.tag == "Player"){                             
Debug.DrawRay(transform.position, transform.forward, Color.red);                                         
}                                                                                                                                                       
}                                                                                                                                                       

  • Firstly we defined a variable of type RaycastHit to help us detect the collision.                                   
  • Next we modified the statement (3) to include this variable.                                                                         
  • Further we check if the casted ray is hitting any object which is tagged with the tag "Player".                         
  • If it does hit we are just changing the color of the ray (for now) from green to red to indicate the collision detection (You could also use Debug.Log and print something to indicate this as well.)                                                    
And as  a result we would see something like this on the gameObject (AICar here)


Once this is done what we have to add is the collision avoidance logic, whatever we did till now was the collision detectance thing.
Since we are talking about cars here we already have a target where the car should head towards i.e. the waypoints, now we will make the AICar avoid the obstacle in front of it by using the following statement:
transform.Rotate(Vector3.up, 90 * 5* Time.smoothDeltaTime); ---(5)

We avoid the obstacle by rotating the AICar in the Y axis. Vector3.up is as good as Vector3(0,1,0).
smoothDeltaTime is a smoothed out Time.deltaTime (Read Only), and we have multiplied it by some factors so as to increase the rotating angle. Since the car was already moving all we needed to do was to rotate it (towards right of the AICar here) to make sure it avoids the obstacle ahead. So the block of code now looks like:
if(Physics.Raycast(strt,transform.forward, out hit, 5)) {
if(hit.collider.gameObject.tag == "Player"){
transform.Rotate(Vector3.up, 90 * 5* Time.smoothDeltaTime);
       Debug.DrawRay(transform.position, transform.forward, Color.red);
 }
}

Next we will add two more rays so as to make it a better collision avoider using the following statements:
if(Physics.Raycast(rside,(transform.forward+transform.right*-.5f)*5, out hit, 5)) {
if(hit.collider.gameObject.tag == "Player"){
 transform.Rotate(Vector3.up, 90 * 2* Time.smoothDeltaTime);
Debug.DrawRay(transform.position, (transform.forward+transform.right*-.5f)*5, Color.red);
}
}
if(Physics.Raycast(fside,(transform.forward+transform.right*.5f)*5, out hit, 5)) {
if(hit.collider.gameObject.tag == "Player"){
          transform.Rotate(Vector3.up, -90 * 2* Time.smoothDeltaTime);
         Debug.DrawRay(transform.position , (transform.forward+transform.right*.5f)*5, Color.red);
}
}

The above two blocks of code will add two more rays and add to the robustness of the collision avoidance.


There are certain things which might throw some doubts, which is the transform.forwards and the transform.rights. The image below will help us clarify this doubt:


That image is bound to remind you of those 6th grade Math classes, and yeah this will help us clarify the questions which are on our mind now. I will list the questions, just in case:

  1. Why did i use addition of transform forwards and rights?
  2. How did we get those angled rays which are neither left nor right?


Now I will try to answer the above two questions:
You might have studied that the Y axis holds for 90 degrees and the X axis for 0 degrees. Now what do we do if we want to get a 45 degrees line, we just add the Y axis and X axis and divide them by two, the same concept is applied here.
NOTE: In unity there is no transform.left and we can play with the transform.right to make it into transform.left, you might as well have guessed from the codes above, we just negate the multiplying factors to make it align towards the left. It is just like left is negative x axis i.e. negative of right.

So we will get rays something like this:


This is all about the raycasting and collision avoidance. To make it work with the AICar, just attach the following script to the AICar and you're ready to go.
raycasting.
NOTE: Remember that the obstacles tagged with Player only are avoided and not the rest. And one more important thing is that the obstacles must and should have a collider installed in them for the obstacle avoidance to work.

Don't just copy that code blindly, try to experiment with it and then you'll get to know the magic of programming.
And yeah, just like this we are done with the understanding of Raycasting.

Share if you could grasp this concept of raycasting.

9 comments:

  1. This has to be the best post on raycasting I've ever read man... Thanks a ton!!

    ReplyDelete
    Replies
    1. You are welcome man.. Thanks for the feedback :)

      Delete
  2. I got the green rays, but on detecting the collision it is not turning into red and not avoiding the collision.. any clue what is happening.. and yes i ve tagged the object is to collided as player

    ReplyDelete
    Replies
    1. well, before you try out anything, create a cube in the path of the car, and of course tag it with 'Player' note the capital P... also you might want to add a box collider to it. Finally make sure that the rays are above the ground and are hitting the obstacles.. Let me know if it worked..

      Delete
  3. This comment has been removed by the author.

    ReplyDelete
  4. Excellent introduction to ray cast and obstacle avoidance. Thanks!

    ReplyDelete
  5. Thanks I'm trying and I don't know how do it :3

    ReplyDelete
  6. Niraj Vishwakarma1 June 2014 at 04:32

    I really appreciating your effort to make things clear. It is really helpful for me. Thanks :)

    ReplyDelete