Search Unity

Tooltip updating it's position lags when Cinemachine moves (video)

Discussion in 'Cinemachine' started by nicmarxp, May 16, 2019.

  1. nicmarxp

    nicmarxp

    Joined:
    Dec 3, 2017
    Posts:
    406
    I'm using a simple Cinemachine Virtual Camera which follows the player with a bit of delay to make it smooth. When holding the mouse over an item, a tooltip shows, and I set it's position like the code below.

    When I move, the tooltip lags after, and is not fixed to the item. I have tried to set this in Update, FixedUpdate and LateUpdate.

    The wantedPosition is where it should be if it's in the middle of the screen, then it sets it so it doesn't go outside the screen. camera1 is Camera.main, which is the main camera where Cinemachine Brain is.

    The tooltip is a UI element in a Screen Space - Overlay Canvas. Should I maybe have the tooltip as a real gameobject instead?

    Any clues on what I'm doing wrong?




    Code (CSharp):
    1.        
    2.  
    3. // Run in Update, FixedUpdate or LateUpdate (same results)
    4. void SetTooltipPositionItem() {
    5.     var wantedPosition = BlueGoo.Utils.Utils.WorldToUISpace(camera1, canvas, currentPosition) + (Vector3) tooltipOffset;
    6.     gameObject.transform.position = BlueGoo.Utils.Utils.CheckIfRectIsInsideParent(wantedPosition, rect, parentRect);
    7. }
    8.  
    9. public static Vector3 WorldToUISpace(Camera camera, Canvas parentCanvas, Vector3 worldPos) {
    10.    //Convert the world for screen point so that it can be used with ScreenPointToLocalPointInRectangle function
    11.    Vector3 screenPos = camera.WorldToScreenPoint(worldPos);
    12.    Vector2 movePos;
    13.  
    14.    //Convert the screenpoint to ui rectangle local point
    15.    RectTransformUtility.ScreenPointToLocalPointInRectangle(parentCanvas.transform as RectTransform, screenPos, parentCanvas.worldCamera, out movePos);
    16.  
    17.    //Convert the local point to world point
    18.    return parentCanvas.transform.TransformPoint(movePos);
    19. }
    20.  
    21. public static Vector3 CheckIfRectIsInsideParent(Vector3 wantedPosition, RectTransform rect, RectTransform parent, float padding = 20) {
    22.    // Set position first, so it can check if it's inside
    23.    rect.position = wantedPosition;
    24.  
    25.    Vector3[] corners = new Vector3[4];
    26.    Vector3[] parentCorners = new Vector3[4];
    27.    Vector2 diff = Vector2.zero;
    28.  
    29.    // Get corners
    30.    rect.GetWorldCorners(corners);
    31.    parent.GetWorldCorners(parentCorners);
    32.  
    33.    // Corner 0 = bottom left, 2 = top right
    34.    // If tooltip is outside, set diff
    35.    if (corners[0].x < parentCorners[0].x + padding) {
    36.       diff.x = parentCorners[0].x - corners[0].x + padding; // Utanför till vänster
    37.    } else if (corners[2].x > parentCorners[2].x - padding) {
    38.       diff.x = parentCorners[2].x - corners[2].x - padding; // Utanför till höger
    39.    }
    40.  
    41.    if (corners[1].y > parentCorners[2].y - padding) {
    42.       diff.y = parentCorners[2].y - corners[1].y - padding; // Utanför uppåt
    43.    } else if (corners[0].y < parentCorners[0].y + padding) {
    44.       diff.y = parentCorners[0].y - corners[0].y + padding; // Utanför neråt
    45.    }
    46.  
    47.    return wantedPosition + (Vector3) diff;
    48. }
    49.  
     
  2. Gregoryl

    Gregoryl

    Unity Technologies

    Joined:
    Dec 22, 2016
    Posts:
    7,711
    This is likely a script execution order problem. Camera is positioned in CinemachineBrain.LateUpdate(), and the brain's script execution order is set to be later than the default, so it will run after all your scripts. That means you are using a stale camera position to calculate the screen position.

    Here are two possible solutions:
    1. set your script to run after CinemachineBrain in the script execution order, or
    2. hook into the brain's Camera Updated event. That's issued whenever the brain moves the camera. That way you don't have to worry about execution order
     
    Last edited: May 16, 2019
    ToastedBeans likes this.
  3. nicmarxp

    nicmarxp

    Joined:
    Dec 3, 2017
    Posts:
    406
    Thanks a lot for the quick reply, I'll try that!
     
  4. Big_Friggin_Al

    Big_Friggin_Al

    Joined:
    Jan 9, 2014
    Posts:
    37
    Gregoryl, I have the same issue, how would I go about hooking into the Camera Updated event? I can't seem to find any info about it anywhere.
     
  5. Gregoryl

    Gregoryl

    Unity Technologies

    Joined:
    Dec 22, 2016
    Posts:
    7,711
    Use
    CinemachineCore.CameraUpdatedEvent.AddListener(MyHandler);
     
    MH2B, Rezonanz, AlexStrook and 2 others like this.
  6. MrDizzle26

    MrDizzle26

    Joined:
    Feb 8, 2015
    Posts:
    36
    Thanks for pointing this out 'CinemachineCore.CameraUpdatedEvent.AddListener(MyHandler);'

    I was looking in the Brain class as it was described as belonging to it!
     
  7. AlexStrook

    AlexStrook

    Joined:
    Oct 19, 2013
    Posts:
    31

    this is an old post, but it saved my life...after an unity update my execution order were messed up and i could not find why my world space UI was flickering like crazy, thanks a lot!!
     
    Gregoryl likes this.
  8. ing_unity

    ing_unity

    Joined:
    Nov 30, 2020
    Posts:
    12
    Thanks a lot
     
  9. MH2B

    MH2B

    Joined:
    Nov 24, 2018
    Posts:
    5
    Thanks a lot this solved my problem. None of other answers which told to use interpolation nor make camera follow another GameObject instead of directly following the character worked previously. I Even was changing the UI Position in LateUpdate and it was not working until I used this approach.
     
    Gregoryl likes this.