I thought I would share the code I'm using which lets you reverse an animation by simply switching a boolean on the tk2dSpriteAnimator itself. This involves changing the core code itself so obviously you will lose any modifications you make if you update/reinstall TK2D.
The nice thing about this code is you can reverse in the middle of the animation and it keeps its position.
Here's the changes I've made to the code:
TK2DROOT\tk2d\Code\Sprites\tk2dSpriteAnimator.cs
Line 47 - added a publically accessible bool which you can toggle to reverse the animation.
public bool reversed = false;
Line 546(ish) - Replace UpdateAnimation(float deltaTime) method - when 'reversed' is true, clipTime is decremented instead of incremented. I've also made a few changes to how it calculates the Frame number so that is supports negative clip time. Note: Reverse mode is only supported when on wrap mode "loop" as that is all I needed it for.
/// <summary>
/// Modified by Twice Circled to add reverse behaviour for looping anims - 22/05/14
/// Steps the animation based on the given deltaTime
/// Disable tk2dSpriteAnimator, and then call UpdateAnimation manually to feed your own time
/// eg. when you need an animation to play when the game is paused using Time.timeScale.
/// </summary>
public void UpdateAnimation (float deltaTime) {
// Only process when clip is playing
var localState = state | globalState;
if (localState != State.Playing) {
return;
}
// Current clip should not be null at this point
// Only supports reverse behaviour on 'loop'
if (reversed && currentClip.wrapMode == tk2dSpriteAnimationClip.WrapMode.Loop) {
clipTime -= deltaTime * clipFps;
} else {
clipTime += deltaTime * clipFps;
}
int _previousFrame = previousFrame;
switch (currentClip.wrapMode) {
case tk2dSpriteAnimationClip.WrapMode.Loop:
case tk2dSpriteAnimationClip.WrapMode.RandomLoop:
{
int currFrame = ((int)clipTime % currentClip.frames.Length + currentClip.frames.Length) % currentClip.frames.Length;
SetFrameInternal (currFrame);
// Only supports reverse behaviour on 'loop'
if (reversed && currentClip.wrapMode == tk2dSpriteAnimationClip.WrapMode.Loop) {
if (currFrame > _previousFrame) { // wrap around
ProcessEvents (_previousFrame, 0, -1); // back to beg of clip
ProcessEvents (currentClip.frames.Length, currFrame, -1); // process back to current frame
} else {
ProcessEvents (_previousFrame, currFrame, -1);
}
} else {
if (currFrame < _previousFrame) { // wrap around
ProcessEvents (_previousFrame, currentClip.frames.Length - 1, 1); // up to end of clip
ProcessEvents (-1, currFrame, 1); // process up to current frame
} else {
ProcessEvents (_previousFrame, currFrame, 1);
}
}
break;
}
case tk2dSpriteAnimationClip.WrapMode.LoopSection:
{
int currFrame = (int)clipTime;
int currFrameLooped = currentClip.loopStart + ((currFrame - currentClip.loopStart) % (currentClip.frames.Length - currentClip.loopStart));
if (currFrame >= currentClip.loopStart) {
SetFrameInternal (currFrameLooped);
currFrame = currFrameLooped;
if (_previousFrame < currentClip.loopStart) {
ProcessEvents (_previousFrame, currentClip.loopStart - 1, 1); // processed up to loop-start
ProcessEvents (currentClip.loopStart - 1, currFrame, 1); // to current frame, doesn't cope if already looped once
} else {
if (currFrame < _previousFrame) {
ProcessEvents (_previousFrame, currentClip.frames.Length - 1, 1); // up to end of clip
ProcessEvents (currentClip.loopStart - 1, currFrame, 1); // up to current frame
} else {
ProcessEvents (_previousFrame, currFrame, 1); // this doesn't cope with multi loops within one frame
}
}
} else {
SetFrameInternal (currFrame);
ProcessEvents (_previousFrame, currFrame, 1);
}
break;
}
case tk2dSpriteAnimationClip.WrapMode.PingPong:
{
int currFrame = (currentClip.frames.Length > 1) ? ((int)clipTime % (currentClip.frames.Length + currentClip.frames.Length - 2)) : 0;
int dir = 1;
if (currFrame >= currentClip.frames.Length) {
currFrame = 2 * currentClip.frames.Length - 2 - currFrame;
dir = -1;
}
// This is likely to be buggy - this needs to be rewritten storing prevClipTime and comparing that rather than previousFrame
// as its impossible to detect direction with this, when running at frame speeds where a transition occurs within a frame
if (currFrame < _previousFrame) {
dir = -1;
}
SetFrameInternal (currFrame);
ProcessEvents (_previousFrame, currFrame, dir);
break;
}
case tk2dSpriteAnimationClip.WrapMode.Once:
{
int currFrame = (int)clipTime;
if (currFrame >= currentClip.frames.Length) {
SetFrameInternal (currentClip.frames.Length - 1); // set to last frame
state &= ~State.Playing; // stop playing before calling event - the event could start a new animation playing here
ProcessEvents (_previousFrame, currentClip.frames.Length - 1, 1);
OnAnimationCompleted ();
} else {
SetFrameInternal (currFrame);
ProcessEvents (_previousFrame, currFrame, 1);
}
break;
}
}
}
Usage: Once set up the usage is very simple. The following code reverses the animation when you press the middle mouse button.
// Script attached to GameObject with a tk2dSpriteAnimator component attached.
void Update () {
tk2dSpriteAnimator animator = GetComponent<tk2dSpriteAnimator>();
if (Input.GetMouseButtonDown (2)) {
animator.reversed = !animator.reversed;
}
}
Just copy and paste the code above into your tk2dSpriteAnimator.cs script. DISCLAIMER: Use at your own risk, there is no guarantee that this code will continue to work in future versions of tk2d.