Learn and Understand Raycasting in Unity3D

You can download the assets used in this tutorial from:
3D character model was created using Autodesk Character Generator
2D sprite was given to me free from Kennynl at Kenney • Tanks

The tutorial source files are located here.
Today, we will talk about Raycasting. To those unfamiliar with the term Raycasting, let’s give a bit of an explanation of what it is before we begin.

become a professional vr game developer with unity

Pre-Order The Complete Virtual Reality Game Development with Unity and learn to create immersive games and experiences by building 10 VR games. The course assumes no prior Unity or VR experience – We’ll teach you C#, Unity and 3D programming from the ground-up

Check it out on Zenva Academy and get Early Access!

What is Raycasting?

“Raycasting is the process of shooting an invisible ray from a point, in a specified direction to detect whether any colliders lay in the path of the ray.”
This is useful with side scrolling shooters, FPS, third person shooters, bullet hell, and even adventure games. Being able to trace where a bullet or laser is going to travel from start to finish means that we know exactly how it should behave. We can physically watch it and manipulate it in the game world.

Raycasting in Unity3D is broken down into two distinct parts, 2D and 3D. Both of which are physics objects. They have their own documentation for the methods they provide; 3D and 2D respectively, however, both of which use the same game object (the line renderer) for both 2D and 3D games.

Getting Started

Before we begin, lets create an empty 3D project. Since this project will utilize both 2D and 3D, it is fairly simple to convert to 2D for a scene later on.

Create 5 total folders in the Assets folder. Models, Scenes and Scripts. Inside the Models folder, create 2 folders called 2D Art and 3D Art.

Project Begin

Import the art into their respective folders.

Project Asset Import

Now, create and save 2 scenes. Name them 2D and 3D respectively.

Project Scene Setup

Load the 2D scene and lets begin the lesson for Raycasting in Unity3D for 2D games.

Raycasting in 2D

To begin, remove the directional light. We click 2D on the scene view and change the camera from Perspective to Orthographic.

2DScene Setup

The tank spritesheet should have the texture type set to Sprite (2D and UI) and the Sprite Mode is set to Multiple. Now select apply.

2DScene Sprite Setup

Click on the Sprite Editor and now we can begin to slice the spritesheet into individual sprite objects.

Click on Slice. It will pull up a prompt, we will keep the slice type to be Automatic, and click Slice in the menu. The last step is to click on Apply.

SliceSpriteSheet

Static image example:

It will take us back to the standard UI of Unity3D. The Tanks spritesheet will have many individual sprites in the subsprite under tanks_spritesheetRetina. We will use tanks_spritesheetRetina_0.

SlicedSpriteSheetSelection

Drag the sprite we want to use onto the Scene View. The x position should be -7.91 and the y position should be 0.75.

SpriteUtilizedInScene

Click add component, the component we want to add is a Line Renderer. the Line Renderer is located in Effects.

2D LineRenderer Location

Create a script called TwoDRayCasting and attach it to the tanks object. Make sure the Line Renderer has a width of 0.25

ScriptToTankImage1

Now, we can write our code.

using System.Collections;
using UnityEngine;

public class TwoDRayCasting : MonoBehaviour
{
    LineRenderer line;

    private void Start()
    {
        line = gameObject.GetComponent<LineRenderer>();
        line.enabled = false;
    }

    private void Update()
    {
        if (Input.GetButtonDown("Fire1"))
        {
            StopCoroutine("fireLazer");
            StartCoroutine("fireLazer");
        }
    }

    private IEnumerator fireLazer()
    {
        line.enabled = true;

        while (Input.GetButton("Fire1"))
        {
            line.SetPosition(0, new Vector3(transform.position.x + .92f, transform.position.y + 0.41f));
            line.SetPosition(1, new Vector3(transform.position.x + 10f, transform.position.y + 0.41f));
            yield return null;
        }

        line.enabled = false;
    }
}

Let’s dissect the code to make it much more understandable.

// This allows us to access the Line Renderer component
 LineRenderer line;
    private void Start()
        {
    // Since the Line Renderer is a private object, we should make //sure we can access the component later on. So get the //component to be safe.
            line = gameObject.GetComponent<LineRenderer>();
     
    // We want the LineRenderer to be false to manually manipulate //when it is turned on and off.
            line.enabled = false;
        }
    private IEnumerator fireLazer()
        {
    // set the line to be enabled at the start of the method.
            line.enabled = true;
     
    // we want this code to only work while the condition is true.
    // In this case it is the built in Mouse 0 click event.
            while (Input.GetButton("Fire1"))
            {
    // Set position for the line. It takes an index and Vector3 position.
    // We set the index to be 0 since it is the first one in the array.
    // We set the vector 3 to be the tank's x and y position + an offset.
    // Since we are working in 2D, we don't need a value for Z so it is assumed
    // to be 0. 
            line.SetPosition(0, new Vector3(transform.position.x + .92f, transform.position.y + 0.41f));
            line.SetPosition(1, new Vector3(transform.position.x + 10f, transform.position.y + 0.41f));
    // next we yield return. Why? Because it works differently from the standard way in C#.
    // The yield statement is a special kind of return, that ensures that the function will continue from the line after the yield statement next time it is called.
                yield return null;
            }
     
    // next we disable the line again.
     
            line.enabled = false;
        }
    private void Update()
        {
    // We only want the line to render when the fire button is pressed.
            if (Input.GetButtonDown("Fire1"))
            {
    // check to be sure the line is not on and turn if off if it is
                StopCoroutine("fireLazer");
    // turn on the line.
                StartCoroutine("fireLazer");
            }
        }

Press the play button and try it out. To control the laser, press the left mouse button.

2D Animation example:

Next up, we will create a horrible animation and do the raycasting with it. Multi click on images number 0, 1, 5 and 6; Drag it onto the canvas. It will open a save prompt. I kept the name as New Animation and saved it into the folder 2D Art.

2DAnimationPt1

The position of the new tank should be -7.91, -0.3, 0. Add the Line Renderer component and change the width of the line renderer to 0.25.

2DAnimationRenderer

Attach the script to the tank as before.

2DAnimationFinal

Run it, prepare for an epileptic seizure from the animation.

Raycasting in 3D

Now we can get to the part I know you guys have been waiting ever so patiently for, 3D raycasting. This one is a bit more complicated, but not that much more complicated. I will go over raycasting as if you were building a side scroll platformer with shooting mechanics and a first person shooter where you shoot a blast like you building are a comic book / anime hero game.

First on the chopping block is we will write the script for both the side scroll and first person mode. I know it is a change in pace on how I do things normally, it will make it a lot easier to show the mundane tasks of attaching empty game objects and instantiating the renderer appropriately.

The Scripts:

Side scroll script

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class ThreeDRayCastingSideScrollMode : MonoBehaviour
{
    LineRenderer line;

    private void Start()
    {
        line = gameObject.GetComponent<LineRenderer>();
        line.enabled = false;
    }

    private IEnumerator fireShot()
    {
        line.enabled = true;

        while (Input.GetButton("Fire1"))
        {
            Ray ray = new Ray(transform.position, transform.right);

            line.SetPosition(0, ray.origin);
            line.SetPosition(1, ray.GetPoint(-10) * .24f);

            yield return null;
        }

        line.enabled = false;
    }

    private void Update()
    {
        if (Input.GetButtonDown("Fire1"))
        {
            StopCoroutine("fireShot");
            StartCoroutine("fireShot");
        }
    }
}

Notice the only difference between this script and the 2D script is that we are using SetPosition in a different context than from the 2D version. Let’s take a closer look at what we are doing with this one.

Ray ray = new Ray(transform.position, transform.right);
line.SetPosition(0, ray.origin); 
line.SetPosition(1, ray.GetPoint(-10) * .24f);

ray.origin is the point in which the ray originates.
ray.GetPoint returns a point at distance units along the way.

We set the Ray to be based off the transform position of the object we attach it to, and the direction is to the right of the transform of the attached object. We set the first element of the array to be at the point of origin for the ray. We set the second element of the ray to be a specific point multiplied by an arbitrary number for handling the curve based off the location of the model and location.

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class ThreeDRayCastingFirstPersonMode : MonoBehaviour
{
    LineRenderer line;

    private void Start()
    {
        line = gameObject.GetComponent<LineRenderer>();
        line.enabled = false;
    }

    private IEnumerator fireShot()
    {
        line.enabled = true;

        while (Input.GetButton("Fire1"))
        {
            Ray ray = new Ray(transform.position, Vector3.forward);

            line.SetPosition(0, ray.origin);
            line.SetPosition(1, ray.GetPoint(100));

            yield return null;
        }

        line.enabled = false;
    }

    private void Update()
    {
        if (Input.GetButtonDown("Fire1"))
        {
            StopCoroutine("fireShot");
            StartCoroutine("fireShot");
        }
    }
}

Next we have the fps script, which works with 1st/3rd/ and top down views.

Ray ray = new Ray(transform.position, Vector3.forward);
line.SetPosition(1, ray.GetPoint(100));

We also set the ray to be based off the position of the transform of the object it is attached to, and we also set the direction to be forward. We only need to put the point to be 100 distance units away from the origin point.

Whew, now that all of that is out of the way, we can begin building the scene.

Side Scroll Scene

Disclaimer : I have created a prefab that already has modified the model from the T-pose to the pose that we want to use for this portion of the lesson. Another lesson later down the road will talk more in depth about 3D model animations within Unity and how to build them.

To begin, create a new scene called 3DSideScroll.

3DSideScrollScene

The Main Camera should be in Perspective mode with a position of 0, 0.33, -3.38 for this example. Although you can and should do Orthographic mode.

3DSideScrollCamera

 

Now we will import the prefab that I created for this portion of the lesson into the scene.
Her position should be -3.26, -1.15, 0. She should also have a rotation of 0,75,0.

3DSideScrollPrefabImport

Add the ThreeDRayCastingSideScrollMode script to the character. I navigated into the hierarchy of the character, all the way to the right hand.

3DSideScrollScriptAttachment

This is the fun part, adding a line renderer to the character. Make sure the box for the line renderer is unchecked. Exactly under where the Script is attached is where I will attach the renderer. Make sure the width of the Line Renderer is 0.05 (although you can play around with the width until you find one you like better).

3DSideScrollLineRendererAttachment

I put the Line Renderer and the Script on the right hand of the prefab because that is the trajectory I want the line renderer to follow. You could very easily put the line renderer in a empty game object in a location of your choice and accomplish the same feat. The way I did it allows the engine to find where the starting point for the line renderer is based on the location of the character without the need for extra code.

You can run the scene and test it out for yourself now.

3D Scene

In this example, I will do both first person and 3rd person over the shoulder view.

3rd Person Over The Shoulder View

Let’s start with 3rd person over the shoulder view. The reason for this is because all we really need to do to modify this one to first person is quite literally changing the position of the character model.

Again, I have already created a prefab of the model because I changed it from the T Pose to the pose I want using the joints within Unity.

Load your 3D scene to get started.

Load3D

Add the prefab to the scene and set the model’s position to -0.22, -1.36, 0.

3DModelAdd

Again, I added the Line Renderer with a width of 0.15 and the ThreeDRayCasting script to the Right Hand Index 1 within the Model’s hierarchy.

3DAttachments

3DLineRenderer

You can run the scene and test it out for yourself now. That wasn’t too hard with 3D 3rd person over the shoulder view was it? Now, let’s go to first person view.

1st Person View

Really, the only difference between 3rd person over the shoulder view and 1st person view really is the character’s position and one very minor change to the camera itself.

To get started, navigate to the Main Camera. Change the Clipping Plane of near to 0.12.

3DCameraNear

Next, we change the model’s position. You can play with it until you find what you like, I went with a simple 0, -0.28, -3.44. It has that old school FPS feel with how it looks, granted without the UI stuff or the fact that there is no gun in this example.

FPS

You can run the scene and test it out for yourself now.

Final Thoughts

As you can see, creating Line Renderers is a very simple task that can be accomplished rather quickly and efficiently. These can take the place of particle effects and act as a laser beam, laser rifle, and many more things. They work  very well with physics and other effects.

All in all, I think it was extremely worth it to show you some very minor things that you could do with Line Renderers because you never know, you could need them at some point in the future.

I hope this tutorial helped you learn something new and I will see you all next time. May your code be clean and bug free. I’ll catch you on the next tutorial.