|
1 | 1 | /*
|
2 |
| - * Copyright (c) 2015-2021 jMonkeyEngine |
| 2 | + * Copyright (c) 2015-2022 jMonkeyEngine |
3 | 3 | * All rights reserved.
|
4 | 4 | *
|
5 | 5 | * Redistribution and use in source and binary forms, with or without
|
@@ -179,6 +179,40 @@ public static Tween callTweenMethod(double length, Object target, String method,
|
179 | 179 | return new CallTweenMethod(length, target, method, args);
|
180 | 180 | }
|
181 | 181 |
|
| 182 | + /** |
| 183 | + * Creates a tween that loops the specified delegate tween or tweens |
| 184 | + * to the desired count. If more than one tween is specified then they |
| 185 | + * are wrapped in a sequence using the sequence() method. |
| 186 | + * |
| 187 | + * @param count the desired loop count |
| 188 | + * @param delegates the desired sequence of tweens |
| 189 | + * @return a new instance |
| 190 | + */ |
| 191 | + public static Tween loopCount(int count, Tween... delegates) { |
| 192 | + if (delegates.length == 1) { |
| 193 | + return new Loop(delegates[0], count); |
| 194 | + } |
| 195 | + |
| 196 | + return new Loop(sequence(delegates), count); |
| 197 | + } |
| 198 | + |
| 199 | + /** |
| 200 | + * Creates a tween that loops the specified delegate tween or tweens |
| 201 | + * to the desired duration. If more than one tween is specified then they |
| 202 | + * are wrapped in a sequence using the sequence() method. |
| 203 | + * |
| 204 | + * @param duration the desired duration |
| 205 | + * @param delegates the desired sequence of tweens |
| 206 | + * @return a new instance |
| 207 | + */ |
| 208 | + public static Tween loopDuration(double duration, Tween... delegates) { |
| 209 | + if (delegates.length == 1) { |
| 210 | + return new Loop(delegates[0], duration); |
| 211 | + } |
| 212 | + |
| 213 | + return new Loop(sequence(delegates), duration); |
| 214 | + } |
| 215 | + |
182 | 216 | private static interface CurveFunction {
|
183 | 217 | public double curve(double input);
|
184 | 218 | }
|
@@ -644,4 +678,87 @@ public String toString() {
|
644 | 678 | return getClass().getSimpleName() + "[method=" + method + ", parms=" + Arrays.asList(args) + "]";
|
645 | 679 | }
|
646 | 680 | }
|
| 681 | + |
| 682 | + private static class Loop implements Tween, ContainsTweens { |
| 683 | + |
| 684 | + private final Tween[] delegate = new Tween[1]; |
| 685 | + private final double length; |
| 686 | + private final int loopCount; |
| 687 | + private double baseTime; |
| 688 | + private int current = 0; |
| 689 | + |
| 690 | + public Loop (Tween delegate, double duration) { |
| 691 | + if (delegate.getLength() <= 0) { |
| 692 | + throw new IllegalArgumentException("Delegate length must be greater than 0"); |
| 693 | + } |
| 694 | + if (duration <= 0) { |
| 695 | + throw new IllegalArgumentException("Duration must be greater than 0"); |
| 696 | + } |
| 697 | + |
| 698 | + this.delegate[0] = delegate; |
| 699 | + this.length = duration; |
| 700 | + this.loopCount = (int) Math.ceil(duration / delegate.getLength()); |
| 701 | + } |
| 702 | + |
| 703 | + public Loop (Tween delegate, int count) { |
| 704 | + if (count <= 0) { |
| 705 | + throw new IllegalArgumentException("Loop count must be greater than 0"); |
| 706 | + } |
| 707 | + |
| 708 | + this.delegate[0] = delegate; |
| 709 | + this.length = count * delegate.getLength(); |
| 710 | + this.loopCount = count; |
| 711 | + } |
| 712 | + |
| 713 | + @Override |
| 714 | + public double getLength() { |
| 715 | + return length; |
| 716 | + } |
| 717 | + |
| 718 | + @Override |
| 719 | + public Tween[] getTweens() { |
| 720 | + return delegate; |
| 721 | + } |
| 722 | + |
| 723 | + @Override |
| 724 | + public boolean interpolate(double t) { |
| 725 | + |
| 726 | + // Sanity check the inputs |
| 727 | + if (t < 0) { |
| 728 | + return true; |
| 729 | + } |
| 730 | + |
| 731 | + if (t < baseTime) { |
| 732 | + // We've rolled back before the current loop step |
| 733 | + // which means we need to reset and start forward |
| 734 | + // again. We have no idea how to 'roll back' and |
| 735 | + // this is the only way to maintain consistency. |
| 736 | + // The only 'normal' case where this happens is when looping |
| 737 | + // in which case a full rollback is appropriate. |
| 738 | + current = 0; |
| 739 | + baseTime = 0; |
| 740 | + } |
| 741 | + |
| 742 | + if (current >= loopCount) { |
| 743 | + return false; |
| 744 | + } |
| 745 | + |
| 746 | + // Skip any that are done |
| 747 | + while (!delegate[0].interpolate(t - baseTime)) { |
| 748 | + // Time to go to the next loop |
| 749 | + baseTime += delegate[0].getLength(); |
| 750 | + current++; |
| 751 | + if (current >= loopCount) { |
| 752 | + return false; |
| 753 | + } |
| 754 | + } |
| 755 | + |
| 756 | + return t < length; |
| 757 | + } |
| 758 | + |
| 759 | + @Override |
| 760 | + public String toString() { |
| 761 | + return getClass().getSimpleName() + "[delegate=" + delegate[0] + ", length=" + length + "]"; |
| 762 | + } |
| 763 | + } |
647 | 764 | }
|
0 commit comments