ESOUI

ESOUI (https://www.esoui.com/forums/index.php)
-   Tutorials & Other Helpful Info (https://www.esoui.com/forums/forumdisplay.php?f=172)
-   -   Animating controls (https://www.esoui.com/forums/showthread.php?t=1191)

acies 04/26/14 02:11 PM

Animating controls
 
In this tutorial I will show a few examples on how to use the ANIMATION_MANAGER, covering most of the basics.

I'll start off with some of the jargon you'll encounter:
A timeline is a set of animations (not required to be sequential).
Easing is a function applied to the offset for each step in an animation to achieve non-linear transitions. Easing functions are usually made using quadratic or cubic Bezier curves.
Translation refers to the Euclidean transformation of an object's coordinates to a new set of coordinates.

The main types of animations are:
  • ANIMATION_ALPHA
  • ANIMATION_COLOR
  • ANIMATION_SCALE
  • ANIMATION_SCROLL
  • ANIMATION_SIZE
  • ANIMATION_TRANSLATE

The self-explanatory types of directions are:
  • ANIMATION_PLAYBACK_ONE_SHOT (default)
  • ANIMATION_PLAYBACK_LOOP
  • ANIMATION_PLAYBACK_PING_PONG

Let's start with a simple example using CreateSimpleAnimation (single animation):
Lua Code:
  1. function simpleAnimation(control, duration)
  2.     local animation, timeline = CreateSimpleAnimation(ANIMATION_ALPHA, control)
  3.  
  4.     -- start at current alpha
  5.     animation:SetAlphaValues(control:GetAlpha(), 1)
  6.     animation:SetDuration(duration or 1000)
  7.  
  8.     timeline:SetPlaybackType(ANIMATION_PLAYBACK_ONE_SHOT)
  9.     timeline:PlayFromStart()
  10. end

As you will notice, not defining an easing function will simply use linear.
Here's a list of easing functions provided by the API:
  • ZO_BezierInEase
  • ZO_BounceEase
  • ZO_EaseInCubic
  • ZO_EaseInOutCubic
  • ZO_EaseInOutQuadratic
  • ZO_EaseInOutQuartic
  • ZO_EaseInOutQuintic
  • ZO_EaseInQuadratic
  • ZO_EaseInQuartic
  • ZO_EaseInQuintic
  • ZO_EaseOutCubic
  • ZO_EaseOutQuadratic
  • ZO_EaseOutQuartic
  • ZO_EaseOutQuintic
  • ZO_LinearEase (default)
To understand these easing functions, check out http://easings.net/
If you wish to make a custom easing, you can do so with ZO_GenerateCubicBezierEase.
Instead of a tedious trial and error process inputting numbers blindly, I can recommend using this interactive tool to come up with the four numbers required: http://cubic-bezier.com/

Each type of animation has its own method for setting the from and to values.
Here's a more elaborate timeline animation with custom easing:
Lua Code:
  1. -- custom bouncing ("out back") easing
  2. local myEasing = ZO_GenerateCubicBezierEase(.05, 1.85, .75, .75)
  3.  
  4. function timelineAnimation(control)
  5.     local isValidAnchor, point, relativeTo, relativePoint, offsetX, offsetY = control:GetAnchor()
  6.  
  7.     local timeline = ANIMATION_MANAGER:CreateTimeline()
  8.  
  9.     -- scale to 100% using our custom easing
  10.     local popup = timeline:InsertAnimation(ANIMATION_SCALE, control)
  11.     popup:SetScaleValues(0, 1)
  12.     popup:SetDuration(500)
  13.     popup:SetEasingFunction(myEasing)
  14.  
  15.     -- animate opacity from 0% to 100%
  16.     local fadeIn = timeline:InsertAnimation(ANIMATION_ALPHA, control)
  17.     fadeIn:SetAlphaValues(0, 1)
  18.     fadeIn:SetDuration(150)
  19.     fadeIn:SetEasingFunction(ZO_EaseOutQuadratic)
  20.  
  21.     -- begin fading out after 2 seconds
  22.     local fadeOut = timeline:InsertAnimation(ANIMATION_ALPHA, control, 2000)
  23.     fadeOut:SetAlphaValues(1, 0)
  24.     fadeOut:SetDuration(500)
  25.  
  26.     -- begin to slide up after 2 seconds
  27.     local translate = timeline:InsertAnimation(ANIMATION_TRANSLATE, control, 2000)
  28.     translate:SetTranslateOffsets(offsetX, offsetY, offsetX, offsetY - 150)
  29.     translate:SetDuration(500)
  30.     translate:SetEasingFunction(ZO_EaseInQuadratic)
  31.  
  32.  
  33.     -- demonstration of timed callbacks
  34.     timeline:InsertCallback(function()
  35.         d('halfway')
  36.     end, timeline:GetDuration() / 2)
  37.  
  38.     -- reset the control's position once the animation stops
  39.     timeline:SetHandler('OnStop', function()
  40.         d('stopped')
  41.         control:ClearAnchors()
  42.         control:SetAnchor(point, relativeTo, relativePoint, offsetX, offsetY)
  43.     end)
  44.  
  45.     timeline:PlayFromStart()
  46. end

I hope this tutorial clarified some of the less obvious things (cf. http://wiki.esoui.com/Controls)

Sideshow 04/28/14 01:08 PM

Great information! Thanks a lot.
I was wondering, if there is any possibility to alter a timeline animation.
More in detail, I would like to do a translate animation, but the starting coords are not known before the animation is applied to a control. So I would like the animation to take the coords of the control as starting point.

GetBackYouPansy 04/28/14 02:26 PM

Quote:

Originally Posted by Sideshow (Post 6263)
Great information! Thanks a lot.
I was wondering, if there is any possibility to alter a timeline animation.
More in detail, I would like to do a translate animation, but the starting coords are not known before the animation is applied to a control. So I would like the animation to take the coords of the control as starting point.

You can get each animation out of the timeline and adjust them. There are shortcuts for the first and last animation, see [1], and you can just do all the animations in the timeline like this.

Lua Code:
  1. -- Increase the duration of every animation in the timeline by 250ms
  2. for i = 1, timeline:GetNumAnimations() do
  3.   local anim = timeline:GetAnimation(i)
  4.   anim:SetDuration(anim:GetDuration() + 250)
  5.  -- what you can do ofc depends on the type of animation!
  6. end

One way you might use this is by creating the timeline from virtual (the virtual being defined in UI XML), with some placeholder durations/positions/whatever, then fill in the actual values, and then run it. For an example in the wild, which the simpler example above is based on, see [2] (Lua) and [3] (XML). The base duration from the XML is bumped up by 250ms for every instance of the timeline, several of which are started in parallel.

[1] http://wiki.esoui.com/Controls#AnimationTimeline
[2] https://github.com/PansyLabs/Timers/...s.lua#L207-211
[3] https://github.com/PansyLabs/Timers/...ers.xml#L70-79

Sideshow 04/29/14 07:30 AM

Thanks for the help!

Roupine 05/14/14 07:00 PM

If the starting coordinates aren't known, I've found that simply using SetTranslateDeltas() works great.

ie.
Lua Code:
  1. anim:SetTranslateOffsets(originX, originY, originX-100, originY)
  2. -- Is almost the same as:
  3. anim:SetTranslateDeltas(-100, 0)
SetTranslateDeltas() appears to automatically grab the animated control's current X and Y and sets that as the origin point. What this means is, if the control has moved since the deltas were set it will "snap" back. I get around this by calling SetTranslateDeltas() again just before calling the animation if I'm expecting such a case.

For example, if you want the visual effect of controls "bumping up" each other as new ones come in at the bottom of a stack, you can create an animation to translate the control up, then add an "OnStop" handler that will call SetTranslateDeltas() again so the next time that "bump" is called, it will move up from its new position.

Another thing to keep in mind is that the beziers only affect the animation speed, not the translate coordinates. In order to get a curved animation, you can't simply add two translate animations to the same object -- the latter translation overwrites the former. You have to anchor one object to another object and animate each differently.

For example:
Lua Code:
  1. WINDOW_MANAGER:CreateTopLevelWindow("SomeTLW")
  2. ctExample = WINDOW_MANAGER:CreateControl("AnimEx", SomeTLW, CT_CONTROL)
  3. ctExample.lbl = WINDOW_MANAGER:CreateControl("AnimExLabel", ctExample, CT_LABEL)
  4. -- Set Anchors
  5. ctExample:SetAnchor(CENTER,GuiRoot,CENTER)
  6. ctExample.lbl:SetAnchor(CENTER,ctExample,CENTER)
  7. -- Add content to the controls so they're visible
  8. ctExample.lbl:SetFont("ZoFontWinH2")
  9. ctExample.lbl:SetText("Hello, World!")
  10. SomeTLW:SetHidden(false)
  11.  
  12. ctExample.anim = ANIMATION_MANAGER:CreateTimeline()
  13. -- Add the horizontal slide to the Control:
  14. ctExample.anim.slideX = ctExample.anim:InsertAnimation( ANIMATION_TRANSLATE, ctExample, 0 )
  15. ctExample.anim.slideX:SetDuration(500)
  16. ctExample.anim.slideX:SetEasingFunction(ZO_LinearEase)
  17. ctExample.anim.slideX:SetTranslateDeltas(200,0) -- slide right
  18. -- Add the vertical slide to the Label:
  19. ctExample.anim.slideY = ctExample.anim:InsertAnimation( ANIMATION_TRANSLATE, ctExample.lbl, 0 )
  20. ctExample.anim.slideY:SetDuration(500)
  21. ctExample.anim.slideY:SetEasingFunction(ZO_EaseInCubic)
  22. ctExample.anim.slideY:SetTranslateDeltas(0,-200) -- slide up
  23.  
  24. -- Since the animations are part of the same animation timeline,
  25. -- even though they affect two different objects, you only need to call:
  26. ctExample.anim:PlayFromStart()
I only attached the timeline to the control object (ie. ctExample.anim) because this code is adapted from an ObjectPool factory function. It could be any sort of variable that's convenient.


There might be a better method out there, but... I haven't found it.

Specko 06/09/14 02:22 PM

First off, thanks for posting this. I am having an issue trying to implement the simple animation. I am using the event for mount status change and the function triggers fine. My issue is with the starting alpha of my label control.

For the below I'm getting attempt to index a nil value for

Code:

--label
    c.label = wm:CreateControl(nil, c, CT_LABEL)
    c.label:SetDimensions(300,200)
        c.label:SetAnchor(CENTER, c, CENTER, 75, -150)
        c.label:SetFont(path .. "|" .. size .. "|" ..  style)
        c.label:SetColor( 128,128,0,.5 )
        c.label:SetHorizontalAlignment( CENTER )
        c.label:SetVerticalAlignment( CENTER )
        c.label:SetText ( "Changed mount status!" )

        return c

  end

  function KillingBlow:simpleAnimation(controlToAnim, duration)
    local animation, timeline = CreateSimpleAnimation(ANIMATION_ALPHA, controlToAnim)

    print("setAlphaValues")
    animation:SetAlphaValues(controlToAnim:GetAlpha(), 1) --Nil value line controlToAnim:GetAlpha()
        print("SetDuration")
    animation:SetDuration(duration or 1000)

    timeline:SetPlaybackType(ANIMATION_PLAYBACK_ONE_SHOT)
    timeline:PlayFromStart()
  end


Froali 06/09/14 03:07 PM

Hard to tell without more information about controlToAnim. Start debugging with testing if controlToAnim is nil.
If it's not validate it actually has a method named "GetAlpha" (use zgoo AddOn!). Maybe it's not a control or a descendant of control.

Specko 06/09/14 03:46 PM

Quote:

Originally Posted by Froali (Post 9240)
Hard to tell without more information about controlToAnim. Start debugging with testing if controlToAnim is nil.
If it's not validate it actually has a method named "GetAlpha" (use zgoo AddOn!). Maybe it's not a control or a descendant of control.

Thanks I'll use zgoo to test the control.

Specko 06/09/14 10:30 PM

It was a scope resolution issue on my part. Doh.

@AlphaLemming 02/23/16 01:59 AM

Please make this sticky. I my case it helps much! Thanks.

Baertram 02/24/16 04:44 AM

You could add it to the WIKI so everyone benefits (even outside the forum).


All times are GMT -6. The time now is 11:57 PM.

vBulletin © 2024, Jelsoft Enterprises Ltd
© 2014 - 2022 MMOUI