Home > Net >  Unity , how to switch camera to second object's position?
Unity , how to switch camera to second object's position?

Time:12-13

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;
    }
}
  • Related