Efficient way to find nearest object with component

Hello,

So as the title suggests, I’m looking for a way to find the nearest object with a certain component that causes the least lag. Using OverlapSphere causes too much lag if there’s too many game objects nearby, and this is due to the fact that I use tiny cubes with colliders as blood. (9 in total).

Is there perhaps a better way to fix this lag problem I’m having?

Code for Detection:

public void senseEnemiesNearby(float radius){
		if (target == null) {
			Collider[] hitColliders = Physics.OverlapSphere(transform.position, radius);
			senseEnemies = true;
			savedLoc = loc;
			Cube cub = GetClosestEnemy (hitColliders, radius);
			if (cub != null) {
				if (cub.team != team) {
					setTarget (cub);
				}
			}
		}
	}

	private Cube GetClosestEnemy(Collider[] enemies, float radius)
	{
		Cube cub = null;
		float minDist = radius;
		Vector3 currentPos = transform.position;
		foreach (Collider c in enemies)
		{
			if (c.gameObject != gameObject) {
				if (c.gameObject.GetComponent<Cube> () != null && c.gameObject.GetComponent<Cube> ().team != team) {
					Transform t = c.transform;
					float dist = Vector3.Distance(t.position, currentPos);
					if (dist < minDist)
					{
						cub = c.gameObject.GetComponent<Cube> ();
						minDist = dist;
					}
				}
			}
		}
		return cub;
	}

Thanks
HighlordWeaponry

Here are three general performance boosters to your algorithm:

  • First of all you may want to use layers. OverlapSphere has an additional layermask parameter.
  • Next you shouldn’t use GetComponent more than once per object. Currently you use GetComponent up to 3 times per object. Just create a local variable inside the foreach loop and get the component once.
  • Finally when sorting objects based on the distance it’s faster to compare sqrMagnitude. It of course doesn’t tell your the actual distance but the greater than / lower than relation will stay the same.

So do something like this:

public LayerMask layers;

public void senseEnemiesNearby(float radius)
{
    if (target == null)
    {
        Collider[] hitColliders = Physics.OverlapSphere(transform.position, radius, layers);
        senseEnemies = true;
        savedLoc = loc;
        Cube cub = GetClosestEnemy (hitColliders, radius);
        if (cub != null)
        {
            setTarget (cub);
        }
    }
}

private Cube GetClosestEnemy(Collider[] enemies, float radius)
{
    Cube cub = null;
    float minDist = radius;
    Vector3 currentPos = transform.position;
    foreach (Collider c in enemies)
    {
        if (c.gameObject == gameObject)
            continue;
        Cube cube = c.GetComponent<Cube>();
        if (cube != null && cube.team != team)
        {
            Transform t = c.transform.position - currentPos;
            float dist = t.x*t.x + t.y*t.y + t.z*t.z;  // Same as "= t.sqrMagnitude;" but faster
            if (dist < minDist)
            {
                cub = cube;
                minDist = dist;
            }
        }
    }
    return cub;
}

Note i removed your second team check in your “senseEnemiesNearby” method. Since your “GetClosestEnemy” method can only return an object that has to be on a different team the null check is enough.

How many objects are there in total and how many are usually in range of the OverlapSphere? I doubt that this actually caused much slowdown. Have you used the Profiler to narrow down your bottleneck?