Home > Enterprise >  How to make the turret that shoot laser to targets to choose the closet target each time and shoot t
How to make the turret that shoot laser to targets to choose the closet target each time and shoot t

Time:04-03

For example there are 5 target and they are moving randomly around the turret. Now i'm using only one target targets[0] and the turret is rotating facing the target and shoot laser to it.

Now i want to make it with multiple targets and that the turret will choose each time the closet target and will shoot to it the laser.

I changed this part added a for loop over the targets :

for (int i = 0; i < targets.Count; i  )

but i'm still using only one target, targets[0] i'm not sure how to add the distance part and the closet target choosing.

I tried this solution but now the turret(transform) is not rotating at all towards the selected target. for some reason this two lines return null on the closestTarget :

RotateToMouseDirection(gameObject, closestTarget.position);

The script with the changes :

using System.Collections;
using System.Collections.Generic;
using System.Runtime.Serialization.Formatters;
using System;
using UnityEngine;

public class Hovl_DemoLasers : MonoBehaviour
{
    public List<Transform> targets;
    public GameObject FirePoint;
    public Camera Cam;
    public float MaxLength;
    public GameObject[] Prefabs;

    private Ray RayMouse;
    private Vector3 direction;
    private Quaternion rotation;

    [Header("GUI")]
    private float windowDpi;

    private int Prefab;
    private GameObject Instance;
    private Hovl_Laser LaserScript;
    private Hovl_Laser2 LaserScript2;
    private bool rotateMouse = true;
    private bool startLaser = true;
    private float buttonSaver = 0f;
    private Hovl_LaserDemo hovl_laserDemo;
    private float maxDistance = 0;
    private float distance;
    private Transform closestTarget;

    void Start ()
    {
        if (Screen.dpi < 1) windowDpi = 1;
        if (Screen.dpi < 200) windowDpi = 1;
        else windowDpi = Screen.dpi / 200f;
        Counter(0);
    }

    void Update()
    {
        //Enable lazer
        if (Input.GetMouseButtonDown(0))
        {
            Destroy(Instance);
            Instance = Instantiate(Prefabs[Prefab], FirePoint.transform.position, FirePoint.transform.rotation);
            Instance.transform.parent = transform;
            LaserScript = Instance.GetComponent<Hovl_Laser>();
            LaserScript2 = Instance.GetComponent<Hovl_Laser2>();

            rotateMouse = true;
        }

        if (Input.GetMouseButtonDown(1))
        {
            rotateMouse = false;
        }

            //Disable lazer prefab
            if (Input.GetMouseButtonUp(0))
        {
            /*if (LaserScript) LaserScript.DisablePrepare();
            if (LaserScript2) LaserScript2.DisablePrepare();
            Destroy(Instance,1);*/
        }

        if ((Input.GetKey(KeyCode.A) || Input.GetAxis("Horizontal") < 0) && buttonSaver >= 0.4f)// left button
        {
            buttonSaver = 0f;
            Counter(-1);
        }
        if ((Input.GetKey(KeyCode.D) || Input.GetAxis("Horizontal") > 0) && buttonSaver >= 0.4f)// right button
        {
            buttonSaver = 0f;
            Counter( 1);         
        }
        buttonSaver  = Time.deltaTime;

        if (startLaser)
        {
            rotateMouse = false;

            Destroy(Instance);

            Instance = Instantiate(Prefabs[Prefab], FirePoint.transform.position, FirePoint.transform.rotation);
            Instance.transform.parent = transform;
            LaserScript = Instance.GetComponent<Hovl_Laser>();
            LaserScript2 = Instance.GetComponent<Hovl_Laser2>();

            hovl_laserDemo = Instance.GetComponent<Hovl_LaserDemo>();

            startLaser = false;
        }

        if (targets != null)
        {
            for (int i = 0; i < targets.Count; i  )
            {
                distance = Vector3.Distance(transform.position, targets[i].position);
                if (distance < maxDistance)
                {
                    maxDistance = distance;
                    closestTarget = targets[i];
                }
            }

            if (hovl_laserDemo != null)
            {
                MaxLength = distance;
                hovl_laserDemo.MaxLength = distance;
            }

            if (Cam != null)
            {
                RaycastHit hit;

                if (Physics.Raycast(transform.position, transform.TransformDirection(Vector3.forward), out hit, MaxLength))
                {
                    RotateToMouseDirection(gameObject, closestTarget.position);
                }
                else
                {
                    RotateToMouseDirection(gameObject, closestTarget.position);
                }
            }
        }

        if (Cam != null && rotateMouse)
        {
            RaycastHit hit;
            var mousePos = Input.mousePosition;
            RayMouse = Cam.ScreenPointToRay(mousePos);
            
            if (Physics.Raycast(RayMouse.origin, RayMouse.direction, out hit, MaxLength))
            {
                RotateToMouseDirection(gameObject, hit.point);
            }
            else
            {
                var pos = RayMouse.GetPoint(MaxLength);
                RotateToMouseDirection(gameObject, pos);
            }
        }
        else
        {
            Debug.Log("No camera");
        }
    }

    void OnGUI()
    {
        GUI.Label(new Rect(10 * windowDpi, 5 * windowDpi, 400 * windowDpi, 20 * windowDpi), "Use the keyboard buttons A/<- and D/-> to change lazers!");
        GUI.Label(new Rect(10 * windowDpi, 20 * windowDpi, 400 * windowDpi, 20 * windowDpi), "Use left mouse button for shooting!");
    }

    void Counter(int count)
    {
        Prefab  = count;
        if (Prefab > Prefabs.Length - 1)
        {
            Prefab = 0;
        }
        else if (Prefab < 0)
        {
            Prefab = Prefabs.Length - 1;
        }
    }

    void RotateToMouseDirection (GameObject obj, Vector3 destination)
    {
        direction = destination - obj.transform.position;
        rotation = Quaternion.LookRotation(direction);     
        obj.transform.localRotation = Quaternion.Lerp(obj.transform.rotation, rotation, 1);
    }
}

The old original script before the changes :

using System.Collections;
using System.Collections.Generic;
using System.Runtime.Serialization.Formatters;
using System;
using UnityEngine;

public class DemoLasers : MonoBehaviour
{
    public List<Transform> targets;
    public GameObject FirePoint;
    public Camera Cam;
    public float MaxLength;
    public GameObject[] Prefabs;

    private Ray RayMouse;
    private Vector3 direction;
    private Quaternion rotation;

    [Header("GUI")]
    private float windowDpi;

    private int Prefab;
    private GameObject Instance;
    private Hovl_Laser LaserScript;
    private Hovl_Laser2 LaserScript2;

    private bool rotateMouse = true;
    private bool startLaser = true;

    private float buttonSaver = 0f;
    private Hovl_LaserDemo hovl_laserDemo;

    void Start ()
    {
        if (Screen.dpi < 1) windowDpi = 1;
        if (Screen.dpi < 200) windowDpi = 1;
        else windowDpi = Screen.dpi / 200f;
        Counter(0);
    }

    void Update()
    {
        //Enable lazer
        if (Input.GetMouseButtonDown(0))
        {
            Destroy(Instance);
            Instance = Instantiate(Prefabs[Prefab], FirePoint.transform.position, FirePoint.transform.rotation);
            Instance.transform.parent = transform;
            LaserScript = Instance.GetComponent<Hovl_Laser>();
            LaserScript2 = Instance.GetComponent<Hovl_Laser2>();

            rotateMouse = true;
        }

        if (Input.GetMouseButtonDown(1))
        {
            rotateMouse = false;
        }

        if ((Input.GetKey(KeyCode.A) || Input.GetAxis("Horizontal") < 0) && buttonSaver >= 0.4f)// left button
        {
            buttonSaver = 0f;
            Counter(-1);
        }
        if ((Input.GetKey(KeyCode.D) || Input.GetAxis("Horizontal") > 0) && buttonSaver >= 0.4f)// right button
        {
            buttonSaver = 0f;
            Counter( 1);         
        }
        buttonSaver  = Time.deltaTime;

        if (startLaser)
        {
            rotateMouse = false;

            Destroy(Instance);

            Instance = Instantiate(Prefabs[Prefab], FirePoint.transform.position, FirePoint.transform.rotation);
            Instance.transform.parent = transform;
            LaserScript = Instance.GetComponent<Hovl_Laser>();
            LaserScript2 = Instance.GetComponent<Hovl_Laser2>();

            hovl_laserDemo = Instance.GetComponent<Hovl_LaserDemo>();

            startLaser = false;
        }

        if (targets != null)
        {
            for (int i = 0; i < targets.Count; i  )
            {
                if (hovl_laserDemo != null)
                {
                    float distance = Vector3.Distance(gameObject.transform.position, targets[0].position);
                    MaxLength = distance;
                    hovl_laserDemo.MaxLength = distance;
                }

                if (Cam != null)
                {
                    RaycastHit hit;

                    if (Physics.Raycast(transform.position, transform.TransformDirection(Vector3.forward), out hit, MaxLength))
                    {
                        RotateToMouseDirection(gameObject, targets[0].position);
                    }
                    else
                    {
                        RotateToMouseDirection(gameObject, targets[0].position);
                    }
                }
            }
        }

        if (Cam != null && rotateMouse)
        {
            RaycastHit hit;
            var mousePos = Input.mousePosition;
            RayMouse = Cam.ScreenPointToRay(mousePos);
            
            if (Physics.Raycast(RayMouse.origin, RayMouse.direction, out hit, MaxLength))
            {
                RotateToMouseDirection(gameObject, hit.point);
            }
            else
            {
                var pos = RayMouse.GetPoint(MaxLength);
                RotateToMouseDirection(gameObject, pos);
            }
        }
        else
        {
            Debug.Log("No camera");
        }
    }

    void OnGUI()
    {
        GUI.Label(new Rect(10 * windowDpi, 5 * windowDpi, 400 * windowDpi, 20 * windowDpi), "Use the keyboard buttons A/<- and D/-> to change lazers!");
        GUI.Label(new Rect(10 * windowDpi, 20 * windowDpi, 400 * windowDpi, 20 * windowDpi), "Use left mouse button for shooting!");
    }

    void Counter(int count)
    {
        Prefab  = count;
        if (Prefab > Prefabs.Length - 1)
        {
            Prefab = 0;
        }
        else if (Prefab < 0)
        {
            Prefab = Prefabs.Length - 1;
        }
    }

    void RotateToMouseDirection (GameObject obj, Vector3 destination)
    {
        direction = destination - obj.transform.position;
        rotation = Quaternion.LookRotation(direction);     
        obj.transform.localRotation = Quaternion.Lerp(obj.transform.rotation, rotation, 1);
    }
}

CodePudding user response:

Have 2 Variables in a Loop. one is the index of the current closest target in you List, and the other one the distance

int closestIndex = 0;
float maxDistance = 0;
for (int i = 0; i < targets.Count; i  )
{
    //Here we calculate the distance of the current pos
    //You can take any Formula e.g. the Manhattan Formula
    float distance = Vector3.Distance(turretPositionOrSth, targets[i].position);
    //if the distance is shorter than the current max Distance
    if (distance < maxDistance)
    {
       maxDistance = distance;
       closestIndex = i;
    }
}
//Now you have your Index in the list to the closest Target,which you can use
//you can use now for example targets[closestIndex] for aiming or so

Also you don't need your already written loop anymore

CodePudding user response:

Here's essentially the same answer as tthe one @cpaech gave, but there was a couple issues.

int closestIndex = 0;
float minDistance = float.MaxValue;
for (int i = 0; i < targets.Count; i  )
{
    //Here we calculate the distance of the current pos
    //You can take any Formula e.g. the Manhattan Formula
    float distance = Vector3.Distance(turretPositionOrSth, targets[i].position);
    //if the distance is shorter than the current max Distance
    if (distance < maxDistance)
    {
       maxDistance = distance;
       closestIndex = i;
    }
}

It could also be helpful to have an attribute for the closest target and have

    if (distance < maxDistance)
    {
       maxDistance = distance;
       closestTarget = targets[i];
    }

CodePudding user response:

It looks like you have two requirements -- to find not just the closest enemy, but the closest enemy with direct line of sight to the turret?

You could sort the list of enemies by distance to the turret and iterate over it from closest to furthest until a valid target is found (requiring fewer raycasts might provide a small performance advantage if there were a massive number of enemies), or you could just try the raycast on every enemy, but here's a compromise that only tries the raycast if the enemy is closer than any previous enemy tested.

Transform target = null;
float lowestDistance = float.MaxValue;
if( cam != null && hovl_laserDemo != null && targets != null )
{
    for( int i = 0; i < targets.Count; i   )
    {
        float distance = Vector3.Distance(gameObject.transform.position, targets[i].position);
        if( distance < lowestDistance )
        {
            RaycastHit hit;
            if( Physics.Raycast(transform.position, transform.TransformDirection(Vector3.forward), out hit, distance) 
                    && hit.transform == targets[i] )
            {
                // If our raycast successfully reached the intended target without being blocked by anything else
                lowestDistance = distance;
                target = targets[i];
            }
        }
    }
}

if( target != null )
{
    MaxLength = lowestDistance;
    hovl_laserDemo.MaxLength = lowestDistance;
    RotateToMouseDirection(gameObject, target.position);
}
else
{
    // Do whatever you want to do when there is no valid target
}

Edit: Actually it looks like your raycast was succeeding if it hit anything, not just the intended target. I've tried to correct that above.

  • Related