简体   繁体   中英

Switching between two or more cameras unity3D

I'm making a game in which the player controls two different characters (each one has its own empty object with a camera as child), and switchs one or another by pressing the control key. The thing is, I'm trying to make a little transition between both characters cameras by using another camera, so it doesn't just teleports between one and another but I can't seem to do it. I tried with lerp but I don't know if I got it right, so I read and tried Vector3.MoveTowards but still couldn't do it. This is my code so far (the while is because a last-moment-braindead I had):

public class CameraController : MonoBehaviour  
{   
    public Camera cam1;   
    public Camera cam2;  
 public Camera movingCamera;  

 public bool isCurrentPlayer;  
 public Transform target1;  
 public Transform target2;  
 public float speed = 0.2f;  
 void FixedUpdate()  
 {  
     float step = speed * Time.deltaTime;  
     if (Input.GetButtonDown("Control"))  
     {  
         if (isCurrentPlayer)  
         {  
             movingCamera.enabled = true;  
             cam2.enabled = false;  
             while (transform.position != target1.position)  
             {  
                 transform.position = Vector3.MoveTowards(transform.position,  target1.position, step);  
             }  
             if (transform.position == target1.transform.position)  
             {  
                 movingCamera.enabled = false;  
                 cam1.enabled = true;  
             }  
             isCurrentPlayer = false;  
         }  
         else if (!isCurrentPlayer)  
         {  
             movingCamera.enabled = true;  
             cam1.enabled = false;  
             while (transform.position != target2.position)  
             {  
                 transform.position = Vector3.MoveTowards(transform.position,  target2.position, step);  
             }  
             if (transform.position == target2.transform.position)  
             {  
                 movingCamera.enabled = false;  
                 cam2.enabled = true;  
             }  
             isCurrentPlayer = true;  
         }  
     }  
 } 

transform.position points to the position of CameraController game object. If you want to move movingCamera you probably want to use movingCamera.transform.position. Also keep in mind that in your script the MoveTowards() would only fire when you are pressing your "Control" button.

As memBrain said it would be the best practice to use only one camera for this - visually it would look the same.

The script should look something like this:

// Assuming target1 is player 1 and target2 is player 2

private float snapThreshold = 0.1f;

private Vector3 movingCameraDestination = Vector3.zero; 

void FixedUpdate()
{
    if(Input.GetButtonDown("Control"))
    {
        if(isCurrentPlayer)
        {
            //Set position of transition camera to player 1 and set it's destination to player's 2 position
            movingCamera.transform.position = player1.position;
            movingCameraDestination = player2.position;

            //Disable player 1 camera and enable transition camera
            cam1.enabled = false;
            movingCamera.enabled = true;
        }
        else
        {
            //Set position of transition camera to player 21 and set it's destination to player's 1 position
            movingCamera.transform.position = player2.position;
            movingCameraDestination = player1.position;

            //Disable player 1 camera and enable transition camera
            cam2.enabled = false;
                movingCamera.enabled = true;
        }
    }

    //If transition camera is enabled and its destination is not Vector3.zero - move it
    if(movingCameraDestination != Vector3.zero && movingCamera.enabled)
    {
        movingCamera.transform.position = Vector3.Lerp(movingCamera.transform.position, movingCameraDestination, speed * Time.deltaTime);

        //If the distance between transition camera and it's destination is smaller or equal to threshold - snap it to destination position
        if(Vector3.Distance(movingCamera.transform.position, movingCameraDestination) <= snapThreshold)
        {
            movingCamera.transform.position = movingCameraDestination;
        }

        //If transition camera reached it's destination set it's destination to Vector3.zero and disable it
        if(movingCamera.transform.position == movingCameraDestination)
        {
            movingCameraDestination = Vector3.zero;
            movingCamera.enabled = false;
        }
    }
}

I'm curious about two things. Why did you use FixedUpdate to manage your updates? This isn't physics code. Is there a particular reason you are using multiple cameras? If I may, I propose the following changes.

You can simply make use of the main camera instead of multiple cameras. Additionally, you can increase the number of player objects you can toggle through by using an array of player GameObjects, and by changing the input parameters to left control and right control, you can toggle between next player and previous player to navigate bi-directionally through the array of players.

Here's my example code that implements these changes (tested and works, though improvements can be made.)

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

// Attached to Main Camera
public class CameraController : MonoBehaviour {
    // set manually in inspector
    public GameObject[] players;
    public float movementSpeed = 1.0f;
    public float rotationSpeed = 1.0f;

    private int currentPlayer;
    private float startTime;
    private float distanceToPlayer;
    private Vector3 startPosition;
    private Quaternion startOrientation;

    // Use this for initialization
    void Start () {
        currentPlayer = 0;
        ResetCamera();
    }

    // Update is called once per frame
    void Update () {
        float distanceCovered;
        float rotationCovered;
        float fractionTraveled;

        // switch to previous
        if (Input.GetButtonDown("left ctrl")) {
            if (currentPlayer == 0) currentPlayer = players.Length - 1;
            else currentPlayer--;
            ResetCamera();
        }

        // switch to nextPlayer
        if (Input.GetButtonDown("right ctrl")) {
            if (currentPlayer == players.Length - 1) currentPlayer = 0;
                else currentPlayer++;
                ResetCamera();
            }

            // Keep moving camera
            if (transform.position != players[currentPlayer].transform.position)
            {
                distanceCovered = (Time.time - startTime) * movementSpeed;
                fractionTraveled = distanceCovered / distanceToPlayer;
                rotationCovered = (Time.time - startTime) * rotationSpeed;
                // Lerp to player position
                transform.position = Vector3.Lerp(
                    startPosition, 
                    players[currentPlayer].transform.position, 
                    fractionTraveled
                );
                // match player orientation
                transform.rotation = Quaternion.RotateTowards(
                    transform.rotation, 
                    players[currentPlayer].transform.rotation, 
                    rotationCovered
                );
            // Stop moving camera
            } else {
                // Match orientation
                if (transform.rotation != players[currentPlayer].transform.rotation) 
                    transform.rotation = players[currentPlayer].transform.rotation;

                // Set parent transform to current player
                transform.parent = players[currentPlayer].transform;
            }
    }

    void ResetCamera() {
        transform.parent = null;
        startTime = Time.time;
        startPosition = transform.position;
        startOrientation = transform.rotation;
        distanceToPlayer = Vector3.Distance(
            transform.position, 
            players[currentPlayer].transform.position
        );
    }
}

Obviously the values would need to be tweaked, and the movement algorithm is pretty basic. Crude but function. You can also add player movement code into the camera, just make sure it points to players[currentPlayer] and it will work for each of your player objects without having to use additional scripts unless there is a reason to do so.

Feel free to use this code. Like I said, it works. However, should you choose to do so, it can easily be modified to function like your original code simply by removing the array and reinstating the individual GameObjects.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM