Search Unity

Best way to look up or down on a 2D platform?

Discussion in 'Cinemachine' started by Cannabik, Jun 1, 2020.

  1. Cannabik

    Cannabik

    Joined:
    Jan 11, 2018
    Posts:
    7
    I am working on a 2D platform game and I use virtual cameras that follow the player.

    The problem is that there are times when I need to make the camera look down so that the player can see what is at the end of a cliff before jumping down it.

    Until now, I've been doing it by editing the "Screen Y" values of the vcam, but it doesn't convince me because when I need the vcam to return to its normal position (putting the value of "Screen Y" back as it was) the vcam is never exactly the same height as before.

    I think there must be a better way to do it. Any suggestion?

    Thank you.
     
    AsemBahra likes this.
  2. gaborkb

    gaborkb

    Unity Technologies

    Joined:
    Nov 7, 2019
    Posts:
    856
    Could you elaborate a bit? For example, could you share screenshots of the scene where you'd like the camera to look down?

    I feel that the CameraMagnets example scene (in CM 2.6 - preview version) may be a solution for you, but it depends on what you'd like to achieve.
     
  3. Cannabik

    Cannabik

    Joined:
    Jan 11, 2018
    Posts:
    7
    Thanks for answering :)

    This is an example of what I am trying to do.
    There are times when I am interested in the camera moving up or down to show the player something.

    In this case when the player approaches the edge the camera lowers a little, so that he sees that it is safe to jump.



    What I have been doing so far has been, using a script and a couple of triggers to edit the values of "Screen Y" and then reset them.

    As it appears in the video, the problem with doing it this way is that when I reset the value of "Screen Y" the camera never looks exactly as it was, I have to jump around to make it look good.

    I am using google translator, so I apologize if it is difficult to understand me.
     
    gaborkb likes this.
  4. marc_tanenbaum

    marc_tanenbaum

    Unity Technologies

    Joined:
    Oct 22, 2014
    Posts:
    637
    I think you're looking for something like this?
    https://imgur.com/a/IByiSd8

    I achieved this with a Mixing Camera and the Camera Offset extension. I simply created a Cinemachine Mixing Camera with three identical vcams (Main, High and Low) as children. The only difference between the children was the addition of the Camera Offsets on the high and low ones.

    I then created a script to manage the mix and lerp the values.

    Code (CSharp):
    1. using System;
    2. using System.Collections;
    3. using System.Collections.Generic;
    4. using Cinemachine;
    5. using UnityEngine;
    6.  
    7. public class CameraMixInput : MonoBehaviour
    8. {
    9.     public CinemachineMixingCamera mixer;
    10.     public float totalTransitionTime = 1f;
    11.    
    12.     private int totalCameras;
    13.     private int selectedCamera = 0;
    14.     private int lastCamera = 0;
    15.     private float elapsedTime = 0f;
    16.    
    17.     // Start is called before the first frame update
    18.     void Start()
    19.     {
    20.         totalCameras = mixer.ChildCameras.Length;
    21.         elapsedTime = 0;
    22.         for (int a = 0; a < totalCameras; a++)
    23.         {
    24.             float dest = (a == selectedCamera) ? 1f : 0f;
    25.             mixer.SetWeight(a, dest);
    26.         }
    27.     }
    28.  
    29.     // Update is called once per frame
    30.     void Update()
    31.     {
    32.         if (elapsedTime < totalTransitionTime)
    33.         {
    34.             for (int a = 0; a < totalCameras; a++)
    35.             {
    36.                 float dest = (a == selectedCamera) ? 1f : 0f;
    37.                 float start = mixer.GetWeight(a);
    38.                 float toLerp = Mathf.Lerp(start, dest, elapsedTime);
    39.                 mixer.SetWeight(a, toLerp);
    40.             }
    41.  
    42.             elapsedTime += Time.deltaTime;
    43.         }
    44.  
    45.         if (Input.GetKey(KeyCode.G))
    46.         {
    47.             selectedCamera = 1;
    48.         } else if (Input.GetKey(KeyCode.B))
    49.         {
    50.             selectedCamera = 2;
    51.         }
    52.         else
    53.         {
    54.             selectedCamera = 0;
    55.         }
    56.  
    57.         if (lastCamera != selectedCamera)
    58.         {
    59.             elapsedTime = 0;
    60.             lastCamera = selectedCamera;
    61.         }
    62.     }
    63. }
    64.  
    Hope that helps!
     
    AsemBahra and gaborkb like this.
  5. gaborkb

    gaborkb

    Unity Technologies

    Joined:
    Nov 7, 2019
    Posts:
    856
    To expand on Marc's answer.
    You could use your triggers to select which camera to use from Marc's answer.

    Have a look at the MixingCamera example in our example package for more information - see the attached screenshot for more info.


    If you don't want to use the MixingCamera, then you could create 3 cameras (just like with the MixingCamera). One for the normal view, one for high view, and one for low view - see the attached screenshot.
    Then, using your triggers, you can set the active camera.
    You can set the active camera using something like this:
    Code (CSharp):
    1. CinemachineBrain brain; // <--- need to initialize/set this
    2.  
    3. // low-, normal-, and highCamera are VirtualCameras
    4. if (triggerLowCamera)
    5.      brain.ActiveVirtualCamera(lowCamera);
    6. if (triggerNormalCamera)
    7.      brain.ActiveVirtualCamera(normalCamera);
    8. if (triggerHighCamera)
    9.      brain.ActiveVirtualCamera(highCamera);
    You can customize the blending between the cameras on CinemachineBrain - see the attached screenshot.
     

    Attached Files:

  6. Cannabik

    Cannabik

    Joined:
    Jan 11, 2018
    Posts:
    7

    Thank you very much for your responses marc_tanenbaum and gaborkb!

    They have helped me a lot, seriously, thanks for your time.

    Now I am trying to make a script that helps me more or less comfortably handle all the situations in which I need to activate / deactivate or move a camera and I have a couple of doubts.

    1 - How can I edit the Offset Extension values of the current camera through a script? I have tried this but it doesn't work and I don't see very well how to do it.


    Code (CSharp):
    1.     GameObject mainCam;
    2.     CinemachineBrain brain;
    3.     CinemachineCameraOffset camOffset;
    4.  
    5.     CinemachineVirtualCamera ActiveVirtualCamera
    6.     {
    7.         get { return brain == null ? null : brain.ActiveVirtualCamera as CinemachineVirtualCamera; }
    8.     }
    9.  
    10.  
    11.     private void Awake()
    12.     {
    13.         mainCam = GameObject.Find("Main Camera");
    14.     }
    15.  
    16.  
    17.  
    18.     // Start is called before the first frame update
    19.     void Start()
    20.     {
    21.         brain = mainCam.GetComponent<CinemachineBrain>();
    22.         CinemachineVirtualCamera vcamActive = ActiveVirtualCamera;
    23.  
    24.         camOffset = vcamActive.GetCinemachineComponent(CinemachineCameraOffset)(); /// This Line not Work
    25.     }
    26.  
    27.  
    28.    

    2 - Is there a way to search for a virtual camera by name? With a GameObject I can use:

    GameObject.Find ("Player").

    But with a virtual camera?


    Thanks for all again!
     
  7. gaborkb

    gaborkb

    Unity Technologies

    Joined:
    Nov 7, 2019
    Posts:
    856
    You can't search directly for a vcam, but you can search for the GameObject that holds the vcam, and then GetComponent to get the vcam.


    Why do you want to access the offset values?
    Do you want your lowCamera to go lower in some cases?
    You can access the Screen offset through the CinemachineFramingTransposer like this:

    Code (CSharp):
    1. // CinemachineVirtualCamera vcam;
    2. vcam.GetCinemachineComponent<CinemachineFramingTransposer>().m_ScreenY = screenY;