Using RaycastHit in Unity to Detect and Manipulate Objects

unity's raycasthit tutorial

Using RaycastHit in Unity to Detect and Manipulate Objects

Introduction

Games often have a need for detecting where objects are in relation to other objects or interactions from the user. Usually, you can detect these interactions through collisions or triggers. Sometimes, you may only want to detect collisions in one direction or over a set path. For example, shooting a bullet or checking for obstacles in front of an enemy AI. Unity’s RaycastHit is the solution to these problems.

RaycastHit, in Unity, is a structured data object that is returned when a ray hits an object during a raycast. Some of the properties of the RaycastHit include collider, distance, rigidbody, and transform.

In this article we are going to discuss how to get RaycastHit data and how to access and use the properties it provides.

Unity’s RaycastHit

To store a RaycastHit we must declare an empty variable with the type RaycastHit. Now, when we call our Raycast method we can use the keyword ‘out’ and pass in our variable to store it. In this simple example, we call Raycast in our if statement. It is called here because it will return true if there is a hit. Afterward, we get the name of the object stored in our RaycastHit variable and print it to the console.

    void OnClicked()
    {
        Ray ray = Camera.main.ScreenPointToRay(Mouse.current.position.ReadValue()
);
        RaycastHit hit;
 
        if (Physics.Raycast(ray, out hit))
        {
            Debug.Log("Clicked on " + hit.transform.name); 
        } 
        else 
        {
            Debug.Log("Nothing hit");
        }
   }

To verify our scripts work we have created a simple scene with a camera, cube, sphere, and input system. Now, we can test our RaycastHit by attaching the script to our camera. Here we have set up Input Actions with a Clicked action that listens for a left click. Check out our post on Unity’s Input Actions for more info on how they work. Now when we click either the sphere or cube it prints the name of the object to the console.

Unity RaycastHit

RaycastHit2D vs RaycastHit

RaycastHit is used for physics in a 3D representation of the world. RaycastHit2D uses roughly the same methods we will discuss below but using physics for a 2D world. The methods and use cases we discuss are still applicable but remember to swap the 3D values for 2D equivalent metrics. For example, Vector3 and Rigidbody variables with Vector2 and Rigidbody2D variables.

How to Get the Object Hit with a Raycast

As stated in previously, we get our RaycastHit object from a raycast. We did that inside of an if statement using the ‘out’ keyword. We could avoid the if statement like so.

    Ray ray = Camera.main.ScreenPointToRay(Mouse.current.position.ReadValue());
    RaycastHit hit;
 
    Physics.Raycast(ray, out hit);

But doing it this way can cause issues if we later try to reference the RaycastHit and it is null. This can happen when the Raycast misses an object. For that reason, we use the if statement to guarantee that our hit is not empty when we try to use data. Raycast returns true on a hit and false for a miss.

        Ray ray = new Ray(transform.position, Vector3.up);
        RaycastHit hit;
 
        if (Physics.Raycast(ray, out hit))
        {
            // Do Something with the hit 
        }

Storing the GameObject from RaycastHit

A common use case for the RaycastHit is to manipulate the GameObject that was hit by the ray. We can retrieve and store the GameObject by setting a GameObject field at the top of our script. Using RaycastHit.transform we can get the GameObject and assign it to the field if there is a hit. If the ray does not hit an object or hits the wrong object we can then set our GameObject field to null.

    private GameObject GameObjectHit;
 
    void OnClicked()
    {
        Ray ray = new Ray(transform.position, Vector3.up);
        RaycastHit hit;
 
        if (Physics.Raycast(ray, out hit))
        {
            GameObjectHit = hit.transform.gameObject;
        }
        else
        {
            GameObjectHit = null;
        } 
   }

Back in our sample scene, we can see that now, when we click on either the sphere or cube, the GameObject is stored in our variable.

Storing the GameObject that was Hit

RaycastHit Tag

We can also use the same reasoning to get the hit GameObject’s tag and compare it to other tags. We can use this to single out specific types of GameObjects. For example, if you have a magnet and you only want it to affect objects hit with the tag “metal”.

        Ray ray = new Ray(transform.position, Vector3.up);
        RaycastHit hit;
 
        if (Physics.Raycast(ray, out hit))
        {
            if(hit.transform.gameObject.CompareTag("Cube"))
            {
                Debug.Log("Tis only a scratch");
            }
        }

Once again, in our sample scene, when we click on the cube, which has been tagged with the “Cube” tag, we see the string print to the console. When we click on the sphere, nothing happens.

RaycastHit Tag

RaycastHit Collider

RaycastHit also provides us with the collider property. We can use this to disable/enable the collider on hit. This is useful for doing things like temporarily destroying barriers. For a more permanent solution, you can also destroy the GameObject when it is hit.

        Ray ray = new Ray(transform.position, Vector3.up);
        RaycastHit hit;
 
        if (Physics.Raycast(ray, out hit))
        {
            if(hit.collider != null)
            {
                Destroy(hit.transform.gameObject);
            }
        }

Continuing with our example, we can now click our cube and it will be destroyed.

RaycastHit Collider

RaycastHit Position

One of the more useful properties that RaycastHit provides is point. Point provides the exact point of contact the ray makes with an object. You can use this to apply force to an object where it is hit, creating realistic impacts for bullets. Another possibility is to use the RaycastHit point to teleport your player to the location hit.

        Ray ray = new Ray(transform.position, Vector3.right);
        RaycastHit hit;
 
        if (Physics.Raycast(ray, out hit))
        {
            transform.position = hit.point;
        }

Applying our script to the sphere object and clicking now causes the sphere to teleport into the cube. If you wanted to teleport next to the object without intersecting it, you would need to apply an offset to the point.

RaycastHit Position

RaycastHit Transform

We can also directly access the transform of the object we hit. Transform will allow us to manipulate position, rotation, and scale associated with the object hit. For example, you could create a ray gun that shrinks or grows objects it hits.

        Ray ray = Camera.main.ScreenPointToRay(Mouse.current.position.ReadValue());
        RaycastHit hit;
 
        if (Physics.Raycast(ray, out hit))
        {
            hit.transform.localScale = hit.transform.localScale * 3;
        }

With the script attached to our camera, we can now click on our cube to increase the size by a factor of three.

Adjust Hit Objects Transform Scale

RaycastHit Distance

The distance between the origin of the raycast and the object hit can also be accessed easily with the RaycastHit property distance. Distance will return a float value. If you have an enemy that needs to patrol a specific path you can use this to have them turn around or move away from obstacles if they are getting too close. Another possibility is to use the distance value to decrease damage done to an opponent that is further away.

        Ray ray = Camera.main.ScreenPointToRay(Mouse.current.position.ReadValue());
        RaycastHit hit;
 
        if (Physics.Raycast(ray, out hit))
        {
            int damage;
 
            if(hit.distance > 50f)
            {
                damage = 5;
            }
            else if(hit.distance > 25f)
            {
                damage = 25;
            }
            else
            {
                damage = 50;
            }
        }

RaycastHit Normal

Normal values are the more difficult values to grasp. Basically, they return a Vector that is perpendicular to the surface where the hit occurred. This is great for determining things like the surface angle. Here is an image to help clarify what is going on.

unity normal value example

Also, referencing the RaycastHit normal value allows you to determine the way an object, like a laser, should reflect or bounce off another. The best example of this is the one pulled directly from the Unity Documentation.

        Ray ray = Camera.main.ScreenPointToRay(Mouse.current.position.ReadValue());
        RaycastHit hit;
 
        if (Physics.Raycast(ray, out hit))
        {
            Vector3 incomingVec = hit.point - transform.position;
 
            Vector3 reflectVec = Vector3.Reflect(incomingVec, hit.normal);
 
            Debug.DrawLine(transform.position, hit.point, Color.red);
            Debug.DrawRay(hit.point, reflectVec, Color.green);
        }

Attach this to your camera. Now, when you click on an object a line will be drawn in the scene view. The line is red when fired at the object but then turns green once it reflects off the object.

And now you are ready to utilize RaycastHit in the games you create with Unity. Thank you for stopping by. Stick around and check out more of our tutorials or posts like our piece on Create a Moving Platform the Player Character Can Stand On. Also, leave a comment telling us what you liked or did not like about the tutorial. Was it easy to follow along? What do you want to learn next? As always check out some of our published apps below.

Leave a Comment

Your email address will not be published. Required fields are marked *