Search Unity

3D Platformer Jump Lag

Discussion in 'Cinemachine' started by PegasiStudios, Jun 21, 2018.

  1. PegasiStudios

    PegasiStudios

    Joined:
    Dec 22, 2014
    Posts:
    26
    I am currently learning how to use the FreeLook component of Cinemachine, and have been having issues making it to where the camera has a weight/lag when the player jumps.

    The camera's 3 rigs are set to composer, and they only seem to respond to when I set X deadzones, and Z damping, etc. But it doesn't respond at all to Y deadzones.

    Y Damping works, but it gives a weird result where the camera rotates really stiff to the player's position when jumping. I don't want it to rotate to keep looking at him, but just have a translation lag for his vertical jumping.

    Any way to do this?

    Thanks in advance!
     
  2. Gregoryl

    Gregoryl

    Unity Technologies

    Joined:
    Dec 22, 2016
    Posts:
    7,728
    Can you show me a picture of the inspector for your FreeLook?
     
  3. PegasiStudios

    PegasiStudios

    Joined:
    Dec 22, 2014
    Posts:
    26
    Totally Here's the photo of the inspector https://i.imgur.com/kAWJ2od.png

    Here's a video as well showing what I mean and the desired function I'm wanting from Cinemachine.


    The "desired" version of the camera is the old camera system, but the way it was programmed makes it impossible for geometry collision, which is a must in this game. Cinemachine provides very good collision, but the vertical following is kinda jarring after playing for a while. The old camera system feels more smooth in terms of that. It's most likely just me not knowing what I'm doing with Cinemachine.
     
  4. Gregoryl

    Gregoryl

    Unity Technologies

    Joined:
    Dec 22, 2016
    Posts:
    7,728
    Looks to me like you just need to add Y damping to the Orbital Transposer in the Body section. A little Z damping might be nice too. Start with the dame damping values in all 3 rigs, then tweak the top/bottom if you want them to be a little different.

    Cinemachine uses separate damping values for position (Body) and orientation (Aim). This is in order to give you complete control over camera behaviour.
     
  5. PegasiStudios

    PegasiStudios

    Joined:
    Dec 22, 2014
    Posts:
    26
    I gave it a try, and with not very much success.The damping here changes the camera's rotation along with a bit of movement when I'm really searching for a way to only move it upwards with no change in rotation and no changes in the X and Z axis as seen in the old video with the "desired damping"

    I'm also trying to make it only do this when the character is jumping. The camera's damping effects are effecting the view while he's running which can make it hard to see.
     
  6. Gregoryl

    Gregoryl

    Unity Technologies

    Joined:
    Dec 22, 2016
    Posts:
    7,728
    Add a vertical dead zone in the Composer to stop the rotation when he's jumping. The dead zone allows the character to move freely within that zone without the camera rotating until the character goes outside the dead zone.

    One way to do it only when he's jumping is to have 2 FreeLooks with slightly different settings that you blend between when the character changes state. You can do this with a StateDrivenCamera if the character's states are contained in an Animation state machine, or you can just do this with a script.
     
    Last edited: Jun 22, 2018
  7. PegasiStudios

    PegasiStudios

    Joined:
    Dec 22, 2014
    Posts:
    26
    Alright, I finally managed to get the jump damp to work, but it causes problems with the character's aim after the camera collides with geometry. Since the deadzone isn't effecting the rotation, it can't get the correct aim again after messing up. I assume I just need to change the deadzones through a script. What functions would I use to change it?

    I believe that at the top of the script I need to use "using Cinemachine;" or something along those lines, but what functions should I actually write to change the deadzone in his different states?
     
    Last edited: Jun 23, 2018
  8. Gregoryl

    Gregoryl

    Unity Technologies

    Joined:
    Dec 22, 2016
    Posts:
    7,728
    This should get you going:
    Code (CSharp):
    1. using UnityEngine;
    2. using Cinemachine;
    3.  
    4. public class FreeLookDeadZoneUpdater : MonoBehaviour
    5. {
    6.     [Range(0, 1)]
    7.     public float deadZoneH = 0;
    8.     [Range(0, 1)]
    9.     public float deadZoneV = 0;
    10.  
    11.     CinemachineComposer[] composers = new CinemachineComposer[3];
    12.  
    13.     void Start()
    14.     {
    15.         var freeLook = GetComponent<CinemachineFreeLook>();
    16.         if (freeLook != null)
    17.         {
    18.             for (int i = 0; i < 3; ++i)
    19.                 composers[i] = freeLook.GetRig(i).GetCinemachineComponent<CinemachineComposer>();
    20.         }
    21.     }
    22.    
    23.     void Update()
    24.     {
    25.         for (int i = 0; i < 3; ++i)
    26.         {
    27.             if (composers[i] != null)
    28.             {
    29.                 composers[i].m_DeadZoneWidth = deadZoneH;
    30.                 composers[i].m_DeadZoneHeight = deadZoneV;
    31.             }
    32.         }
    33.     }
    34. }
    35.  
     
  9. PegasiStudios

    PegasiStudios

    Joined:
    Dec 22, 2014
    Posts:
    26
    Nice. Is there a more direct template you can provide? I'm still very new to cinemachine, and could really use the extra push to understand how it works.

    The basic premise of the code is:

    idle_enterstate(){
    DeadzoneX - 0
    DeadzoneY - 0

    }

    run_enterstate(){
    DeadzoneX - 1
    DeadzoneY - 1

    }

    Really, what I'm trying to do here is make sure the camera is recentered to the player after it collides with geometry. Since the deadzone is at 1 to make the jump damping work correctly, it can't update rotation when it gets manipulated by geometry collision, and I've been trying to find a solution to the issue.

    Is there maybe another, more efficient way of doing that?
     
  10. Gregoryl

    Gregoryl

    Unity Technologies

    Joined:
    Dec 22, 2016
    Posts:
    7,728
    Do you really want the deadzone width to be 1 when he's running? Then the camera will never recenter on him. I thought you just wanted a vertical deadzone, to stop the camera rotating when he jumps. Leave the H deadzone at 0, and put the V deadzone to nonzero.

    The code sample shows you how to set the deadzones from script. Instead of doing it on OnUpdate the way the sample does, do it in your enterstate() methods.
     
  11. PegasiStudios

    PegasiStudios

    Joined:
    Dec 22, 2014
    Posts:
    26
    Ah, that was a mistake on my reply, the Horizontal deadzone is set to 0, which follows him perfectly when moving horizontal, It's just the vertical deadzone that's 1.

    So even if I attach the code to a gameobject separate from the actual camera, it'll be able to locate the current camera that is being used and make the changes?
     
  12. Gregoryl

    Gregoryl

    Unity Technologies

    Joined:
    Dec 22, 2016
    Posts:
    7,728
    No, the sample code needs to be attached to the FreeLook game object. If you want to put it somewhere else you have a few options:
    1. Add a public field for the FreeLook game object, set it up appropriately, and get your components from there. You'll have to do that once per FreeLook.
    2. Query the CinemachineBrain dynamically for the current camera and, if it's a FreeLook and if it's looking at the player, fetch its composers and set the dead zone there. If you use this method, you'll need to take care to guard against unnecessary Garbage Collection, as GetComponent() generates garbage. Usually the solution is to cache the components and re-fetch them only if the camera changes.
    3. Use the Brain's OnCameraActivated event to invoke a piece of code to register the current camera with the state handler. That code would fetch and cache the composers. The code would not be called every frame, just when the camera changes.
     
  13. PegasiStudios

    PegasiStudios

    Joined:
    Dec 22, 2014
    Posts:
    26
    I got a good setup going. I just set up a public script reference for the camera in the player's state script, and made it so that depending on his states, it runs between two functions off that script: RecenterCam, and ReleaseCam.

    It snaps into place though, which is very jarring, I guess I need to set a lerp to it.
     
  14. PegasiStudios

    PegasiStudios

    Joined:
    Dec 22, 2014
    Posts:
    26
    I tried doing this as the lerp between its two values in a 1 second period. when he enters Idle_Enterstate(), it doesn't seem to work though. What am I doing wrong here?

    It recenters when the lerp is taken off, but again, it's very "snappy" and jarring to the player's view.

    Code (CSharp):
    1. public void ReCenterCam()
    2.     {
    3.         for (int i = 0; i < 3; ++i)
    4.         {
    5.             if (composers[i] != null)
    6.             {
    7.                 composers[i].m_DeadZoneHeight = Mathf.Lerp(1, 0, 1 * Time.deltaTime);
    8.             }
    9.         }
    10.     }
    (sorry for bothering you so much btw, I hope I'm not being too difficult)
     
  15. Gregoryl

    Gregoryl

    Unity Technologies

    Joined:
    Dec 22, 2016
    Posts:
    7,728
    Time.deltaTime is the delta time between frames - it will always be in the neighbourhood of 1/60 second, so you're not really lerping. What you need to do is to cache the time of the state change, say with Time.time, and then feed to your lerp the time since then divided by the time over which you want the lerp to happen.

    But really you're doing this the hard way. Why not just make 2 FreeLook cameras, one with a dead zone and the other without, and activate the second one when he's running. Let the brain handle the transitions. That's what it's for.
     
  16. PegasiStudios

    PegasiStudios

    Joined:
    Dec 22, 2014
    Posts:
    26
    That sounds a heck of a lot easier. Won't that tank performance though? This game is going to be running on Xbox One hardware along with PC, and it has issues running more than one camera ingame

    Is this how I'm supposed to start doing the transition? What am I supposed to do next? I assume there's no scripting involved?

    code.png
     
  17. Gregoryl

    Gregoryl

    Unity Technologies

    Joined:
    Dec 22, 2016
    Posts:
    7,728
    Virtual cameras are not cameras. They are camera controllers. The paradigm is that you have a plurality (read Lots and Lots) of camera controllers, each customized for a specific game state. You enable the appropriate one based on game state, and the brain handles the transitions to keep it all smooth. The camera controllers consume little or no resources, especially when they are inactive.

    It's not at all uncommon to have different camera logic for running, walking, and idle, and subtle differences in camera work between these states can really enhance the emotional impact of the game.

    Yes you can setup a custom blend asset to customize the transitions between specific vcams, but it might be simpler to start with just setting the brain's default blend to EaseInOut with a duration of 1 second. Right now you have it set to Linear/0, which is equivalent to a cut.

    For enabling cameras based on player state, the most efficient (i.e. code-free) way to do that is to use the State-Driven-Camera, driven by the player's animation controller. Set up a default cam for it, then an override cam for when he's running.
     
  18. PegasiStudios

    PegasiStudios

    Joined:
    Dec 22, 2014
    Posts:
    26
    Ah, a bit of an issue there. my player controller uses SuperCharacterController, which does not use an animator for it's states. The states are entirely script driven, and it's animations are played through script in a standard animation component.

    I've been watching a tutorial on how to set everything up, but what method should I do if there's no animator?
     
  19. Gregoryl

    Gregoryl

    Unity Technologies

    Joined:
    Dec 22, 2016
    Posts:
    7,728
    Well in that case you can't use StateDrivenCamera for this. You'll have to manually activate the cameras on state changes. When the vcam needs to change, you can deactivate the current vcam's gameObject, then activate the new one right away. CinemachineBrain will take care of blending, even if the outgoing vcam is deactivated.
     
  20. PegasiStudios

    PegasiStudios

    Joined:
    Dec 22, 2014
    Posts:
    26
    Could I just literally use SetActive for that? or is there another function I'll need to do that will take care of the blending?
     
  21. Gregoryl

    Gregoryl

    Unity Technologies

    Joined:
    Dec 22, 2016
    Posts:
    7,728
    Yes, use SetActive.