Environmental Elements

Laser Tower that automatically attacks targets within range using (draw line in game)

You don’t have access to this lesson
Please register or sign in to access the course content.

This guide will demonstrate how to make a tower that will shoot a simulated laser at a specified time to the first object that moves within it’s range.

You need to be able to:

  • move a character around on the scene
  • Have a Player Properties script attached to the player with a public health variable (This script is shown below).

A good lesson to complete before this is Environmental damage to the player over time when in an area.

You can download a completed demo here.

Here is the example PlayerProperties script. Attach this to your player prefab.

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
/* 1. 
Added the scene management for reloading the scene on death
This is used just for testing.
*/
using UnityEngine.SceneManagement;

public class PlayerProperties : MonoBehaviour
{
    // 2. Player Health
    public float health = 100;
    // 3. Max player health (not used)
    public float maxHealth = 100;
    // 4. player armour (not used)
    public float armour = 50;
    // 5. Max player armour (not used)
    public float maxArmour = 100;
    // 6. The player name (not used)
    public string name = "Pete the Player";

    // Update is called once per frame
    void Update()
    {
        // 7. Check if out of health
        if(health <= 0) {
            // 8. Reload the current scene.
            SceneManager.LoadScene(SceneManager.GetActiveScene().name);
        }
    }
}

Also make sure that your Player prefab has the Player tag applied to it.

Next we will create the tower object that will shoot the lasers (draw a line with the Line Renderer component).

Create a new prefab.

Create your tower and add any materials or textures you like.

Add an empty game object above the tower or at the point you want the laser line to be drawn from.

Name it LaserOrigin and give it an identifier to make it easier to see.

On the root object of the prefab add a Sphere Collider.

Set this collider to be a trigger.

Move the centre of this collider to the origin point of the laser line (laserOrigin)

Also adjust the radius of the sphere to be the size that you want.

This will be our detection area. If an object labelled player comes in this area the laser will shoot at it and keep doing so every n seconds until the object dies or leaves the area.

We need to add an empty gameobject as a child of the laser origin point. This will be the object used to draw our laser line.

Call this LaserLine.

Add the line renderer component to this object.

We can leave it’s properties as is.

There are multiple ways to achieve this. This guide only shows one possible solution. There are much more elegant ways of achieving this.

Now we will create a script to manage firing the laser tower.

Create a script called FireLaserTower and attach it to the laser tower prefab.

Add the laser tower to the scene.

The code is shown below. The points listed are in order which you should add them to the script. Don’t just copy and paste.

  1. First we set up a variable to store the origin transform point of the laser called laserOrigin
    We also create a GameObject variable laserLine for storing the object that we will draw the laser on.
    These will be linked up later on by dragging the relevant game objects into the component view.
    There is also a list of type GameObject that will store the potential targets for the tower.
  2. This is where we set up variables to store the damage the tower will inflict and the rate of fire / time between the tower firing.
  3. Next we setup the function that will be run in the coroutine to manage the tower’s rate of fire. This is called FireTowerWeapon.
    This function takes one parameter which is the delay between shots.
  4. As we want this to run indefinitely we put the code into an infinite loop while(true)
  5. As we don’t want to fire immediately we use the yield keyword and WaitForSeconds function to yield control of the program and tell the IEnumerator and coroutine to wait for the set number of seconds before moving onto the next line of code which will call the DrawLaserLine function.
    This is covered in point 12.
  6. We want to check the number of potential targets for the laser tower to aim at. We do this by checking if the Sphere collider we added to the laser Tower root game object has had something enter it’s collider trigger area.
  7. Add an if statement to check if the collider object that was triggered on entering the sphere collider has the tag Player (or tag of your choice)
    We have a Debug.Log line to show that this collider and tag has triggered correctly.
  8. Here we add each item with the tag of player to the list of potential targets. Our code will only target the first item in the list.
    We need to get the gameObject that is attached to the collider.
    potentialTargets.Add(col.gameObject);
  9. Now we need to remove the player from the list of targets if they leave the laser’s range. We use the OnTriggerExit api function for this.
  10. We check if the collider is attached to an object with the tag Player. This is the same as for the OnTriggerEnter collider check.
  11. We need to get the gameObject that is attached to the collider and remove it from the list using the .Remove() function of the list.
  12. Now we need to sort out firing the laser, inflicting damage and drawing the laser on the screen.
    We create a function DrawLaserLine()
  13. Next we create a LineRenderer variable that gets the LineRenderer component that is attached to the laserLine variable.
    The LineRenderer takes pairs of Vector3 positions for the start and end point of a line and draws a line between them.
  14. We initially set the line target for the laser to be the same as the origin point for the laser.
    Vector3 target = laserOrigin.position;
  15. Next we check that there are objects that are in the range of the laser (if there aren’t it will fire a laser from the start point to the target which is the same as the origin).
    We are checking that the list of potential targets has more than 0 items in the list. i.e. it’s not empty.
  16. If there is an item we set the target variable to be the position of the first potential targets transform. To get the first item in a list we use [0] to get the first index.
    target = potentialTargets[0].transform.position;
  17. Now that we know there is an object we want to inflict damage on the player / target. We need to get the PlayerProperties script component from the target object. We use the GetComponent<PlayerProperties>() function. If the script with the player health has a different name put this instead of PlayerProperties.
    PlayerProperties pp = potentialTargets[0].GetComponent<PlayerProperties>();
    Next we update the health value of the PlayerProperties by removing the laserDamage from it.
    pp.health = pp.health – laserDamage;
  18. Not we set the origin point for the LineRenderer to the origin point of the laser.
    This first position if index 0.
    lr.SetPosition(0, laserOrigin.position);
  19. Then we set the target position for the line. This is index 1.
    lr.SetPosition(1, target);
  20. Return to the FireTowerWeapon function.
    Add in a call to the DrawLaserLine() function after the yield line of code, this will run the DrawLaserLine() function after the delay has expired.
  21. Finally we need to set this up so that it will start when the tower is created.
    Assign the IEnumterator to the fireLaser variable by calling the FireTowerWeapon function passing the delay for the weapon.
    fireLaser = FireTowerWeapon(laserDelay);
  22. Finally start the Coroutine by passing the StartCoroutine function the fireLaser variable.
    StartCoroutine(fireLaser);
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class FireLaserTower : MonoBehaviour
{
    /* 1. 
    Origin point for the laser to raycast from.
    Also origin draw point for drawing a line
    */
    [SerializeField]
    private Transform laserOrigin;

    public GameObject laserLine;

    [SerializeField]
    private List<GameObject> potentialTargets;

    IEnumerator fireLaser;

    // 2. variables for the damage of the laser and the delay between shots.
    public float laserDamage = 5.0f, laserDelay = 2.0f;

    // Start is called before the first frame update
    void Start()
    {
        // 21. Set the laser to fire (draw line) with the delay set
        fireLaser = FireTowerWeapon(laserDelay);
        // 22. Start the coroutine to repeatedly fire
        StartCoroutine(fireLaser);
    }

    // 6. Check if a object tagged Player has entered the area.
    void OnTriggerEnter(Collider col) {
        // 7. Check if object is tagged as a player
        if(col.CompareTag("Player")) {
            Debug.Log("Player is in range");
            // 8. Add the object to a list of targets
            potentialTargets.Add(col.gameObject);
        }
    }

    // 9. Check if the object has left the lasers range
    void OnTriggerExit(Collider col) {
        // 10. Check if it's one we care about tagged Player
        if(col.CompareTag("Player")) {
            Debug.Log("Player left range");
            /* 11. 
            Remove the object from the list as it is not out of the 
            range of the laser.
            */
            potentialTargets.Remove(col.gameObject);
        }
    }

    // 3. Function to use with coroutine to fire weapon with delay
    IEnumerator FireTowerWeapon(float delay) {
        // 4. Fire indefinitely, could add initial random delay here.
        while (true)
        {
            // 5. Wait delay seconds before firing
            yield return new WaitForSeconds(delay);   
            // 20. Draw the line
            DrawLaserLine();
        }
    }
    
    // 12. Draw the line and inflict damage to the object
    void DrawLaserLine() {
        // 13. Create a line renderer object (must be attached to the gameobject)
        LineRenderer lr = laserLine.GetComponent<LineRenderer>();
        /* 14.
        Set the target to be the origin initially.
        For testing put in a random vector3 set of coordinates.
        */
        Vector3 target = laserOrigin.position;

        // 15. Check if there are valid targets (tagged Player)
        if(potentialTargets.Count > 0) {
            /* 16.
            Get the first target in the list's position
            Set this position as the target for the laser
            We use the item at position [0] as this is the 
            first item that entered the range of the laser.
            */
            target = potentialTargets[0].transform.position;

            /* 17. 
            Inflict damage on player
            This assumes the object has a PlayerProperties script
            component attached with a public health variable.
            */
            PlayerProperties pp = potentialTargets[0].GetComponent<PlayerProperties>();
            pp.health = pp.health - laserDamage;
        }

        // 18. Set the start position of the line to render
        lr.SetPosition(0, laserOrigin.position);
        // 19. Set the end position of the line to render
        lr.SetPosition(1, target);
    }
}

Save your script.

Now we need to attach the laser origin transform and the game object that we will use to draw the line to the script component on the laser tower.

You can also set the damage amount and time delay for the laser tower here.

Test your program you should now have a line drawn every two seconds so long as the player is with in range of the laser.

You might want to add code to play a sound or display a warning if the player is in range to let them know they are being targeted.