Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. Dismiss Notice

Tweening a panel on/off screen with a screen space canvas.

Discussion in 'UGUI & TextMesh Pro' started by larku, Mar 6, 2015.

  1. larku

    larku

    Joined:
    Mar 14, 2013
    Posts:
    1,422
    EDIT: Solved - solution is: http://forum.unity3d.com/threads/tw...th-a-screen-space-canvas.307739/#post-2010011

    I'm looking for how to animate (I'll end up using LeanTween) a panel on to and off of the screen (enter from screen left, exit to screen right) but I don't understand how to determine the values required to move the panel to the correct positions.

    EDIT: Note: I do not want to use 'Animations' to do this - I need a scriptable solution.

    In the past I've just used quads and camera.ViewportToWorldPoint(new Vector3(0, 1, 1)) etc to get the edge positions and then used the renderer.bounds.extents.x to determine how far left/right they should be. But this technique does not map to the new UI system.

    So I have:

    Canvas
    --> Panel
    ----> All panel elements


    The canvas is screen space and I want to move the panel to the left of the screen, then tween it to screen center and when I close it I want to tween it to the right of the screen.

    LeanTween has the method: move(RectTransform rectTrans, Vector3 to, float time) which will do all the tweening for me, but it's getting the 'to' values I can't work out.

    Note, the canvas has a CanvasScaler attached so I can't assume any constant values for the panel size since they will be different based on the screen size and aspect ratio.

    Any assistance will be greatly appreciated!
     
    Last edited: Mar 10, 2015
    MilenaRocha and shekalo like this.
  2. larku

    larku

    Joined:
    Mar 14, 2013
    Posts:
    1,422
    Sorry to bump this, but I'm sure someone out there knows how to do this.
     
  3. Yukichu

    Yukichu

    Joined:
    Apr 2, 2013
    Posts:
    420
    I watched a bunch of tutorials and basically they show how to do pretty much anything that would be tweened with animators.

    I mean, the demo project does this even. Use the animator to move something smoothly on/off screen, rotate it, change color, whatever. Works very nicely I must say. You can just change the pivot or whatnot and it'll move, regardless of screen size/aspect ratio. I just googled "unity ui tutorial" and of course I got the example project that's listed as like thread #2.
     
  4. larku

    larku

    Joined:
    Mar 14, 2013
    Posts:
    1,422
    Thanks Yukichu,

    I should have made it explicit in my original post (now updated) that I don't want to use Animations for this. I have lots of general purpose dialogs of different shapes and sizes (which can change at runtime) and I don't want to create animations for all. This is a task I do often in script and I'd like to know how to do it even if I did end up using Animations.

    Thanks again for your reply!
     
    valentin56610 likes this.
  5. larku

    larku

    Joined:
    Mar 14, 2013
    Posts:
    1,422
    Bump again - really, no one knows how to do this?

    Sorry if I'm sounding spoilt, but I'd have thought this would be trivial once known.

    I totally get that using Animations is the way Unity expects this to be done, but there are cases where Animations are not the best fit. I'd really appreciate some input here from those who know :)

    /spoilt tantrum over - I'll get back in my box for now.
     
  6. Yukichu

    Yukichu

    Joined:
    Apr 2, 2013
    Posts:
    420
    No idea, sounds like something you're going to have to figure out?

    Camera.main.WorldToViewportPoint might be a starting point in order to find some position you want it to move to and translate it into ... the pivot point or something. I'd just start messing with stuff.
     
  7. larku

    larku

    Joined:
    Mar 14, 2013
    Posts:
    1,422
    Yes I could spend hours working this out, but I figured it would be better to find how to do it properly.

    Camera.main.WorldToViewportPoint does not help at all since the canvas is in screen space but seems to use a different coordinate system to the Camera screen space coordinate system. So I'm at a loss.
     
  8. Feaver1968

    Feaver1968

    Joined:
    Nov 16, 2014
    Posts:
    70
    You can do this with DOTween. Switch the inspector to debug mode when looking at a panel's RectTransform. Take note of the Anchored Position values, those are the Vector2 values you use to do movement. In your code do something like this:
    Code (CSharp):
    1. panel.DOAnchorPos (new Vector2(-90,-200), 1f);
     
  9. larku

    larku

    Joined:
    Mar 14, 2013
    Posts:
    1,422
    Thanks Feaver1968,

    I'm not very keen on using DOTween as its performance is not as good as LeanTween - I have extensive use of LeanTween in my project already and LeanTween can also tween rect transforms.

    My issue is calculating the positions at runtime based on the panel size and screen size / aspect ratio all at runtime.

    Perhaps I'm missing your point (apologies if I am) but given that the sizes can change at runtime I don't see how using DOTween will help me any more than using LeanTween will.

    So, what I'm actually needing is how to find the size and positions needed at runtime - the calls to the tweening api is trivial once I know the positions based on the info I need.
     
  10. Feaver1968

    Feaver1968

    Joined:
    Nov 16, 2014
    Posts:
    70
    Oh, I thought how to move was part of the issue so I suggested DOTween, but whatever works. I also assumed you were just trying to move a panel into the center of the screen then off to the side. Assuming the panel has a center pivot and is anchored to stretch horizontally and vertically, moving the panel to Vector2.zero would bring it on screen, then you can move the panel by Screen.Width in the negative or positive directions for left and right.
     
  11. larku

    larku

    Joined:
    Mar 14, 2013
    Posts:
    1,422
    Ah, now we're talking :) why did I not think of that!

    Yes that is ridiculously easy! Thanks - Feaver1968, I owe you one beer, add it to my tab!

    So the solution turns out to be a simple as:

    Edit: changed code to simplified and corrected version.

    Code (csharp):
    1.  
    2. Vector3 offScreenLeftPosition;
    3. Vector3 offScreenRightPosition;
    4. Vector3 centerPosition;
    5. RectTransform rt;
    6.  
    7. void Awake()
    8. {      
    9.     rt = GetComponent<RectTransform>();
    10.  
    11.     centerPosition = new Vector3(0, 0, 0);
    12.     offScreenLeftPosition = new Vector3(-Screen.width, 0, 0);
    13.     offScreenRightPosition = new Vector3(Screen.width, 0, 0);
    14.  
    15.     rt.localPosition = offScreenLeftPosition;
    16. }
    17.  
    18. public void show()
    19. {
    20.     LeanTween.cancel(gameObject);      
    21.     rt.localPosition = offScreenLeftPosition;
    22.     LeanTween.move(rt, centerPosition, 0.3f).setEase(LeanTweenType.easeInOutExpo);      
    23. }
    24.  
    25. public void hide(Action onHidden)
    26. {
    27.     LeanTween.cancel(gameObject);
    28.     LeanTween.move(rt, offScreenRightPosition, 0.3f).setEase(LeanTweenType.easeInOutExpo).setOnComplete(delegate() { onHidden(); });
    29. }
     
    Last edited: Mar 10, 2015
    thathurtabit and Feaver1968 like this.
  12. festival

    festival

    Joined:
    Feb 3, 2011
    Posts:
    80
    @larku Your code only works when scale is 1 of your gameObject
     
  13. larku

    larku

    Joined:
    Mar 14, 2013
    Posts:
    1,422
    @festival did you have a solution for scales other than 1?
     
  14. nikokoneko

    nikokoneko

    Joined:
    Feb 20, 2015
    Posts:
    35
    Old thread, but today I needed exactly the same thing, and came up with this component which works for any screen edge and any canvas scale factor (I tested it with CanvasScaler "Scale With Screen Size" option):

    Code (CSharp):
    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using UnityEngine;
    4. using UnityEngine.UI;
    5.  
    6.  
    7. [RequireComponent(typeof(RectTransform))]
    8. public class SlidingGui : MonoBehaviour {
    9.  
    10.     public enum Direction { Up, Down, Left, Right };
    11.  
    12.     // Keep this to 0 if you want this element to perfectly align to the edge of the screen (when off screen).
    13.     static float Overshoot = .1f;
    14.  
    15.     [SerializeField]
    16.     Direction slideToScreenEdge;
    17.  
    18.     [SerializeField]
    19.     float animDuration = .3f;
    20.  
    21.     [SerializeField]
    22.     bool visibleOnStart = true;
    23.  
    24.     [SerializeField]
    25.     bool delayedShow = true;
    26.  
    27.     bool isVisible;
    28.     RectTransform rt, canvasRT;
    29.     Vector2 visiblePos, offScreenPos;
    30.     Vector2 offsetDirection = Vector2.zero;
    31.  
    32.     void Start()
    33.     {
    34.         rt = GetComponent<RectTransform> ();
    35.         canvasRT = GetComponentInParent<Canvas> ().GetComponent<RectTransform> ();
    36.         visiblePos = rt.anchoredPosition;
    37.         isVisible = !visibleOnStart;
    38.         SetDirection (slideToScreenEdge);
    39.         SetVisible (visibleOnStart, false);
    40.     }
    41.  
    42.      
    43.     public bool GetVisible()
    44.     {
    45.         return isVisible;
    46.     }
    47.  
    48.     public void SetVisible(bool onoff, bool isAnimated = true)
    49.     {
    50.         if (isVisible != onoff) {
    51.             isVisible = onoff;
    52.             if (isAnimated) {
    53.                 LTDescr tween =  LeanTween.move (rt, isVisible ? visiblePos : offScreenPos, animDuration);
    54.                 tween.setEase (isVisible ? LeanTweenType.easeOutExpo : LeanTweenType.easeInExpo);
    55.                 // Delay is set so that these tabs can get "swiped".
    56.                 if (delayedShow && onoff)
    57.                     tween.setDelay (animDuration);
    58.                 return;
    59.             }
    60.             rt.anchoredPosition = isVisible ? visiblePos : offScreenPos;
    61.         }
    62.     }
    63.  
    64.     public void SetDirection(Direction direction)
    65.     {
    66.         Vector2 dirVector = Vector2.zero;
    67.         Vector2 canvasSize = canvasRT.sizeDelta;
    68.         Vector3[] corners = new Vector3 [4];
    69.  
    70.  
    71.         // Calculate four corners of our rect transform
    72.         rt.GetWorldCorners (corners);
    73.         for (int i=0; i < 4; i++) {
    74.             corners = canvasRT.InverseTransformPoint (corners );
    75.             print ("corners: " + corners );
    76.         }
    77.         float offScreenValue;
    78.         switch (direction) {
    79.         case Direction.Up:
    80.             offScreenValue = (.5f + Overshoot) * canvasSize.y - corners [0].y;
    81.             offScreenPos.Set (visiblePos.x, visiblePos.y + offScreenValue);
    82.             break;
    83.         case Direction.Down:
    84.             offScreenValue = -(.5f + Overshoot) * canvasSize.y - corners [1].y;
    85.             offScreenPos.Set (visiblePos.x, visiblePos.y + offScreenValue);
    86.             break;
    87.         case Direction.Left:
    88.             offScreenValue = -(.5f + Overshoot) * canvasSize.x - corners [2].x;
    89.             offScreenPos.Set (visiblePos.x + offScreenValue, visiblePos.y);
    90.             break;
    91.         case Direction.Right:
    92.             offScreenValue = (.5f + Overshoot) * canvasSize.x - corners [0].x;
    93.             offScreenPos.Set (visiblePos.x + offScreenValue, visiblePos.y);
    94.             break;
    95.         }
    96.     }
    97.  
    98. }
     
    Last edited: Aug 2, 2017
  15. RhinoFreak

    RhinoFreak

    Joined:
    Dec 11, 2017
    Posts:
    6

    I'm getting an error that cannot convert vector3[] to vector3 on this line:
    Code (CSharp):
    1. corners = canvasRT.InverseTransformPoint (corners );