Skip to main content

Tweener Service

Intro

TpTweener is a TPT service that can be used for tweening TilePlus tile sprites, GameObjects; just about anything. The Tweener also has support for sequences. Tweens and Sequences can be Awaited or used from Coroutines.

When used with TilePlus tiles, tweens are used within TilePlus tile code, ZoneActions, or EventActions. The main restriction is that a TPT tile reference must be provided when creating Tweens or Sequences for TPT tiles.

When used with GameObjects you can use built-in methods to tween GameObject position, rotation, scale, or Color as well as a method to tween a GameObject position along a Bezier path.

To tween anything else, you create a small class containing start and end values, and some custom code that is called when the tween is evaluated. The custom code uses the 'small class' instance to:

  • Reference whatever it is that's being tweened
  • Update a current value for diagnostic use.

You can see how this works in the provided examples in the next few pages. It's pretty easy to extend the Tweener service.

Careful null-checking ensures that if a tile or GameObject is destroyed then the tween and/or its parent sequence is auto-killed. This is especially important when used with the TilePlus Layout system where tiles and prefabs are frequently added and destroyed (or restored to a pool).

Why Another Tweener?

But why create another Tweener in the first place? The Unity Asset store is full of free Tweeners on the Unity Asset Store and DemiGiant's DOTween is really great.

Here's why: none of them support natively tweening Tile sprites.

  • You can do it in DOTween with Getters and Setters but DOTween can't handle tiles suddenly becoming null (if they're deleted) in the same way as it does for GameObjects.
  • TilePlus Toolkit has a 'DOTween Adapter' which handles some of that, but it's inconvenient (and deprecated).
  • DOTween is great but is way more complex than needed just for tiles.

TpTweener is non-generic and hard-coded, but can tween anything. It doesn't have a lot of frills such as the ability to pause tweens or start with a delay (easy to do with a sequence): low GC pressure and speed were the most important design considerations.

Unlike most other Tweeners, TweenerService Tweens and Sequences can be Awaited. Coroutine support is trivial, read about it here.

It's not supposed to be a substitute for DOTween but you can make it do almost anything that DOTWeen does with some custom code.

For Tiles

You use it by first obtaining a service handle from protected static TpTweener TweenerService property within any TPT tile code.

For example:


var tId = TweenerService.CreateTween(this,
                    Vector3.zero,
                    Color.red,
                    Matrix4x4.identity,
                    TpEasingFunction.Ease.Linear,
                    TpTweener.EaseTarget.Color,
                    1,
                    0,
                    Tpweener.LoopType.PingPong,
                    -1,
                    OnFinished);

This creates and starts a Color tween (EaseTarget.Color) with the final color being Color.red. The return value is a long which is used as an ID or 'handle.'

Although the Linear easing function is specified here, it's ALWAYS linear (Lerp) for Color tweens (the value is ignored for Color tweens).

The duration is one second. The -1 means that this tween repeats a PingPong tween until killed. When the tween is killed then the OnFinished callback is invoked. When you use PingPong for tweens, the duration value is used for each phase, hence, a two second duration for a tween running in ping-pong mode takes a total of 4 seconds to complete per loop.

The first four parameters are a reference to the tile itself (this), a Vector3 value, a Color value and a Matrix value. For the Vector3, Color, and Matrix parameters you just use the one you need for a particular tween.

Here, the Vector3 field is set to Vector3.zero and the Matrix field is set to Matrix4x4.identity because this is a Color tween.

The Vector3 field is used for tweens that use Vector3 values like Position, Rotation, or Scale.

The Matrix parameter is used for Matrix tweens which are a special tween variety.

Demos

TilePlus Extras has a TpTweener folder with a few example tiles and several scenes.

  • TweenerFlexTile has fields for all possible types of tweens (except DELAY) and the fields which are shown change with what's being affected
    • I.E., if the tween target is Color then a color picker is available, but for, say, position, a Vector3 field is shown.
  • TweenSpecTile uses a TpTweenSpec asset to run a tween from that asset.
  • TweenSpecSequenceTile uses all the entries from a TpTweenSpec asset to create and run a sequence. You can also check a toggle for interactive use. This allows you to tweak the TweenSpec asset while the Editor is playing: each time the sequence ends it re-loads from the asset rather than internally repeating the cached sequence.

These three tiles are part of the normal distribution in the Plugins folder but for many uses, in a real app, you'd run a tween as the result of a Message being sent to a tile or because of a Zone entry or exit.

However, the stock 'Tweening' tiles are great for your experimentation with this feature; especially TweenSpecSequenceTile.

To use tweens in the code for Event or Zone actions, check out the TpTweenerSubObject. SubObjects are scriptable objects which are attached as references to TpTileZoneActions or TpTileEventActions.

TpTweenerSubObject can be used by a TileAction to easily tween the tile's sprite when an event is handled (EventAction) or when a Zone is entered or exited (ZoneAction.)

This approach is used in the TileFabDemos/LayoutSystem demo.

Tweens and Sequences

Tweens

You can tween Position, Rotation, Scale, and Color of Tile sprites.

For color tweens you can also specify 'Constant A', which means that the alpha value doesn't change from the value found when the tween begins.

You can also tween the Tile's Matrix, or the Matrix with Color, or the Matrix with Color-Constant-A. These let you create a single tween that can change Position, Rotation, Scale and/or Color/Color-Constant-A, with optional fine-grained control over which parts of the transform change. For example, one could specify a Matrix tween where only position and scale are changed.

  • Matrix tweens also allow specifying different Ease functions for Position, Rotation, and Scale.
  • MatrixColor and ColorConstantA use Lerp for the Color tween.
  • Color Tweens always Lerp

It's incredibly flexible, albeit a bit more work to set up.

Don't get confused: if you use one of the Matrix varieties, including those with Color, it's one tween. When the tween updates it can affect Postion, and/or Rotation, and/or Scale, and/or Color in one operation. It's not three or four tweens in parallel.

To that end, the TweenSpecSequenceTile has an interactive mode. In this mode, the sequence is forced to not loop. When the sequence completes, it restarts with a fresh set of value fom the Tween Spec asset. Hence, if you change values of this asset while the editor is Playing, such changes will be seen when the sequence restarts. As is true for project assets, the changes will remain after you exit play mode. It's a great way to play with sequences and Matrix-style tweens.

The tweener supports one-shot, looping, and ping-pong tweens. For looping tweens there's a loop count and as usual if the loop count is -1 the loop continues forever until cancelled or the tile is deleted.

Delay tweens can also be created, but they're only for sequences.

Sequences

A sequence can be created and tweens can be created with automatic adding to a sequence. Sequences do what you'd expect: run all the tweens in a list of tweens. Delay tweens can be added to a sequence. They don't tween anything, just time out. Since a callback can be issued each time the sequence changes to the next tween, a sequence of just Delay tweens can be used to create a simple sequencer.

Callbacks

Individual tweens have callbacks for each Update, on completion, and when a looping tween loops. Tweens are auto-deleted when their parent tile becomes null. Since a callback is issued to a tile and the tile is null in this case, the tween-ending callback is not issued.

Note that callbacks for each update can get extremely processor-intensive depending on how many tweens are running and what is done during execution of the callback. For example, if you have 100 tweens running then you'd get 100 callbacks every frame. Hence, these are recommended ONLY during development but there's no explicit restriction on this.

Note that while each callback provides a reference to the specific tween that caused the callback, most of the values in the instance are read-only properties so

  1. Do not hold a reference outside the local scope. These are pooled at at the end of the tween: it is returned to the pool and reset.
  2. You can't change anything except a "Diagnostics" property.
  3. You can't copy a tween and inject it back into the system.

Sequences have callbacks when complete and when the next tween in the sequence begins.

Sequences intercept the individual tween callbacks for the sequence's internal use but don't relay them to tiles.

Create a tween

There are four ways to create and run a tween.

  • Use the Create methods
    • CreateTween: create any sort of tween.
    • CreateDelayTween: Don't tween anything, just wait. Sequences only.
    • CreateTweenFromSpec: Use the TpTweenSpec asset to create tweens.
      • TpTweenSpec.Tween are the individual specs in a list of specs in the asset.
    • CreateGoTween: support for Rotation, Position, Scale, and Color tweens for GameObjects.
      • This method supports custom tweens.
      • See the next few pages for more information.

Create methods return a long integer which is the ID of the tween.

Tile Tweening

For tiles, tweens are relative: for example, if you tween position, the value provided as an endpoint is the CHANGE that you want and NOT the absolute position.

For example: Creating a tween that changes Position with an EndValue of Vector3(2.2,3.5,0) doesn't move the Tile's sprite to (2.2,3.5,0). It offsets the position by 2.2 units in the X direction and 3.5 units in the Y direction from the tile's position in the tilemap: it's relative to the tile.

So if the tile is at (0,0,0) for this example, the tile's sprite would move to 2.2,3.5,0. If the tile were at (10,15,0) then the tile's sprite moves to (10+2.2, 15+3.5, 0+0) = (12.2,18.5,0).

And that makes a lot of sense in this context: the tile itself doesn't move while you're tweening its color or transform. You're actually affecting the Tilemap and how it displays the tile's sprite. Nothing in the tile's data changes at all.

Similarly, if affecting rotation, the change is relative to the existing rotation of the tile's sprite, and if affecting scale, the change is relative to the existing scale of the tile's sprite.

Color tweens are a little different: you're tweening between the color when the tween is launched and an absolute end color specified in the CreateTween method call.

GameObject Tweening

GameObject tweens are normally absolute: for example, if you tween position you provide the initial position and the end position. If you don't specify an initial position, the Tweener uses the current position as the initial position and adjusts the end position, turning the tween into a 'relative' tween.

GameObject tweens have different Create methods but the workflow is similar.

  • GameObject tweens can be created from a project asset which defines the tween parameters.
  • GameObject tweens can be in sequences.
  • Adding GameObject tweens to sequences with Tile tweens or vice versa will cause the tween to be rejected.

See the next section for more information about GameObject tweening.

CreateTweenFromSpec

In a practical application, CreateTweenFromSpec is the most useful. Most likely you'll have several tweens that you'll use repeatedly for many tiles. Note that this doesn't support GameObject tweens.

Rather than have individual tiles have all the fields for specifying tweens (as in TweenTileExample) you use a Tween specification from a TpTweenSpec asset; this can be seen in TweenTileExample2.

You can also use specs from this asset when creating sequences.

Ignoring CreateDelayTween, the Create methods launch the tween immediately. If you need a delay, create a two-element sequence with a DELAY as the first tween in the sequence.

Operations on Tweens

Most of these use the id or 'handle' returned from the Create methods.

  • A running tween can be cancelled with KillTween.

  • Get a reference to a running tween with GetTween. However, since these are pooled items, do not hold this reference outside a local scope or you WILL get memory leaks.

  • Get an unpooled copy of a running tween with CopyTweener. Note that this is NOT pooled but is a COPY of the running tween at that point in time.

  • Get the ToString of a running tween without affecting the instance with GetTweenInfo.

  • Tweens are auto-deleted if their parent tile or the parent tile's Tilemap become null.

Create a sequence.

  • Use CreateSequence, add tweens using a Create method, and use PlaySequence to run the sequence.
    • Note that you use one of the input parameters to CreateSequence to indicate if this is a sequence of Tile tweens or of GameObject tweens: they can't be mixed in the same sequence.
  • Use CreateSequenceFromSpec and use PlaySequence to run the sequence.

CreateSequenceFromSpec uses the tween specifications in a TpTweenSpec asset and makes a sequence out of the tweens.

  • An array of indices into the List of Tweens in a TpTweenSpec asset can be used if you want only specific tweens from the list to be used.
    • Don't do this unless really needed: if you change the TpTweenSpec asset later you have to update the array.
  • If the array is null (the default) then the entire list of Tweens is used.

CreateSequence and CreateSequenceFromSpec return a long integer which is the ID of the sequence.

If you're not using CreateSequenceFromSpec:

  • Create a sequence using CreateSequence.

  • Use CreateTween or CreateDelayTween and supply the ID of the sequence in the method call.

    • When the sequence ID is supplied, the created tween is NOT immediately run, but its data structure (a TpTween instance) is added to the sequence.
  • Use PlaySequence to start the sequence.

Operations on Sequences

Just like Tweens, the id/handle retrurned from the Create methods for sequences is used as an identifier for the following:

  • Delete an unused sequence with DeletePendingSequence.
  • Kill a running sequence with (wait for it...) KillRunningSequence.
  • Sequences are auto-deleted if their parent tile or the parent tile's Tilemap become null.

Reset

Reset the tweener with ResetTweener and the Sequencer with ResetSequencer. Both release all active tweens and those which are included in the sequences' lists of tweens.

Observe

  • Use the Tween Monitor (menu item). This opens an Editor window which displays all of the information about running tweens and sequences.
    • If you have many tweens running this can slow down your game.
  • Use the Services Inspector (menu item). This shows all running services (including this one).

Tweener and GC

When you tween the tile sprite the Tilemap will execute one or more callbacks, with allocations for each one. For example, the Tween demo called "StressTest" runs about 400 tweens and generates about 60 Kb of garbage every Update. Of course this is an extreme example but it's important to bear in mind.

  • This is entirely a Tilemap phenomenon.