To not miss out on any new articles, consider subscribing.
Introduction
If you’re developing a game in Unity, with an enemy and another player in the game, would you like to set a trigger for the enemy to carry out an action once it sights the player? In general, have you ever wanted to find out all the objects that a certain object can see in a Unity environment? Raycasting can be used to solve this.
What is Raycasting?
Raycasting in Unity is a Physics function applied to a GameObject by sending out a ray from the GameObject to a given direction. It is done by importing already-built Physics functions into a C# script and adding the script as a GameObject’s component. Raycasting in Unity could either return the first game object hit by the ray or all the objects that are hit by the ray projected in the given direction. However, it only returns objects with colliders (not set as triggers) attached to the objects; therefore, to get complete results, all assets and prefabs in the environment need collider components. You can add a collider to an object in the environment, by viewing the object in the Inspector, clicking on Add component, and selecting a collider. A box collider is the simplest collider to add to objects and you can add this for raycasting purposes, as shown in the image below.
In this article, I will explain raycasting in Unity, mention some applications of this technique, the differences between the different raycasting functions available (Linecast vs. Raycast vs. RaycastAll), different ways to raycast, as well as a walkthrough of this in a demo Unity project.
Applications of raycasting in Unity
As mentioned in the introduction paragraph, raycasting in Unity is used to check for detection/line of sight between two objects in an environment. Alternatively, raycasting can also be used to find the height of a plane or a position in the environment. This could be done by raycasting directly below the object from an extremely far height and returning the height (y-value) of the point at which the ray intersects the plane underneath. While this is not a very common application of raycasting, it is very helpful in computing the elevation or depth of a position in an environment.
Unity project
For this article, I set up a Unity project, which can be found on my Github, to demonstrate raycasting. I created an empty project and then imported the free Simplepoly City Low Poly asset. This asset is a collection of low poly assets for creating city-based games like buildings, trucks, buses, cars, roads, street lights, road signs, trees, bushes, rocks, and grass among other objects.
I added a light gray-colored sphere GameObject to the asset, as seen in the scene image of the environment below, with a camera component. This is the GameObject that I will add the raycast script to.
Physics.Raycast()
The first raycasting function from Unity that I will cover in this article is Physics.Raycast(). This function takes in the source position, the direction to cast the ray to, a variable to save the object that might be hit by the ray, additional constraints like the maximum distance for the ray to extend out to, and a layer mask. This layer mask is used to exclude or only include certain objects in the ray casting. For example, if you want to get the first object in the line of sight from a certain vantage point that is not a road sign, you can use the layer mask variable to exclude road signs from the ray cast. This is an optional parameter to be used only if you need it and I discuss this further in a subsequent section.
The Raycast function returns a boolean stating whether an object is hit or not from the source in the target direction set and saves the first object that is hit to the RaycastHit variable that is passed as one of the parameters when the function is called. This RaycastHit object that is saved has the object name, tag, layer, distance, and point attributes attached to it, as well as inheriting attributes attached to the GameObjects.
void RayCast_fn()
{
Debug.Log("Raycast from " + sourcePosition + " to " + targetDirection);
if(Physics.Raycast(sourcePosition, targetDirection, out hit, Mathf.Infinity))
{
Debug.Log("Object name and position");
Debug.Log(hit.transform.gameObject.name + " at " + hit.point + ", with ray magnitude (distance) = " + hit.distance);
Debug.Log(hit.transform.gameObject.tag);
Debug.Log(hit.transform.gameObject.layer);
}
}
The function above casts a ray from the source position to the target direction and prints a log of the first object hit by this ray, with its position in the environment, the distance of the object from the source, and the object’s tag and layer value.
How to layer masks
To either exclude or only include certain objects from the ray casting results, the layer(s) value of such objects is passed as a layer mask when calling the Raycast function. The layer mask is set by getting the index value of the desired layer in the Unity asset–in this case, the road signs layer–then bit-shifting the index integer to generate a bit mask, and negating this bit mask to exclude collisions by the ray on road signs. Sometimes, some objects/assets in the Unity project might not be tagged or labeled properly, so you need to assign the labels properly to the objects before running the Raycast function for accurate results.
void Layermask_fn(Vector3 position)
{
Debug.Log("RaycastAll from " + sourcePosition + " to " + position);
Vector3 direction = sourcePosition + position;
//The traffic signal assets were assigned to Layer 6 in the project.
//Here, I create a bit mask for that layer by bit shifting the index. This cast rays against colliders in that layer only.
int layer6_bitMask = 1 << 6;
// To exclude objects (colliders) in that layer from the ray cast, I negate the bit mask.
layer6_bitMask = ~layer6_bitMask;
hits = Physics.RaycastAll(sourcePosition, direction, Mathf.Infinity, layer6_bitMask); // This excludes traffic signal objects from being hit by the ray.
Debug.Log("Number of objects hit = "+ hits.Length);
for (int i = 0; i < hits.Length; i++)
{
RaycastHit hit = hits[i];
Debug.Log("Object name and position");
Debug.Log(hit.transform.gameObject.name + " at " + hit.point + ", with ray magnitude (distance) = " + hit.distance);
Debug.Log(hit.transform.gameObject.tag);
Debug.Log(hit.transform.gameObject.layer);
}
}
Calculating direction from two known positions
In the previous scenarios, we have ray cast from a game object as the source to a given direction. However, what if you want to ray cast to a particular target object (position) and not necessarily a given direction? To do this, you can obtain the transform positions of the source object and the target object, and calculate the direction of the target object from the source object.
Vector3 direction = sourcePosition - targetDirection;
You can also use the Physics.Linecast() function, which I discuss in the section after the next, to cast a line from a start position to a target position without calculating direction.
Physics.RaycastAll()
There are some other functions that carry out raycasting in Unity apart from Physics.Raycast(). The first function I’ll discuss is Physics.RaycastAll(). As opposed to the Physics.Raycast() function, Physics.RaycastAll() does not return a boolean value or just the first object that the ray hits. Rather, it returns an array of all the objects hit by a ray extended from a source position to a target position, with the attributes of these RaycastHit objects.
void RaycastAll_fn()
{
Debug.Log("RaycastAll from " + sourcePosition + " to " + targetDirection);
Vector3 direction = sourcePosition - targetDirection;
hits = Physics.RaycastAll(sourcePosition, direction, Mathf.Infinity);
Debug.Log("Number of objects hit = "+ hits.Length);
for (int i = 0; i < hits.Length; i++)
{
RaycastHit hit = hits[i];
Debug.Log("Object name and position");
Debug.Log(hit.transform.gameObject.name + " at " + hit.point + ", with ray magnitude (distance) = " + hit.distance);
Debug.Log(hit.transform.gameObject.tag);
Debug.Log(hit.transform.gameObject.layer);
}
}
The function in the code snippet uses the RaycastAll() function to cast a ray from the source position to the target direction, obtains an array of the objects hit, and prints the some details of these objects in the console in Unity Editor as shown below.
Physics.Linecast()
Physics.Linecast(), on the other hand, extends an imaginary line from a start position to an end position, returning true if there is an object colliding with the line. This function also has parameters like layer mask and the object hit with its attributes are stored in a RaycastHit variable object. It works for ray casting to a target with a known location in the world, as opposed to a target direction.
While Physics.Linecast() is similar to Physics.Raycast(), Physics.Linecast() is from a start and end position in world space. Physics.Raycast(), on the other hand, is casting a ray from an origin position in a specific direction, and it allows you to cast an infinite ray. Physics.Linecast() is useful if you know the exact position of the source game object and target object and want to check for an object between both positions, while you can use Physics.Raycast if you know the position of the source game object and the maximum distance (can be up to infinity) in the desired direction you want to cast the ray to.
void LineCast_fn()
{
Debug.Log("Linecast from " + sourcePosition + " to " + camera.transform.TransformDirection(Vector3.down));
Physics.Linecast(sourcePosition, camera.transform.TransformDirection(Vector3.down), out hit);
Debug.Log("Object name and position");
Debug.Log(hit.transform.gameObject.name + " at " + hit.point + ", with ray magnitude (distance) = " + hit.distance);
Debug.Log(hit.transform.gameObject.tag);
Debug.Log(hit.transform.gameObject.layer);
}
This function casts a line from a vector position (0.0, 5.0, 0.0) to underneath it, which is vector position (0.0, -1.0, 0.0), which returns the Road Corner as the object on the ground at that position.
Conclusion
In this article, I walked through using the Raycast, RaycastAll, and Linecast C# Physics functions in Unity to obtain details of game objects in the line of sight of a source object in an environment. In addition to explaining the applications and the different function behaviors, I also include sample code blocks in a demo project with snapshots of the results logged in the Console. You can find the full script here and the project used on my GitHub.
In general, I hope this article has been helpful in explaining ray casting in Unity, its applications, constraints, and the different functions with sample code. Please drop a comment if this was helpful to you in any way, or if you have questions or suggestions. You can also reach out to me on Twitter, or LinkedIn, or send an email: contactaniekan at gmail dot com.
Thank you for reading.
Aniekan.
To not miss out on any new articles, consider subscribing.
Official documentation
- https://docs.unity3d.com/ScriptReference/Physics.Raycast.html
- https://docs.unity3d.com/ScriptReference/Physics.RaycastAll.html
- https://docs.unity3d.com/ScriptReference/Physics.Linecast.html
To not miss out on any new articles, consider subscribing.
