I'm struggling with weird problem in Unity 3D. My idea is to find the closest and the second closest object from the array to the player. Then I want the camera to move to the closest object's position and look at player but if the distance between player and the nearest object is too small I want the camera to move to the second object's position. I did some coding and I don't know why the third section of else if doesn't even execute. When player comes too close the camera does not switch but keeps the closest object position.
public class Robot2 : MonoBehaviour
{
public GameObject cameraHolder;
public Transform[] objects;
private Transform nearestObj;
private Transform secondObj;
void Update()
{
float lowestDist = 9999f;
float secondLowestDist = lowestDist 1f;
float tooCloseDist = 3f;
nearestObj = null;
secondObj = null;
foreach(Transform obj in objects)
{
float dist = Vector3.Distance(transform.position, obj.position);
if(dist < lowestDist)
{
lowestDist = dist;
nearestObj = obj;
cameraHolder.transform.position = nearestObj.transform.position;
}
else if(dist < secondLowestDist)
{
secondLowestDist = dist;
secondObj = obj;
}
else if(dist < tooCloseDist)
{
Debug.Log("Too close , switching");
cameraHolder.transform.position = secondObj.transform.position;
}
}
Debug.DrawLine(transform.position, nearestObj.transform.position, Color.red);
}
}
CodePudding user response:
What if the second object is also too close?
For a more general solution before using and accessing the first and second closest object I would first go through the entire array and see if there really is no one closer.
You could use Linq OrderBy
and as criteria use (transform.position - obj.position).sqrMagnitude
which is cheaper than using the magnitude
(which is what Vector3.Distance
is using)
using System.Linq;
...
[SerializeField] float tooCloseDist = 3f;
// Just a little helper struct, could also use a tuple
// but this is probably easier to understand
private struct DistanceInfo
{
public readonly Transform transform;
public readonly float sqrDistance;
public DistanceInfo(Transform self, Transform target)
{
transform = target;
sqrDistance = (self.position - target.position).sqrMagnitude;
}
}
private void Update ()
{
// It's cheaper to use squared magnitude of vectors if it is only about comparing them
var tooCloseDistanceSqr = tooCloseDistance * tooCloseDistance;
// In one go for each object get according distance info instance
// and order them starting with the smallest distance
var orderedByDistance = objects.Select(obj => new DistanceInfo (transform, obj)).OrderBy(info => info.sqrDistance);
// Go through the sorted instances of DistanceInfo
foreach(var info in orderedByDistance)
{
// since we ordered by distance "info" is always the next closest object
// if it is too close -> skip to the next closest one
if(info.sqrDistance < tooCloseDistanceSqr) continue;
// we found the next closest object that is not too close
cameraHolder.transform.position = info.transform.position;
Debug.DrawLine(transform.position, info.transform.position, Color.red);
// break the loop as we don't want to do anything further
break;
}
}