Finding Closest by Type

Hello Everyone,

I’ve been working on this issue for a whole week now, and I can’t get a working solution. I have a turret that should shoot a laser at the closest other turret to create a laser fence. Except the turrets just refuse to find the closest turret! I’m getting frustrated.

Here’s my turret code:

using UnityEngine;
using System.Collections;

public class TurretFence : MonoBehaviour {
	
	public LineRenderer laserPrefab;
	private LineRenderer Laser;
	private float laserEnergy= 0.01f;
	private Animator thisAnimator;
	private Transform thisLaserPoint;
	private Transform nearestTurret;
	
	void Start()
	{
		thisAnimator=GetComponent<Animator>();
		thisLaserPoint= transform.FindChild("LaserPoint1");
	}
	
	// Update is called once per frame
	void Update () 
	{
		nearestTurret = Tools.FindNearest<TurretFence>(transform.position).transform;
		
		if (!thisAnimator.GetBool("NotUpright"))
		{
			Laser=Instantiate(laserPrefab) as LineRenderer;
			if (Laser!=null)
			{
				Laser.SetPosition(0,thisLaserPoint.position);
				Laser.SetPosition(1,nearestTurret.position);
				Destroy(Laser, laserEnergy);
			}
		}
		
	}
	
}

and my finding code:

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

public class Tools {

	public static T FindNearest<T>(Transform reference) where T : MonoBehaviour
	{
		return FindNearest<T>(reference.position);
	}
 
	public static T FindNearest<T>(Vector3 reference) where T : MonoBehaviour
	{
		List<T> list = (GameObject.FindObjectsOfType(typeof(T)) as T[]).ToList();
		list.Sort(
		(x, y) =>
		(x.transform.position - reference).sqrMagnitude
		.CompareTo((y.transform.position - reference).sqrMagnitude));
		return list.FirstOrDefault();
	}
}

All the turrets do is fire at themselves or fire into nothingness.
19631-turretissue.png

That red line at the turret is the laser.
I appreciate any suggestions.

-Hyperion

I would use OrderBy instead of Sort - it’s just easier.

I created a simple test environment for ya:

19633-window.png

The cubes have a Cube script attached to them, and the sphere in the center has a Center script.

public class Center : MonoBehaviour
{
	void OnGUI()
	{
		if (GUILayout.Button("Find closest")) {
			var allCubes = GameObject.FindObjectsOfType<Cube>();
			var relativePoint = transform.position;
			Cube closest = allCubes.OrderBy(cube => (cube.transform.position - relativePoint).sqrMagnitude).FirstOrDefault();
			if (closest != null)
 			    closest.renderer.material.color = Color.green;
		}
	}
}

When I click the button, I find the closest cube relative to me (the sphere).

OrderBy orders in an ascending order by default. If you want descending, use OrderByDescending.

More on sorting.

If you want to get the grips with Linq, I highly recommend this series from Jamie King.

One more thing, I don’t really recommend using FindObjectsOfType - unless in non-performance sensitive areas. Instead of that, I would create a static list of cubes, when a cube comes to life, I add it to it.

public class Cube : MonoBehaviour
{
   private static List<Cube> allCubes = new List<Cube>();
   public static List<Cube> AllCubes { get { return allCubes } };

   void OnEnable()
   {
      allCubes.Add(this);
   }
   void OnDisable()
   {
      allCubes.Remove(this);
   }   
}

And then in my Center code:

if (GUILayout.Button("Find closest")) {
	var allCubes = Cube.AllCubes;
	var relativePoint = transform.position;
	...
}

You already got it mostly. You’re missing the fact that the turret itself is the nearest turret to that position… So you will need to ski it. Simply take the second closest instead of the closest, since the closest will always be the turret itself.

Don’t forget to check that there are at least 2 entries in the list before using the second one.