Finding the distance of player to light, while lights are in array.

I am trying to find the distance from the center point of the closest light to the player, if the light/s are enabled and while the lights are in an array and this needs to be updated constantly.

Here is the script i made so far;

public Light[] lightsP, lightsS;
	public Transform player;
	private float PdisToPlayer, SdisToPlayer, r;
	
	void Start () {
		lightsP = Light.GetLights(LightType.Point, 0);
		lightsS = Light.GetLights(LightType.Spot, 0);
	}
	
	void Update () {
		for (int i = 0; i < (lightsP.Length + lightsS.Length + 1); i++) {
			if (lightsP[i].enabled == true || lightsS[i].enabled == true) {
				Debug.Log("Lights Are On");
				PdisToPlayer = Vector3.Distance(lightsP[i].transform.position, player.position);
				SdisToPlayer = Vector3.Distance(lightsS[i].transform.position, player.position);
				if (PdisToPlayer < lightsP[i].range || SdisToPlayer < lightsP[i].range) {
					if (PdisToPlayer - lightsP[i].range < SdisToPlayer - lightsS[i].range)
						r = lightsP[i].range - PdisToPlayer;
					else if (PdisToPlayer - lightsP[i].range > SdisToPlayer - lightsS[i].range)
						r = lightsS[i].range - SdisToPlayer;
				}
			}
			else i++;
			if (i > (lightsP.Length + lightsS.Length))
				i = 0;
		}
		Debug.Log(r);
	}

See I think the loop only runs once, and i was trying to make the loop run multiple times using the code;

if (i > (lightsP.Length + lightsS.Length))
	i = 0;

I am not to sure about how i need to go about this script to make it work. I was thinking of using the “foreach” function but i wanted to kill 2 birds with one stone (using both arrays in one function), and I am not to sure if the “foreach” loop function runs forever, or just once after it has check all the items in the array.

foreach (Light l in lightsS) {
			if (l.enabled == true) {
				SdisToPlayer = Vector3.Distance(l.transform.position, player.position);
				if (SdisToPlayer < l.range)
					r = l.range - SdisToPlayer;
			}
		}

If someone could point me on the right path, or give me an insight to what I am doing wrong that would be greatly appreciated :slight_smile:

Woah, your code is hard to read :wink:

And I am not quite sure what exactly you want, only the distance to the nearest light? The center you mentioned is difficult to understand for me.

But to get the nearest light i would do something like this:

using System.Linq;
...
var nearestLight = lightsP.Concat(lightsS)
  .OrderBy(light => Vector3.Distance(light.transform.position, transform.position))
  .FirstOrDefault();
  
if (nearestLight)
{
  var distance = Vector3.Distance(nearestLight.transform.position, transform.position)
  Debug.Log(distance);
  Debug.Log(nearestLight);
}

The LINQ might be a little heavy for a per-frame operation. There’s also this more explicit approach:

public Light FindClosestLightToPoint(Light[] lights, Vector3 point, out float distance)
{
   distance = float.MaxValue;
   Light result = null;
   for(int i = 0; i < lights.Length; ++i)
   {
      float thisDist = Vector3.Distance(point, lights[i].transform.position);
      if(thisDist < distance)
      {
         distance = thisDist;
         result = lights[i];
      }
   }
   return result;
}

haha yeah i know my code is hard to read, i really need to set it out better :stuck_out_tongue:
but could you please explain the use of “Concat” in the System.Linq?

this is what I am trying to achieve:

  • I am getting all the lights in the scene and storing them in an array. But the spotlight and Point light gameobjects need to be in separate arrays.
  • Then i am checking which lights are enabled in each array.
  • With the lights that are enabled I am trying to find the closest one from the player.
  • then I need to find the difference between the player, and the center of the light, when the player is withing the range of the light.

^ above is a bit confusing… this is what I will use to find the distance to the center of the light when the player is in range of the light;

if (SdisToPlayer < lightsS[i].range)
	r = lightsS[i].range - SdisToPlayer;

So when the player gets closer to the center of the light the value of r will increase to the value of lightsS*.range*
- I need this value to use in an exponential graph.
Sorry if this is hard to understand I am trying my best :smile:

would you be able to find the closest light if 2 lights were to intersect?

Sure. The distance check only cares about the centre of the lights relative to the player; the centre of the lights relative to each other doesn’t matter.

I’ve modified my code a bit to exclude disabled lights and lights where the player is beyond the light’s range:

public Light FindClosestLightToPoint(Light[] lights, Vector3 point, out float distance)
{
   distance = float.MaxValue;
   Light result = null;
   for(int i = 0; i < lights.Length; ++i)
   {
      if(!lights[i].enabled) continue;
      float thisDist = Vector3.Distance(point, lights[i].transform.position);
      if(thisDist > lights[i].range) continue;
      if(thisDist < distance)
      {
         distance = thisDist;
         result = lights[i];
      }
   }
   return result;
}

Thank you! You have solved my problem, once I tweak the script and add bits to it I will upload the whole script.