-
Notifications
You must be signed in to change notification settings - Fork 23
2. The Details
We should know how to setup a tween at this point. The extension methods make that super easy. In reality, they are just taking care of some minor housekeeping for us. The way ZestKit is setup provides some nice flexibility and if you want to get into tinkering with its internals there are only a few objects you should know about.
-
ZestKit: the only MonoBehaviour subclass present. It is very simple class with a simple mind. All it nows about is calling a tweenstickmethod. When the tween is done (tick will return true indicating completion) it removes the tween from it's internal List. That is all it does. -
Tween<T>: the state holder. TheTweenclass manages the tween's state (running, paused, complete). It knows how to count from 0 to the duration of the tween. It doesn't, however, know which object or property it is tweening. It only cares about the type of the tween (int, float, Vector2, etc). -
ITweenTarget<T>: the simplest of all the ZestKit players. All it does is set the tweened value. -
AbstractTweenTarget<U,T>: this is a handy base class that implements ITweenTarget. If you use this as a base class when creating a new ITweenTarget all you have to do is right-click -> Refactor -> Implement abstract members and the IDE will essentially write the class for you. See the TweenTargets.cs file for a bunch of examples. -
Zest: this is a special little helper. It can be used with or without ZestKit (very handy for making quick coroutine tweens in just a few lines of code for example). It consists of a series of methods that handle the tween math including easing. -
AbstractTweenable: tweens that aren't even tweens. More info is available in this wiki page
This class/interface structure lets us separate out the responsibilities. All of the tweenable types are already written and ready for use (Tween<T> subclasses). Anytime you need to tween something new the only thing required is to make a new TweenTarget<T> which consists of just a single method to set the final tweened value.
Now lets have a look at what is happening under the hood in one of the extension methods. We'll look at the ZKalphaTo method. The comments below break down what is going on.
// the MaterialAlphaTarget class implements ITweenTarget<float>. All it needs to know how to do is
// set the value on the object being tweened (in this case, a Material color property)
var tweenTarget = new MaterialAlphaTarget( self, propertyName );
// alpha is a float so we are going to need the built in FloatTween to handle the tweening. There are
// built in *Tween classes for all tweenable values. We also set the initial state of the tween
// and pass along the tweenTarget so it knows where to send the tweened value
var tween = new FloatTween( tweenTarget, self.GetColor( propertyName ).a, to, duration );Sometimes you need to know when a tween completes or when a loop iteration finishes. You can use the set*CompletionHandler methods to set an Action that will be called at the appropriate time. The example below will run the tween and when it is complete the completion handler will be called which is a method in the current class (someMethodToCallWhenTheTweenCompletes).
quad.ZKpositionTo( Vector3.one, 0.3f )
.setCompletionHandler( someMethodToCallWhenTheTweenCompletes )
.start();For most folks that will work just fine and you can stop reading. This next section is for folks who want to avoid all possible allocations at the expense of slightly more verbose code.
Without going into the details of how .NET/Mono works with regard to closures let's just say that when you pass a delegate that is a named method in your class (as in the example above) you will get an allocation. The same would be true if you just called that method in an anonymous delegate like this: () => this.someMethodToCallWhenTheTweenCompletes(). With ZestKit, we can optimize away this allocation. The way ZestKit does this is by providing a context property that you can set to whatever you want. Below is a modified version that will not cause any allocations for the completion handler:
quad.ZKpositionTo( Vector3.one, 0.3f )
.setContext( this ) // notice that we are setting the context here which will be available in the tween
.setCompletionHandler( tween =>
{
var self = (OurClass)tween.context; // here we can fetch and cast our context without allocating
self.someMethodToCallWhenTheTweenCompletes();
} )
.start();