Search Unity

[UI] Animate Fullscreen Panel from off-screen?

Discussion in 'Unity UI (uGUI) & TextMesh Pro' started by FoWare, Oct 1, 2014.

  1. FoWare

    FoWare

    Joined:
    May 24, 2013
    Posts:
    13
    I found it pretty straight forward to animate an element from off screen by simply changing specific anchor positions from 1 to 0, however this doesn't work if you want the element to stretch on more than one axis.

    What is the best technique using the editor's animator tool to animate a panel that stretches width and height from offscreen to a zero coord?

    Edit: After working with it for a few hours, it seems the new UI system goes against working with full-screen dimensions dynamically when using the built-in Animator.
     
    Last edited: Oct 2, 2014
  2. FoWare

    FoWare

    Joined:
    May 24, 2013
    Posts:
    13
    Maybe I should elaborate because my post doesn't quite get the message across. The main goal here is to be able to handle animating Full-Screen panels according to their current bounds outside of scripts. As an example, here is my panel:



    Notice it is anchored to each corner to ensure it stretches itself to the full width/height of the screen its running at. I want to have it animate from off screen as a transition effect into this full screen panel. I'm trying to do this completely outside of code so I can utilize all the neat features of Unity's built in animation edtior.



    The animation would start from the width of the canvas and animate to a zero x position. The issue here is that in the animator I can only put in static values.



    Is there a solution to this aside from animating it via scripts?
     
    Last edited: Oct 2, 2014
    JayKay135 likes this.
  3. secondbreakfast

    secondbreakfast

    Joined:
    Jan 5, 2013
    Posts:
    98
    This has always been an issue with the Animator. It doesn't really have much to do with the new UI. Providing a dynamic starting point or ending point isn't supported (that I'm aware of) so you have to work around it. Since anchored position uses the reference resolution for the canvas, if your screen size is always the same aspect, using the reference screen width will work. You do need to make sure you add ReferenceResolution to your Canvas though. If the aspect does change slightly (like with android phones or iphone 4 vs 5) you need to make sure that you move it far enough offscreen to cover both screen shapes so you don't see it at it's starting position. That the easy method that works for most cases.

    Another trick I've learned is you can make your own script that has a variable between 0 and 1 (0 meaning the start Vector and 1 meaning the destintation Vector) and use Vector2.Lerp in Update() to move it to the proper spot based on the variable. Then in the Animator, you can animate your variable in the script instead of the RectTransform directly so it will animate between your two dynamic starting and ending positions that your script knows about. That way you aren't animating in your script, you're just setting the dynamic location based on a variable you are animating in the Animator.
     
    JayKay135 likes this.
  4. _Adriaan

    _Adriaan

    Joined:
    Nov 12, 2009
    Posts:
    418
    As an example, here's the script I made to do exactly as secondbreakfast gives as his second solution. Attach it to the UI object with the RectTransform that you'd like to animate, and animate the 'animatablePosition' float on this script instead of the position directly.

    My script only works for full-screen slide-in's - not for animating not-so-full-screen things.

    Code (CSharp):
    1. using UnityEngine;
    2. using System.Collections;
    3.  
    4. public class AnimatableScreen : MonoBehaviour
    5. {
    6.     public enum Position
    7.     {
    8.         Center,
    9.         Left,
    10.         Right,
    11.         Up,
    12.         Down
    13.     }
    14.  
    15.     public float animatablePosition = 0f;
    16.     public Position positionAtZero = Position.Center;
    17.     public Position positionAtOne = Position.Down;
    18.  
    19.     private RectTransform rectTransform;
    20.  
    21.     void Start ()
    22.     {
    23.         rectTransform = GetComponent<RectTransform>();
    24.     }
    25.  
    26.     void Update ()
    27.     {
    28.         Vector2 posAt0 = GetPosition(positionAtZero);
    29.         Vector2 posAt1 = GetPosition(positionAtOne);
    30.         rectTransform.anchoredPosition =  Vector2.Lerp(posAt0, posAt1, animatablePosition);
    31.     }
    32.  
    33.     Vector2 GetPosition(Position p)
    34.     {
    35.         switch(p)
    36.         {
    37.         case Position.Center: return Vector2.zero;
    38.         case Position.Up: return new Vector2(0f, rectTransform.rect.height);
    39.         case Position.Down: return new Vector2(0f , -rectTransform.rect.height);
    40.         case Position.Left: return new Vector2(-rectTransform.rect.width, 0f);
    41.         case Position.Right: return new Vector2(rectTransform.rect.width, 0f);
    42.         default: return Vector2.zero;
    43.         }
    44.     }
    45. }
     
    JayKay135, Maweypeyyu and Sean09 like this.
  5. sethwklein

    sethwklein

    Joined:
    Oct 24, 2014
    Posts:
    8
    I'm not exactly sure what everyone above is trying to accomplish, but I found this thread when trying to figure out how to animate RectTransform anchor values (not position values) outside the range 0-1 (IOW, off screen) which you need to do when building resolution independent things without using the ReferenceResolution component. This is a problem because the inspector won't let you set anchor values outside that range. Turns out, the Animation window WILL let you set values outside that range. So you can add the curves in the Animation window and then type in maybe 2 or -1 in the field that appears when you click the diamond shaped key.
     
  6. Wai-chuen

    Wai-chuen

    Joined:
    May 28, 2015
    Posts:
    5
    Thanks so much! I was trying to get this working for ages!
     
  7. achimmihca

    achimmihca

    Joined:
    Feb 13, 2016
    Posts:
    17
    Here is my version of a fly-in script. It lets a RectTransform fly in from one side of its parent canvas (therefore the object must have a canvas as parent).
    The script works with different sizes of the RectTransform, screen resolutions and pivot settings.

    Have fun :)
    Code (CSharp):
    1. using UnityEngine;
    2. using System.Collections;
    3.  
    4. /// Lets a RectTransform fly in from one of the edges of its canvas.
    5. public class RectTransformFlyIn : MonoBehaviour {
    6.  
    7.     public enum Sides {
    8.         Left,
    9.         Right,
    10.         Top,
    11.         Bottom
    12.     }
    13.  
    14.     /// The side from where the rect transform should fly in.
    15.     public Sides side;
    16.  
    17.     /// The transition factor (from 0 to 1) between inside and outside.
    18.     [Range(0,1)]
    19.     public float transition;
    20.  
    21.     /// Inside is assumed to be the start position of the RectTransform.
    22.     private Vector2 inside;
    23.  
    24.     /// Outside is the position
    25.     /// where the rect transform is completely outside of its canvas on the given side.
    26.     private Vector2 outside;
    27.  
    28.     /// Reference to the rect transform component.
    29.     private RectTransform rectTransform;
    30.     /// Reference to the canvas component this RectTransform is placed on.
    31.     private Canvas canvas;
    32.  
    33.     void Start() {
    34.         rectTransform = GetComponent<RectTransform>();
    35.         canvas = GetComponentInParent<Canvas>();
    36.         inside = rectTransform.position;
    37.     }
    38.  
    39.     void Update() {
    40.         CalculateOutside();
    41.         rectTransform.position = Vector2.Lerp(outside, inside, transition);
    42.     }
    43.  
    44.     void CalculateOutside() {
    45.         outside = inside + GetDifferenceToOutside();
    46.     }
    47.  
    48.     Vector2 GetDifferenceToOutside() {
    49.         var pos = inside;
    50.         var size = canvas.scaleFactor * rectTransform.rect.size;
    51.         var pivot = rectTransform.pivot;
    52.         var canvasSize = canvas.pixelRect.size;
    53.  
    54.         switch(side) {
    55.         case Sides.Top:
    56.             var distanceToTop = canvasSize.y - pos.y;
    57.             return new Vector2(0f, distanceToTop + size.y*(pivot.y));
    58.         case Sides.Bottom:
    59.             var distanceToBottom = pos.y;
    60.             return new Vector2(0f, -distanceToBottom - size.y*(1-pivot.y));
    61.         case Sides.Left:
    62.             var distanceToLeft = pos.x;
    63.             return new Vector2(-distanceToLeft - size.x*(1-pivot.x), 0f);
    64.         case Sides.Right:
    65.             var distanceToRight = canvasSize.x - pos.x;
    66.             return new Vector2(distanceToRight + size.x*(pivot.x), 0f);
    67.         default:
    68.             return Vector2.zero;
    69.         }
    70.     }
    71. }
    72.  
     
    SkIllFaKeR likes this.
  8. SkIllFaKeR

    SkIllFaKeR

    Joined:
    May 13, 2016
    Posts:
    1

    Thx for the Code. It worked for me when i changed the "position" to "anchoredPosition":

    rectTransform.position = Vector2.Lerp(outside, inside, transition);
    to
    rectTransform.anchoredPosition = Vector2.Lerp(outside, inside, transition);

    and

    inside = rectTransform.position;
    to
    inside = rectTransform.anchoredPosition;
     
  9. crispybeans

    crispybeans

    Joined:
    Apr 13, 2015
    Posts:
    210
    Why don't you use localPosition ? that is the center of the widget...

    ( We animate in and out based on that . )
     
  10. yapaysinek

    yapaysinek

    Joined:
    Nov 19, 2013
    Posts:
    5
    Hey guys,

    i have tried implementing the script that @achimmihca posted and it does what I was looking for but it has a slight bug (I guess its a bug idk) that is the higher the resolution the further down (or whichever side you want the panel to fly in from) the panel positions itself. Now this bug also does this vice versa so the lower the resolution the more the panel is visible on screen because it positions itself there.
    Here are some example screenshots so you can see what I was trying to explain:
    http://imgur.com/lf5vLsC
    http://imgur.com/e0MFVOS
    http://imgur.com/AQSAund
     
  11. achimmihca

    achimmihca

    Joined:
    Feb 13, 2016
    Posts:
    17
    New version of my RectTransformFlyIn Script:
    It now uses localPosition to change the movement. This works way better. For example it now works together with "Screen Space - Camera" on a canvas.
    I also changed the "outside" calculation a bit. I think there was an issue with it.

    For me, this new version works like a charm in all situations (different sizes and positions of the RectTransform, screen resolutions, pivot settings, "Screen Space - Overlay" as well as "Screen Space- Camera" on the canvas)

    Code (CSharp):
    1. using UnityEngine;
    2. using System.Collections;
    3. using UnityEngine.UI;
    4.  
    5. /// Lets a RectTransform fly in from one of the edges of its canvas.
    6. /// This can be used with an animator.
    7. public class RectTransformFlyIn : MonoBehaviour {
    8.  
    9.     public enum Sides {
    10.         Left,
    11.         Right,
    12.         Top,
    13.         Bottom
    14.     }
    15.  
    16.     /// The side from where the rect transform should fly in.
    17.     public Sides side;
    18.  
    19.     /// The transition factor (from 0 to 1) between inside and outside.
    20.     [Range(0,1)]
    21.     public float transition;
    22.  
    23.     /// Inside is assumed to be the start position of the RectTransform.
    24.     private Vector2 inside;
    25.     private Vector2 globalPosition;
    26.  
    27.     /// Outside is the position
    28.     /// where the rect transform is completely outside of its canvas on the given side.
    29.     private Vector2 outside;
    30.  
    31.     /// Reference to the rect transform component.
    32.     private RectTransform rectTransform;
    33.     /// Reference to the canvas component this RectTransform is on.
    34.     private Canvas canvas;
    35.  
    36.     void Start() {
    37.         rectTransform = GetComponent<RectTransform>();
    38.         canvas = GetComponentInParent<Canvas>();
    39.         globalPosition = GetGlobalPosition(rectTransform);
    40.         inside = rectTransform.localPosition;
    41.         outside = inside + GetDifferenceToOutside();
    42.     }
    43.  
    44.     Vector2 GetGlobalPosition(RectTransform trans) {
    45.         // Calculate the global position of the RectTransform on the canvas
    46.         // by summing up all local positions of parents.
    47.         var pos = Vector3.zero;
    48.         foreach(var parent in trans.GetComponentsInParent<RectTransform>()) {
    49.             if(parent.GetComponent<Canvas>() == null) {
    50.                 pos += parent.localPosition;
    51.             } else {
    52.                 return pos;
    53.             }
    54.         }
    55.         return pos;
    56.     }
    57.  
    58.     void Update() {
    59.         rectTransform.localPosition = Vector2.Lerp(outside, inside, transition);
    60.     }
    61.  
    62.     Vector2 GetDifferenceToOutside() {
    63.         // Pixel size of this RectTransform in normal resolution
    64.         var size = rectTransform.rect.size;
    65.         var pivot = rectTransform.pivot;
    66.         // Pixel size of the canvas in normal resolution
    67.         var canvasSize = canvas.GetComponent<RectTransform>().rect.size;
    68.         // The summed up position has its origin in the center of the canvas.
    69.         // However, in the calculation below, the position is assumed to have its origin in the lower left corner.
    70.         // So we move the coords by canvasSize/2.
    71.         var pos = globalPosition + (canvasSize/2.0f);
    72.  
    73.         switch(side) {
    74.         case Sides.Top:
    75.             var distanceToTop = canvasSize.y - pos.y;
    76.             return new Vector2(0f, distanceToTop + size.y*(pivot.y));
    77.         case Sides.Bottom:
    78.             var distanceToBottom = pos.y;
    79.             return new Vector2(0f, -distanceToBottom - size.y*(1-pivot.y));
    80.         case Sides.Left:
    81.             var distanceToLeft = pos.x;
    82.             return new Vector2(-distanceToLeft - size.x*(1-pivot.x), 0f);
    83.         case Sides.Right:
    84.             var distanceToRight = canvasSize.x - pos.x;
    85.             return new Vector2(distanceToRight + size.x*(pivot.x), 0f);
    86.         default:
    87.             return Vector2.zero;
    88.         }
    89.     }
    90.  
    91.     public void ToggleVisible() {
    92.         var anim = GetComponent<Animator>();
    93.         anim.SetBool("Hide", !anim.GetBool("Hide"));
    94.     }
    95. }
    96.  
     
  12. c0ffeeartc

    c0ffeeartc

    Joined:
    Jul 23, 2015
    Posts:
    21
    Animate Anchor Min, Anchor Max
     
  13. Ebonicus

    Ebonicus

    Joined:
    Oct 31, 2016
    Posts:
    91

    Do this require animator, i need a solution for script only. Is that possible?
     
  14. gdwf

    gdwf

    Joined:
    Feb 25, 2015
    Posts:
    1
    I tried something with the build-in functionality in Unity and it seems to work as expected, animating ui from offscreen left, to the center regardless of the resolution.

    1. In the first frame of the animation I set the object's anchor to the left of the parent and place the object offscreen.
    2. Then in the last frame of the animation I set the object's anchor to the center of the parent and place the object exactly where I want it to end up.
    Screenshot 2019-02-16 at 11.55.42.png Screenshot 2019-02-16 at 11.55.56.png
     
    farazk86 likes this.