public void update(float delta) {
    delta *= timeScale;
    for (int i = 0; i < tracks.size; i++) {
      TrackEntry current = tracks.get(i);
      if (current == null) continue;

      float trackDelta = delta * current.timeScale;
      float time = current.time + trackDelta;
      float endTime = current.endTime;

      current.time = time;
      if (current.previous != null) {
        current.previous.time += trackDelta;
        current.mixTime += trackDelta;
      }

      // Check if completed the animation or a loop iteration.
      if (current.loop
          ? (current.lastTime % endTime > time % endTime)
          : (current.lastTime < endTime && time >= endTime)) {
        int count = (int) (time / endTime);
        if (current.listener != null) current.listener.complete(i, count);
        for (int ii = 0, nn = listeners.size; ii < nn; ii++) listeners.get(ii).complete(i, count);
      }

      TrackEntry next = current.next;
      if (next != null) {
        if (time - trackDelta > next.delay) setCurrent(i, next);
      } else {
        // End non-looping animation when it reaches its end time and there is no next entry.
        if (!current.loop && current.lastTime >= current.endTime) clearTrack(i);
      }
    }
  }
  /** Set the current animation. Any queued animations are cleared. */
  public TrackEntry setAnimation(int trackIndex, Animation animation, boolean loop) {
    TrackEntry current = expandToIndex(trackIndex);
    if (current != null) freeAll(current.next);

    TrackEntry entry = Pools.obtain(TrackEntry.class);
    entry.animation = animation;
    entry.loop = loop;
    entry.time = 0;
    entry.endTime = animation.getDuration();
    setCurrent(trackIndex, entry);
    return entry;
  }
  public void update(float delta) {
    delta *= timeScale;
    for (int i = 0; i < tracks.size; i++) {
      TrackEntry current = tracks.get(i);
      if (current == null) continue;

      current.time += delta * current.timeScale;
      if (current.previous != null) {
        float previousDelta = delta * current.previous.timeScale;
        current.previous.time += previousDelta;
        current.mixTime += previousDelta;
      }

      TrackEntry next = current.next;
      if (next != null) {
        next.time = current.lastTime - next.delay;
        if (next.time >= 0) setCurrent(i, next);
      } else {
        // End non-looping animation when it reaches its end time and there is no next entry.
        if (!current.loop && current.lastTime >= current.endTime) clearTrack(i);
      }
    }
  }
  /**
   * Adds an animation to be played delay seconds after the current or last queued animation.
   *
   * @param delay May be <= 0 to use duration of previous animation minus any mix duration plus the
   *     negative delay.
   */
  public TrackEntry addAnimation(int trackIndex, Animation animation, boolean loop, float delay) {
    TrackEntry entry = Pools.obtain(TrackEntry.class);
    entry.animation = animation;
    entry.loop = loop;
    entry.time = 0;
    entry.endTime = animation.getDuration();

    TrackEntry last = expandToIndex(trackIndex);
    if (last != null) {
      while (last.next != null) last = last.next;
      last.next = entry;
    } else tracks.set(trackIndex, entry);

    if (delay <= 0) {
      if (last != null) delay += last.endTime - data.getMix(last.animation, animation);
      else delay = 0;
    }
    entry.delay = delay;

    return entry;
  }