Search Unity

Cinemachine Virtual Camera jumping around

Discussion in 'Cinemachine' started by antzaras, Sep 23, 2019.

  1. antzaras

    antzaras

    Joined:
    Aug 25, 2019
    Posts:
    10
    I'm making a 2D tactical RPG game.

    I have the mouse followed by a virtual camera so that I can pan around the map (second screen shot). When I select a unit to move (first screenshot), the virtual camera "follows" that unit, but it jumps abruptly to it. Likewise, when I cancel the unit selection so I can select a different unit or pan around the map, the virtual camera "follows" the mouse again, abruptly jumping to its position, even if the unit and mouse are right next to each other.

    When the enemy units move, the virtual camera "follows" each one in turn and abruptly jumps between them.

    The jumping makes for really jarring gameplay.

    How can I make it so that there is no abrupt jumping when following new objects if the first object and the following object in a sequence are within a certain distance of each other, or within a certain confining box? If the camera "follows" a new object within the same bounding area that the previous object is in, I think that the camera shouldn't move.

    Thank you,

    Nicholas


    upload_2019-9-23_14-27-10.png

    upload_2019-9-23_14-28-29.png
     

    Attached Files:

  2. Gregoryl

    Gregoryl

    Unity Technologies

    Joined:
    Dec 22, 2016
    Posts:
    7,719
    If you change the target of a vcam, it will jump abruptly. To get a smooth blend, have 2 vcams: one with the old target, the other with the new target. Enable the new vcam, and it will take over from the old vcam, making a nice blend for the transition.
     
  3. antzaras

    antzaras

    Joined:
    Aug 25, 2019
    Posts:
    10
    Thanks. Let me try that.

    Will that also prevent the camera from moving to the new object if they are within a certain bounding area? Or will it move over to the new object, just smoothly?
     
  4. Gregoryl

    Gregoryl

    Unity Technologies

    Joined:
    Dec 22, 2016
    Posts:
    7,719
    I'm not sure I understand the question, but I'll take a guess. If you set a dead zone in the framing transposer, the camera will not move if the target is within that dead zone. If the new target is within the dead zone of the outgoing vcam, and if the incoming vcam is activated at the position of the outgoing vcam, then it won't move. To make that happen, enable the "Inherit Position" checkbox of the vcam. Otherwise, the incoming vcam will be positioned to center the target character in the dead zone. And in that case, it will move smoothly to the new position. Does that make sense?

    upload_2019-9-23_15-3-39.png
     
  5. antzaras

    antzaras

    Joined:
    Aug 25, 2019
    Posts:
    10
    Yes, that makes sense. Let me try to figure this out, based on what you said. I'll let you know by tomorrow afternoon if I'm still having troubles.

    I appreciate your help.

    Nicholas
     
    Gregoryl likes this.
  6. antzaras

    antzaras

    Joined:
    Aug 25, 2019
    Posts:
    10
    I'm trying it out, but it stills bounces around between all the objects that are being followed. It smoothly blends between them, but it still moves around so much that it's likely to make people nauseated.

    Here is a video of what it looks like:


    Below is the code that I use to switch between following the mouse and following different units.

    I must be doing something wrong.

    public void CameraToFollowMouseTileCursor() {
    GetNewCameraPriorityForSwitching();
    newCamera.Follow = mouseTileCursor.transform;
    newCamera.GetCinemachineComponent<CinemachineFramingTransposer>().m_XDamping = 1f;
    newCamera.GetCinemachineComponent<CinemachineFramingTransposer>().m_YDamping = 1f;
    newCamera.GetCinemachineComponent<CinemachineFramingTransposer>().m_SoftZoneHeight = 0.7f;
    newCamera.GetCinemachineComponent<CinemachineFramingTransposer>().m_SoftZoneWidth = 0.7f;
    newCamera.GetCinemachineComponent<CinemachineFramingTransposer>().m_DeadZoneHeight = 0.7f;
    newCamera.GetCinemachineComponent<CinemachineFramingTransposer>().m_DeadZoneWidth = 0.7f;
    newCamera.GetCinemachineComponent<CinemachineFramingTransposer>().m_UnlimitedSoftZone = true;
    newCamera.GetCinemachineComponent<CinemachineFramingTransposer>().m_CenterOnActivate = false;
    }

    public void CameraToFollowUnit(Unit unit) {
    GetNewCameraPriorityForSwitching();
    newCamera.Follow = unit.transform.parent.transform;
    newCamera.GetCinemachineComponent<CinemachineFramingTransposer>().m_XDamping = 0f;
    newCamera.GetCinemachineComponent<CinemachineFramingTransposer>().m_YDamping = 0f;
    newCamera.GetCinemachineComponent<CinemachineFramingTransposer>().m_SoftZoneHeight = 0.7f;
    newCamera.GetCinemachineComponent<CinemachineFramingTransposer>().m_SoftZoneWidth = 0.7f;
    newCamera.GetCinemachineComponent<CinemachineFramingTransposer>().m_DeadZoneHeight = 0.7f;
    newCamera.GetCinemachineComponent<CinemachineFramingTransposer>().m_DeadZoneWidth = 0.7f;
    newCamera.GetCinemachineComponent<CinemachineFramingTransposer>().m_UnlimitedSoftZone = false;
    newCamera.GetCinemachineComponent<CinemachineFramingTransposer>().m_CenterOnActivate = false;
    }

    private void SetPriorityOfVirtualCameras(CinemachineVirtualCamera vcam) {
    if (vcam.name == "CM vcam1") {
    virtualCamera1.Priority = 100;
    virtualCamera2.Priority = 0;
    }
    else if (vcam.name == "CM vcam2") {
    virtualCamera1.Priority = 0;
    virtualCamera2.Priority = 100;
    }
    }

    private CinemachineVirtualCamera GetNewCameraPriorityForSwitching() {
    if (virtualCamera1.Priority == 100) {
    oldCamera = virtualCamera1;
    newCamera = virtualCamera2;
    newCamera.transform.position = oldCamera.transform.position;
    SetPriorityOfVirtualCameras(newCamera);
    return newCamera;
    }
    else {
    oldCamera = virtualCamera2;
    newCamera = virtualCamera1;
    newCamera.transform.position = oldCamera.transform.position;
    SetPriorityOfVirtualCameras(newCamera);
    return newCamera;
    }
    }
     
  7. Gregoryl

    Gregoryl

    Unity Technologies

    Joined:
    Dec 22, 2016
    Posts:
    7,719
    It's a little hard to understand what's going on in the video, but it mostly looks smooth. Only at 0:15 there is a pop. It could be that you're clicking many times in a row, so that a new vcam is needed but the 2 vcams are still busy completing the blend. You can't recycle a vcam before it's finished blending, or there will be a pop.

    You can try making a circular buffer, with more vcams in it.

    You don't need to do the priority thing. You can set all the vcams to the same priority, and use SetActive to activate/deactivate them. When the outgoing vcam is deactivated, it will still blend out. But don't recycle it until the blend is done.

    Also, when you post code here, it's better to use this button, to make it readable:
    upload_2019-9-24_8-26-26.png
     
  8. antzaras

    antzaras

    Joined:
    Aug 25, 2019
    Posts:
    10
    That makes sense.

    Sorry about the code.

    In the video, when I click "End" to end my turn, the enemies move in sequence, and the vcam jumps back and forth smoothly between each unit. How do I make it so that it follows the units as it does, but does not blend to the location of each one until they are outside of the dead zone? In my mind, each of those units is close enough to each other that the vcam does not need to move around at all to see where each one goes. Does that makes sense? Is there a way to keep the camera still when they are so close to each other? I haven't figured out a way to do that successfully.

    The constant moving back and forth even a little bit between units is still quite jarring after a while. It's not pleasant to look at for too long of a time.
     
  9. Gregoryl

    Gregoryl

    Unity Technologies

    Joined:
    Dec 22, 2016
    Posts:
    7,719
    You are using InheritPosition, right? Then it should be that the vcam will not move if it gets activated and the target is in its dead zone.

    If you can't get this to work, then you might want to consider an alternative (somewhat simpler) strategy: Have just one vcam, and make it follow an invisible game object. When you click on a character, make the invisible object a child of that character.
     
  10. antzaras

    antzaras

    Joined:
    Aug 25, 2019
    Posts:
    10
    I am using InheritPosition, yes.

    Wow, that's a genius idea! I'll try that and see.

    Thanks so much!
     
    Gregoryl likes this.
  11. antzaras

    antzaras

    Joined:
    Aug 25, 2019
    Posts:
    10
    Quick question. What is the best way to figure out if a blend is finished or if it's still taking place? Is there a function I can call? Or is there a different way?

    Thanks,

    Nicholas
     
  12. antzaras

    antzaras

    Joined:
    Aug 25, 2019
    Posts:
    10
    Nevermind. You answer here https://forum.unity.com/threads/how...ctive-virtual-cam-blend-has-completed.498544/ did the job for me.

    I used the following and it worked great:

    Code (CSharp):
    1. public bool FinishedBlending() {
    2.         if (!Camera.main.GetComponent<Cinemachine.CinemachineBrain>().IsBlending) {
    3.             return true;
    4.         }
    5.         return false;
    6.     }
    7.  
    8. yield return new WaitUntil(FinishedBlending);
     
    Gregoryl likes this.
  13. antzaras

    antzaras

    Joined:
    Aug 25, 2019
    Posts:
    10
    I think all along you've been right about the InheritPosition solving what I had a problem with. I just upgraded from 2.3.3 to 2.4.0 and the camera now stays still as long as the new targets that it follows are within the bounds. What you suggested and what I implemented were right, but I was just on an old version, it seems.

    Thank you for your help. My game is now very very smooth.
     
    Gregoryl likes this.