Search Unity

  1. Megacity Metro Demo now available. Download now.
    Dismiss Notice
  2. Unity support for visionOS is now available. Learn more in our blog post.
    Dismiss Notice

Dolly to follow player on track

Discussion in 'Cinemachine' started by Enec0, Mar 13, 2019.

  1. Enec0

    Enec0

    Joined:
    Nov 6, 2017
    Posts:
    8
    Hey guys,

    first of all, I'm not trying to set up a camera movement, but a game object to follow the player. I thought that maybe the cinemachine tools could help me out with that, as the camera is also just an object following the player. This is what I'm trying to do:

    I want a game object to follow the player on a predefined track and position itself always at the closest point to the player on that track. Therefore I have set up a track using the "Cinemachine Smooth Path" script. After that I created the game object to follow the player and attached the "Cinemachine Dolly Cart" script. Unfortunately I can only set it up to follow the track with a given speed. There is no option to follow an object.

    How can I edit the script to update the position of the cart according to the player's position?
     
  2. Gregoryl

    Gregoryl

    Unity Technologies

    Joined:
    Dec 22, 2016
    Posts:
    7,658
    Set the cart's speed to zero, and add a custom script to set the cart's position directly. Use path.FindClosestPoint(playerPosition, 0, -1, 10) to find the desired position in path units, and set the cart's position to that.
     
  3. Enec0

    Enec0

    Joined:
    Nov 6, 2017
    Posts:
    8
    Thanks for your input. Unfortunately I'm not a programmer, but a sound designer and therefore only have basic c# skills. I tried to code it myself, but I simply don't know how to reference the different parameters and push them through to the dolly cart.
     
  4. Enec0

    Enec0

    Joined:
    Nov 6, 2017
    Posts:
    8
    After reading some more code and doing some research I got it to work. Thank you.
     
  5. SamRock

    SamRock

    Joined:
    Sep 5, 2017
    Posts:
    250
    @Gregoryl

    Thanks for the function FindClosestPoint. I have a similar requirement and your tip helped get the closest path. I am struggling in two areas
    1. How to I turn the object to face the player? I tried Transform.LookAt. But the rotation seems to be fixed to the Cart path.
    2. Changing Speed doesnt seem to have any affect on how fast the Object moves in the Path, When I use ClosestPoint and assign it, the object instantly moves to the Player's location. Is there a way to make the object(Enemy boss), slowly inch towards the payers and also look towards him?
     
  6. Gregoryl

    Gregoryl

    Unity Technologies

    Joined:
    Dec 22, 2016
    Posts:
    7,658
    Make your object a child of the cart and then you can rotate it.

    The Speed parameter is a way of making the cart move at a constant speed. It just increments the cart's position every frame. If you want to move the cart yourself, set the speed to zero and lerp the position gradually every frame until you reach the desired position.
     
    Last edited: Sep 1, 2021
    SamRock likes this.
  7. SamRock

    SamRock

    Joined:
    Sep 5, 2017
    Posts:
    250
    Thank you so much @Gregoryl !!

    I figured out I had to Lerp the position, and now it works great. Thanks for confirming that :)

    Will work on the rotation now.
    Here is what I have achieve so far..very early stage

     
    Gregoryl likes this.
  8. HeyBishop

    HeyBishop

    Joined:
    Jun 22, 2017
    Posts:
    238
    THIS!!!!!
    Thank you so much.
     
    SamRock and Gregoryl like this.
  9. HeyBishop

    HeyBishop

    Joined:
    Jun 22, 2017
    Posts:
    238
    I'm attempting to instantiate two CinemachineDollyCarts on the path, one 50 distance units before, and another 50 distance units after the playerPosition.

    But when when I use path.FindClosestPoint(playerPosition, 0, -1, 10), it returns a value Path Units, not Distance units. So, when I set the .m_Position of my two CinemachineDollyCarts, I can't use FindClosestPoint(playerPosition, 0, -1, 10) + 50;

    EDIT: I just figured it out:
    float currentPosInDistance = path.FromPathNativeUnits(myCart.m_Position, CinemachinePathBase.PositionUnits.Distance);
     
    Last edited: Oct 17, 2021
    Gregoryl likes this.
  10. kerptastic

    kerptastic

    Joined:
    Feb 1, 2020
    Posts:
    2
    @SamRock could you share how you setup the lerp? I am trying to do something sort of similar.

    I am putting together an endless runner, where the camera is on a track, and is targeting an object on the track as well.

    The player, moved independently of the targeting object on the track, and instead will set the targeting objects position on the track using
    FindClosestPoint()
    as well. The issue I have, is when I need to turn.

    Assume I am making a right hand turn.

    When the player is on the inside of the track, the closest point on the track to the player jumps super fast, and causes stuttering from the camera as the camera also jumps to continue following the target point. This happens due to the fact I can cut a corner with the player and completely skip a point on the pre-determined track as it rounds the corner.

    When the player is on the outside - everything works great because the player can never skip a point, and thus the calculation will work out fine.

    I assume I need to always lerp the targeting object, but cant seem to get things working right. Any help appreciated.

    Code (CSharp):
    1.         protected override void Update()
    2.         {
    3.             base.Update();
    4.  
    5.             var track = GameObject.Find("DollyTrack1");
    6.             var target = GameObject.Find("CameraDollyTarget");
    7.  
    8.             var path = track.GetComponentInChildren<CinemachineSmoothPath>();
    9.             var destination = path.FindClosestPoint(transform.position, _lastSegment, -1, 10);
    10.             _lastSegment = Mathf.FloorToInt(destination);
    11.  
    12.  
    13.             //Debug.Log(VelocityForward);
    14.  
    15.             var targetsCart = target.GetComponentInChildren<CinemachineDollyCart>();
    16.             //targetsCart.m_Speed = VelocityForward;
    17.  
    18.             var lerpValue = GetLerpValue(targetsCart.m_Position, destination, _velocityForward);
    19.  
    20.  
    21.  
    22.             targetsCart.m_Position = destination;
    23.             //targetsCart.m_Position = lerpValue;
    24.  
    25.             //Debug.Log(destination);
    26.         }
    27.  
    28.         private float GetLerpValue(float start, float destination, float velocityMagnitude)
    29.         {
    30.             var delta = destination - start;
    31.  
    32.             var foo = 0.0f;
    33.             //foo = Mathf.Lerp(start, destination, MoveSpeed);
    34.             //foo = Mathf.Lerp(start, destination, Mathf.Abs(_velocityForward));
    35.  
    36.             foo = Mathf.SmoothDamp(start, destination, ref _camTargetMaxSpeed, Time.deltaTime);
    37.  
    38.             Debug.Log($"Delta: {delta}  Destination: {destination}   Lerp: {foo}");
    39.             return foo;
    40.         }
     
  11. Gregoryl

    Gregoryl

    Unity Technologies

    Joined:
    Dec 22, 2016
    Posts:
    7,658
    Right, you shouldn't be using FindClosestPoint, because on inside corners it won't give smooth results (why? because the inside of an arc approximates a segment of a circle, and what is the closest point on the circumference to the center of a circle? All of them).

    So you should travel along the path by having a speed and by advancing the PathPosition according to that speed.
     
    kerptastic likes this.
  12. kerptastic

    kerptastic

    Joined:
    Feb 1, 2020
    Posts:
    2
    @Gregoryl Thanks for the response! I ended up changing how I wanted to approach to camera with some gameplay changes, but I believe I will hit this again in the future.

    I think I can do some slick math to update the speed of the camera based on the X,Y in a particular game piece and that may work. Thanks again for the insight!
     
    Gregoryl likes this.
  13. alexanderFabula

    alexanderFabula

    Joined:
    Sep 1, 2019
    Posts:
    22
    Hey

    I have a sidescroller. Is there a way to match the cameras x position on the path(Dolly Track) to the players x position?
     
  14. alexanderFabula

    alexanderFabula

    Joined:
    Sep 1, 2019
    Posts:
    22
    upload_2022-7-6_14-36-25.png

    I want the camera centered?
     
  15. Gregoryl

    Gregoryl

    Unity Technologies

    Joined:
    Dec 22, 2016
    Posts:
    7,658
    @alexanderFabula There is nothing out of the box to do precisely this. You would have to write a custom script to update the camera's position on the track based on the player's position.
     
  16. alexanderFabula

    alexanderFabula

    Joined:
    Sep 1, 2019
    Posts:
    22
    @Gregoryl Ok. I'm not sure how to go about searching the path for the path point with the correct x position. Do you have a suggestion? Everything I have just causes stack overflow exceptions.

    I'm calling this in update:

    Code (CSharp):
    1. private void FindPathPointMatchToTargetTransformXPosition()
    2.     {
    3.         if (MatchXPos())
    4.         {
    5.             dolly.m_PathPosition = searchPoint;
    6.  
    7.             minLimitSearchPoint = searchPoint - 10f;
    8.  
    9.             if (minLimitSearchPoint < 0)
    10.             {
    11.                 minLimitSearchPoint = 0;
    12.             }
    13.  
    14.             maxLimitSearchPoint = searchPoint + 10f;
    15.  
    16.             searchPoint = minLimitSearchPoint;
    17.         }
    18.         else
    19.         {
    20.             if (searchPoint <= maxLimitSearchPoint)
    21.             {
    22.                 searchPoint += 0.05f;
    23.             }
    24.             else
    25.             {
    26.                 searchPoint = minLimitSearchPoint;
    27.             }
    28.  
    29.             FindPathPointMatchToTargetTransformXPosition();
    30.  
    31.         }
    32.     }
    33.  
    34.     private bool MatchXPos()
    35.     {
    36.         evaluatedPoint = path.EvaluatePosition(searchPoint);
    37.  
    38.         if (evaluatedPoint.x > targetTransform.transform.position.x - 0.1f && evaluatedPoint.x < targetTransform.transform.position.x + 0.1f)
    39.         {
    40.             return true;
    41.         }
    42.         else
    43.         {
    44.             return false;
    45.         }
    46.     }
    47.  
     
  17. alexanderFabula

    alexanderFabula

    Joined:
    Sep 1, 2019
    Posts:
    22
    I think i got it working with this code instead (its called in update)


    Code (CSharp):
    1.     private void FindPathPointMatchToTargetTransformXPosition()
    2.     {
    3.         for (float i = 0f; i < path.PathLength; i += 0.05f)
    4.         {
    5.             evaluatedPoint = path.EvaluatePosition(i);
    6.  
    7.             if (evaluatedPoint.x > targetTransform.transform.position.x - 0.1f && evaluatedPoint.x < targetTransform.transform.position.x + 0.1f)
    8.             {
    9.                 dolly.m_PathPosition = i;
    10.                 return;
    11.             }
    12.         }
    13.     }
     
  18. Gregoryl

    Gregoryl

    Unity Technologies

    Joined:
    Dec 22, 2016
    Posts:
    7,658
    It depends how accurate you need it to be. Here are some ideas:
    1. Cheap and cheerful: for your calculation, approximate the path as a simple line from start point to end point. Then x(t) = x0 + t * (x1 - x0). Solve for desired x. Use normalized path units so that t range is [0...1].
    2. More complicated, and more accurate: sample the path at regular t intervals, Make a lookup table for the x values. Linearly interpolate for values between the samples.
    3. Very precise: do a binary search every time. This can be expensive, but you can get arbitrary precision. Do you really need it?
    EDIT: just saw your last post. That's a linear search, which will consume more and more CPU as the player moves along the path. Performance-wise, not ideal, but if it works for you, fine.