Unity3D multiple UI Buttons change main camera position NOT SCENE

Viewed 1267

Using multiple UI buttons to try and change main cameras positions to different views. I don't want to change scene. I am looking at one object lets say a car, and I want to see the head lights, I want to click a button to move main camera to see head lights and have a pop up window showing text "HeadLights". Then I want to move to BrakeLights, I click the break lights button and the main camera then moves to the break light area and has another pop up text saying "break lights". There is multiple buttons for each car part, I am stuck and new to unity and looking for help.

3 Answers

If I'm understanding you correctly, you have multiple buttons, and clicking each will move your main camera to a spot corresponding to that button. What you should do is:

  1. Create a script that stores the text you want to show, and the position and rotation of the camera. Attach it to each of the buttons' gameobjects.

  2. Then, create a function in that script to set the text and camera position / rotation. The script should look something like this:


using UnityEngine;
using UnityEngine.UI;

public class CameraSwitch : MonoBehaviour
{
    public Text UILabel;
    public string text;
    public Vector3 cameraPos;
    public Vector3 cameraRot;

    public void SwitchToHere()
    {
        Camera.main.transform.position = cameraPos;
        Camera.main.transform.rotation = Quaternion.Euler(cameraRot);
        UILabel.text = text;
    }
}

  1. Go back to Unity. In each of the button's OnClick events, subscribe (add) that function you just created. (Be sure to add the function from the script attached to that button)

  2. Change the text to whatever you want, and set the cameraPos and cameraRot to where you want the camera to switch to when pressing this button.


Here is a video of me doing the whole thing: https://youtu.be/L621IcEBAtU

This will definitely work, but the transition between each spots is instant. If you want a smooth transition, you can either use the cinemachine pack or change the script.

If you would like, for each position you could create two Vector3's, one for the position you would like the camera to be in, and another you would like the camera to be facing.

public Vector3 cameraPos;
public Vector3 cameraLootAkPos;

public void ChangeCameraTransform()
{
    Camera.main.transform.position = cameraPos;
    Camera.main.transform.LookAt(cameraLootAkPos);
}

I did my own version of this if you would like to use it. The above version is an instant transition, the one included below transitions more smoothly at runtime. you can consider taking it further with things like Mathf.Lerp

public class ChangeCamera : MonoBehaviour
{
    // You can populate each list with the appropriate positions. Making sure they are in order from 0 upward
    public List<Vector3> CameraPositions;
    public List<Vector3> CameraLookAtPositions;

    public Vector3 LookAtTarget;

    // to see which camera configuration we should use.
    public int CamConfig;

    float moveSpeed = .5f;
    float rotSpeed = .5f;

    public Transform MainCamera;

    void Update()
    {
        if (MainCamera.position != CameraPositions[CamConfig])
        {
            MainCamera.position = Vector3.MoveTowards(MainCamera.position, CameraPositions[CamConfig], moveSpeed);
        }
        LookAtTarget = Vector3.MoveTowards(LookAtTarget, CameraLookAtPositions[CamConfig], rotSpeed);
        MainCamera.LookAt(LookAtTarget);
    }

    public void ChangeCameraConfig(int ConfigNo)
    {
        CamConfig = ConfigNo;
    }
}

As an exercise I've tried to write a simple C# script to do something like you've described above. I hope this helps as a starting point for your own:

using UnityEngine;

public class CamSwitcher : MonoBehaviour {

    public CamSpotInfo[] spots;
    [Range(0.1f, 3.0f)] public float anim_speed = 0.3f;
    protected int idx = 0;
    protected float t_accum = 0.0f;

    void Update() {
        Transform cam = Camera.main.transform;
        cam.position = Vector3.Lerp(cam.position, spots[idx].transform.position, t_accum);
        cam.LookAt(spots[idx].target); /* TODO: interpolate target positions */
        t_accum += Time.deltaTime * anim_speed;
    }

    void OnGUI() {
        if (GUI.Button(new Rect(10, 70, 200, 30), "next spot: " + spots[idx].name)) {
            if (++idx >= spots.Length)
                idx = 0;
            t_accum = 0.0f;
        }
    }
}

[System.Serializable]
public class CamSpotInfo {
    public Transform transform;
    public Transform target;
    public string name;
}

In order to assign new "camera spots" to the array, set the "Size" manually in the Unity inspector first and then drag new GameObjects/transforms from the scene Hierarchy window to the individual elements of the array in the Inspector (these can for example just be empty game objects indicating the camera position for each "camera spot"). Then assign camera targets to each element in the array, you want the main camera to look at at each "camera spot" (e.g. wheels). And finally, enter a name for each element that will be displayed on the GUI button.

In this example, there will be only one GUI button displayed in Play Mode, which is used to switch to the next "spot" in the array. But you can easily modify the script to make the camera switch to specific elements directly...

CameraSwitcher script component in Unity's Inspector window

(Not sure if this is really a good question for this site, since it is quite open-ended, since there are so many different ways to come up with possible solutions for such a feature (many different areas involved, like camera motion controller, path interpolation, GUI etc.)).


EDIT: Multiple GUI Buttons

Here is a modified version of the script above, that uses multiple GUI buttons, one for each camera spot. Each one can be enabled/disabled in the inspector via the "Show GUI" checkbox:

using UnityEngine;

public class CamSwitcher : MonoBehaviour {

    public CamSpotInfo[] spots;
    [Range(0.1f, 3.0f)] public float animSpeed = 0.3f;
    protected uint idx = 0;
    protected float t = 0.0f;

    void Update() {
        Transform cam = Camera.main.transform;
        Vector3 dir_target = spots[idx].target.position - cam.position;
        Quaternion roti = Quaternion.LookRotation(dir_target);
        cam.position = Vector3.Lerp(cam.position, spots[idx].transform.position, t);
        cam.rotation = Quaternion.Slerp(cam.rotation, roti, t);
        t += Time.deltaTime * animSpeed;
    }
    void OnGUI() {
        Rect rect = new Rect(10, 70, 200, 30);
        for (uint i=0; i<spots.Length; ++i) {
            if (spots[i].showGUI) {
                if (GUI.Button(rect, "switch to " + spots[i].name)) {
                    idx = i;
                    t = 0.0f;
                }
                rect.y += rect.height + 5;
            }
        }
    }
}

[System.Serializable]
public class CamSpotInfo {
    public Transform transform;
    public Transform target;
    public string name;
    public bool showGUI = true;
}
Related