1. 程式人生 > >libgdx -spine動畫實現倒序播放

libgdx -spine動畫實現倒序播放

最近用libgdx進行遊戲開發,開發過程中遇上一個讓spine倒序播放的需求,但之前並沒有接觸過這個功能,遇上搬出程式設計師神器->百度一下,你就知道。然鵝悲催的是逛了3小時,並沒有實際的進展,雖然有部分人也在問同樣的問題,但回答的可用性幾乎為零。於是,這篇文章就出來了。
為了實現這個功能,我們首先進入到原始碼中去,在spine-libgdx的原始碼中,在AnimationState中,有一個內部類TrackEntry,裡面定義了麼一個屬性,且看:

        /** Current time in seconds this track entry has been the current track entry. The track time determines
         * {@link #getAnimationTime()}. The track time can be set to start the animation at a time other than 0, without affecting
         * looping. */
public float getTrackTime () { return trackTime; } public void setTrackTime (float trackTime) { this.trackTime = trackTime; }

從註釋中我們可以發現這個trackTime就是當前通道實體的起始位置。就好像幀動畫中的起始幀一般,而這裡的實體,實際上是和這兩個東西匹配的:

...setAnimation(trackindex,animationanme,loop)方法原始碼
    /** Sets the current animation for a track, discarding any queued animations.
     * @param
loop If true, the animation will repeat. If false it will not, instead its last frame is applied if played beyond its * duration. In either case {@link TrackEntry#getTrackEnd()} determines when the track is cleared. * @return A track entry to allow further customization of animation playback. References to the track entry must not be kept * after the {@link AnimationStateListener#dispose(TrackEntry)} event occurs. */
public TrackEntry setAnimation (int trackIndex, Animation animation, boolean loop) { if (animation == null) throw new IllegalArgumentException("animation cannot be null."); boolean interrupt = true; TrackEntry current = expandToIndex(trackIndex); if (current != null) { if (current.nextTrackLast == -1) { // Don't mix from an entry that was never applied. tracks.set(trackIndex, current.mixingFrom); queue.interrupt(current); queue.end(current); disposeNext(current); current = current.mixingFrom; interrupt = false; // mixingFrom is current again, but don't interrupt it twice. } else disposeNext(current); } TrackEntry entry = trackEntry(trackIndex, animation, loop, current); setCurrent(trackIndex, entry, interrupt); queue.drain(); return entry; } .....addAnimation(trackindex,animationanme,loop)方法原始碼 public TrackEntry addAnimation (int trackIndex, Animation animation, boolean loop, float delay) { if (animation == null) throw new IllegalArgumentException("animation cannot be null."); TrackEntry last = expandToIndex(trackIndex); if (last != null) { while (last.next != null) last = last.next; } TrackEntry entry = trackEntry(trackIndex, animation, loop, last); if (last == null) { setCurrent(trackIndex, entry, true); queue.drain(); } else { last.next = entry; if (delay <= 0) { float duration = last.animationEnd - last.animationStart; if (duration != 0) delay += duration * (1 + (int)(last.trackTime / duration)) - data.getMix(last.animation, animation); else delay = 0; } } entry.delay = delay; return entry; }

是的,我們的通道實體實際上在我們設定或者增加某個動畫的時候就會創建出來,所謂通道,是保證各動畫平穩過度的層級關係,這裡我一般使用0。話說道這裡,我們繼續往下走一波:看看setAnimation和AddAnimation是怎麼建立這個trackentry的:

/** @param last May be null. */
    private TrackEntry trackEntry (int trackIndex, Animation animation, boolean loop, TrackEntry last) {
        TrackEntry entry = trackEntryPool.obtain();
        entry.trackIndex = trackIndex;
        entry.animation = animation;
        entry.loop = loop;

        entry.eventThreshold = 0;
        entry.attachmentThreshold = 0;
        entry.drawOrderThreshold = 0;

        entry.animationStart = 0;
        entry.animationEnd = animation.getDuration();
        entry.animationLast = -1;
        entry.nextAnimationLast = -1;

        entry.delay = 0;
        entry.trackTime = 0;
        entry.trackLast = -1;
        entry.nextTrackLast = -1;
        entry.trackEnd = Float.MAX_VALUE;
        entry.timeScale = 1;

        entry.alpha = 1;
        entry.mixAlpha = 1;
        entry.mixTime = 0;
        entry.mixDuration = last == null ? 0 : data.getMix(last.animation, animation);
        return entry;
    }

在這裡,我們發現,我們上面說的,trackTime預設為0,與之對應的另一個引數timescale,則為1.這兩者的意思為:
從trackTime開始,下一次播放的時間軸點為trackTime+timescale。則根據這個以下是解決辦法:

1.animationState.getCurrent(trackIndex).setTrackTime(animationState.getCurrent(trackIndex).getAnimation().getDuration());
2.animationState.getCurrent(trackIndex).setTimeScale(-1);

以上兩行的意思為:設定trackTime的初始節點為整個動畫的全部,即時間軸末端,然後設定setTimeScale的值為-1,如此便可實現倒序播放。注意這樣寫的話比較麻煩,應該根據實際的專案進行進一步的封裝,但核心程式碼保持這樣就好。