Search Unity

Question Prevent Tracked Dolly Path Position From Going Backwards

Discussion in 'Cinemachine' started by PhantasmicDev, Nov 19, 2021.

  1. PhantasmicDev

    PhantasmicDev

    Joined:
    Jul 10, 2013
    Posts:
    35
    I'm making a game similar to doodle jump where the player ascends to progress, and sometimes levels require the player to move horizontally. Using a Tracked Dolly with Auto Dolly enabled does almost everything I need the camera to do, but when the player moves downward I don't want the camera to follow the player.

    I've tried making an extension that in the Body stage, it sets the Dolly's path position to Mathf.Max(currentPathPosition, LastPathPosition). It seems to set the path's position to the desired position in the editor field but I think the Tracked Dolly disregards it and makes it's own calculation.

    Code (CSharp):
    1. using UnityEngine;
    2. using Cinemachine;
    3.  
    4. public class CinemachinePath : CinemachineExtension
    5. {
    6.     protected override void PostPipelineStageCallback(CinemachineVirtualCameraBase vcam, CinemachineCore.Stage stage, ref CameraState state, float deltaTime)
    7.     {
    8.         if (stage == CinemachineCore.Stage.Body)
    9.         {
    10.             var extra = GetExtraState<VcamExtraState>(vcam);
    11.             if(extra.m_TrackedDolly == null)
    12.                 extra.m_TrackedDolly = (vcam as CinemachineVirtualCamera).GetCinemachineComponent<CinemachineTrackedDolly>();
    13.  
    14.             extra.m_TrackedDolly.m_PathPosition = Mathf.Max(extra.m_TrackedDolly.m_PathPosition, extra.m_LastPathPosition);
    15.             extra.m_LastPathPosition = extra.m_TrackedDolly.m_PathPosition;
    16.         }
    17.     }
    18.  
    19.     private class VcamExtraState
    20.     {
    21.         public float m_LastPathPosition;
    22.         public CinemachineTrackedDolly m_TrackedDolly;
    23.     }
    24. }

     
  2. PhantasmicDev

    PhantasmicDev

    Joined:
    Jul 10, 2013
    Posts:
    35
    Ok, from some experimenting I was able to get the behavior I want with a custom Cinemachine Extension. I disabled the AutoDolly from CinemachineTrackedDolly and do the PathPosition calculation myself. Here is the script for anyone who is curious. The little testing I've done shows promise but there could be some bugs.

    Code (CSharp):
    1. using UnityEngine;
    2. using Cinemachine;
    3.  
    4. [ExecuteAlways]
    5. public class CinemachineOneWayAutoTrackedDolly : CinemachineExtension
    6. {
    7.     public enum Direction { Forward, Backward }
    8.  
    9.     public Direction direction;
    10.     public CinemachineTrackedDolly.AutoDolly autoDolly = new CinemachineTrackedDolly.AutoDolly(true, 0f, 2, 5);
    11.  
    12.     private CinemachineTrackedDolly m_TrackedDolly;
    13.     private float m_PreviousPathPosition;
    14.  
    15.     public CinemachineTrackedDolly trackedDolly
    16.     {
    17.         get
    18.         {
    19.             if (m_TrackedDolly == null)
    20.                 m_TrackedDolly = (VirtualCamera as CinemachineVirtualCamera).GetCinemachineComponent<CinemachineTrackedDolly>();
    21.             return m_TrackedDolly;
    22.         }
    23.     }
    24.  
    25.     protected override void PostPipelineStageCallback(CinemachineVirtualCameraBase vcam, CinemachineCore.Stage stage, ref CameraState state, float deltaTime)
    26.     {
    27.         if (trackedDolly == null || enabled == false || autoDolly.m_Enabled == false)
    28.             return;
    29.  
    30.         //Init previous frame info
    31.         if (deltaTime < 0 || !VirtualCamera.PreviousStateIsValid)
    32.             m_PreviousPathPosition = m_TrackedDolly.m_PathPosition;
    33.  
    34.         if (stage == CinemachineCore.Stage.Body)
    35.         {
    36.             float prevPos = m_TrackedDolly.m_Path.ToNativePathUnits(m_PreviousPathPosition, m_TrackedDolly.m_PositionUnits);
    37.  
    38.             var newPathPosition = m_TrackedDolly.m_Path.FindClosestPoint(m_TrackedDolly.FollowTargetPosition, Mathf.FloorToInt(prevPos),
    39.                 (deltaTime < 0 || autoDolly.m_SearchRadius <= 0) ? -1 : autoDolly.m_SearchRadius, autoDolly.m_SearchResolution);
    40.  
    41.             newPathPosition = m_TrackedDolly.m_Path.FromPathNativeUnits(newPathPosition, m_TrackedDolly.m_PositionUnits);
    42.             newPathPosition += autoDolly.m_PositionOffset;
    43.  
    44.             if (Application.isPlaying)
    45.                 newPathPosition = direction switch
    46.                 {
    47.                     Direction.Forward => Mathf.Max(m_PreviousPathPosition, newPathPosition),
    48.                     Direction.Backward => Mathf.Min(m_PreviousPathPosition, newPathPosition),
    49.                     _ => newPathPosition
    50.                 };
    51.  
    52.             m_TrackedDolly.m_PathPosition = newPathPosition;
    53.  
    54.             m_PreviousPathPosition = newPathPosition;
    55.         }
    56.     }
    57. }
     
    Gregoryl likes this.