This is a module for giu providing an animation system.
@gucio321 Head Developer | @sirthunderek Logo Designer | @Garnn Editor |
For complete code, please check out examples
Please make sure that you're using the same version of giu as this project (technically, you need to use giu version that uses the same imgui-go version as yours)
At the moment, there are three implementations of animations:
- Transition - a smooth transition between two windows/sets of windows e.t.c. NOTE applying this animation to single widgets is not implemented yet and may not work as expected.
- Color Flow - you can apply this animation to any widget You can configure this animation to make your button hover smoothly or change it into a rainbow!
- Movement - moves DrawCursor, emulating moving an object (aka
giu.Widget
).
Lets shortly discuss particular types of animations:
Lets look at the API:
func Transition(renderers ...func(starter func(mode PlayMode))) *TransitionAnimation {...}
renderers
are just key frames of trasition.
In each stage appropiate renderer is called.
The argument to the renderers is a pointer to Animator.Start (see later)
so that you can call it to play the animation.
func ColorFlow(
widget giu.Widget,
applying []giu.StyleColorID,
colors ...func() color.RGBA,
) *ColorFlowAnimation {...}
- The first argument is a function producing a widget that the animation should apply to
- next is the list of style-color identifiers. Color changes apply to all of them.
- and the last list of arguments are key frames of color flow.
There is also a variant of the above method called ColorFlowStyle
, which does not need
colors list. These colors are obtained
by function like this:
func() color.RGBA {
return imgui.CurrentStyle().GetStyleColor(styleID)
}
func Move(w func(starter StarterFunc) giu.Widget, steps ...*MoveStep) *MoveAnimation {...}
This will move w
around the steps.
Lets take a closer look on steps now:
- You create a step with
Step
orStepVec
methods. - You have two options of specifying position:
- you can make it relative to the previous step. This way the system will take position and add it to the position of the previous step (and do it until it reaches first step or any step with absolute position)
- After calling
Absolute()
method of the MoveStep, its position becomes absolute so that it does not rely on any previous step.
- An additional feature of Steps is a Bezier Curve implementation.
In order to enable it, simply call
Bezier
method and specify as many points as you wish.
One more important thing to mention is the first step.
By default, position of the first step you specify will be treated
absolute, even though it wasn't set to be. To change this
there are two additional methods of MoveAnimation
.
- the first one is called
StartPos
and takes one argument of the following type:func(startPos imgui.Vec2) *MoveStep
. It is expected to return non-nil MoveStep.startPos
argument is the position of drawing cursor at the moment of first call ofAnimator
. - another method is tu simply call
DefaultStartPos
method. It takes no arguments and acts like most users would like to useStartPos
- it returnsStep(startPos)
.
These are some additional ways of controlling the flow of animation:
const (
EasingAlgNone EasingAlgorithmType = iota
EasingAlgInSine
EasingAlgOutSine
EasingAlgInOutSine
EasingAlgInQuad
EasingAlgOutQuad
EasingAlgInOutQuad
EasingAlgInCubic
EasingAlgOutCubic
EasingAlgInOutCubic
EasingAlgInQuart
EasingAlgOutQuart
EasingAlgInOutQuart
EasingAlgInQuint
EasingAlgOutQuint
EasingAlgInOutQuint
EasingAlgInExpo
EasingAlgOutExpo
EasingAlgInOutExpo
EasingAlgInCirc
EasingAlgOutCirc
EasingAlgInOutCirc
EasingAlgInBack
EasingAlgOutBack
EasingAlgInOutBack
EasingAlgInElastic
EasingAlgOutElastic
EasingAlgInOutElastic
EasingAlgInBounce
EasingAlgOutBounce
EasingAlgInOutBounce
EasingAlgMax
)
for further reference, see https://easings.net
This interface holds a reference to the part of AnimatorWidget
responsible
for starting animations. At the moment, there are three functions
Start(PlayMode)
go to the next KeyFrame (forwards or backwards)StartCycle(numberOfCycles int, mode PlayMode)
- play animationnumberOfCycles
times starting and ending on this frame.StartKF(base, destination KeyFrame, numberOfCycles int, mode PlayMode)
go frombase
todestination
inmode
direction (frame by frame) makingnumberOfCycles
cycles
After constructing an animation, you need to create a special type of giu widget
called AnimatorWidget
.
You may want to store it in a temporary variable, but, as you'll see later, animator's api is designed so that you don't need to do so every time.
As an argument to Animator(...)
constuctor, you pass previously created animation.
Animator has some useful methods:
Duration
allows you to specify animation's duration (default is 0.25 s)FPS
sets Frames per second value for animation playback (default is 60) NOTE it is not real application's FPS! It just describes how often animation's status is updated.Start
- this method you can use to invoke animation play.IsRunning
returns true, if animation is being played right now.
AnimatorWidget
has a special ID method that allows you to specify
your own giu-ID. This ID is used to store an internal animator's state
inside of giu context.
Using this method is extremely important if you want to avoid confusing panics
when using TransitionAnimation along with sub-animators inside that animation.
It may happen, that one animator receives the same ID as the previous one.
This may lead to unexpected behaviour or even panic! Its good practice to set
unique ID everywhere!
Animator provides a simple way of automated starting of animations.
You can do this by using Trigger
method. This method takes three arguments:
TriggerType
(TriggerNever, TriggerOnChange, TriggerOnTrue) tells Animator when to start the animation.- play mode - tells how to start it
- and the last argument is a trigger function
func() bool
(TIP you can use any ofimgui
functions likeimgui.IsItemHovered
)
Key frames are specific frames of an animation, other frames get interpolated according to them. All other states between them are calculated on the go. Key frames system in this module is not very advanced, but it should suit needs of most users. For more information about implementation of this system in particular animation types, see above.
You can use this API to create your own animation.
To do soo, lets take a look at the Animation
interface.
type Animation interface {
Init()
Reset()
KeyFramesCount() int
BuildNormal(currentKeyFrame KeyFrame, starter func())
BuildAnimation(animationPercentage, animationPurePercentage float32, startKeyFrame, destinationKeyFrame KeyFrame, starter func())
}
This is a copy from animation.go, but I've removed comments for clarity
init is called once, during first call of Animator.Build you can put some initialization here.
Reset is called along with (*Animator).Start
Returns a number of key frames the animation implements. This number determines behaviour of Animator while calling Start*
is called when !(*Animator).IsRunning()
It takes a pointer to (*Animator).Start
as an argument
so you can easily start animation from there.
is called instead of BuildNormal when playing an animation.
Along with pointer to (*Animator).Start
, it also receives
current animation progress in percents (0 >= currentPercentage <= 1)
You can do some calculations there.
If you implement something interesting, find any bugs, or improvements and if you would be so kind to open a PR, your contribution is welcome!
For now, this system is used in one of The Greater Heptavirate's projects. But (as I'm an author of that system) I've decided to share it for public - feel free to use if you can find any use case.
This project is shared under (attached) MIT License.