Skip to content

Commit 1a071eb

Browse files
authored
Added a Loop tween to Tweens factory class (#1846)
* Added a Loop tween to Tweens factory class. Supports looping by count or duration. * Redesigned the Loop tween to work similar to Sequence tween. Now fast forwarding the loop will also try to catch up the loops left behind making sure they always see their 'length'. * Added the missing Override annotation.
1 parent 7911a61 commit 1a071eb

File tree

1 file changed

+118
-1
lines changed

1 file changed

+118
-1
lines changed

jme3-core/src/main/java/com/jme3/anim/tween/Tweens.java

Lines changed: 118 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2015-2021 jMonkeyEngine
2+
* Copyright (c) 2015-2022 jMonkeyEngine
33
* All rights reserved.
44
*
55
* 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,
179179
return new CallTweenMethod(length, target, method, args);
180180
}
181181

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+
182216
private static interface CurveFunction {
183217
public double curve(double input);
184218
}
@@ -644,4 +678,87 @@ public String toString() {
644678
return getClass().getSimpleName() + "[method=" + method + ", parms=" + Arrays.asList(args) + "]";
645679
}
646680
}
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+
}
647764
}

0 commit comments

Comments
 (0)