| package aurelienribon.tweenengine; |
| |
| import aurelienribon.tweenengine.equations.Quad; |
| import java.util.HashMap; |
| import java.util.Map; |
| |
| /** |
| * Core class of the Tween Engine. A Tween is basically an interpolation |
| * between two values of an object attribute. However, the main interest of a |
| * Tween is that you can apply an easing formula on this interpolation, in |
| * order to smooth the transitions or to achieve cool effects like springs or |
| * bounces. |
| * <p/> |
| * |
| * The Universal Tween Engine is called "universal" because it is able to apply |
| * interpolations on every attribute from every possible object. Therefore, |
| * every object in your application can be animated with cool effects: it does |
| * not matter if your application is a game, a desktop interface or even a |
| * console program! If it makes sense to animate something, then it can be |
| * animated through this engine. |
| * <p/> |
| * |
| * This class contains many static factory methods to create and instantiate |
| * new interpolations easily. The common way to create a Tween is by using one |
| * of these factories: |
| * <p/> |
| * |
| * - Tween.to(...)<br/> |
| * - Tween.from(...)<br/> |
| * - Tween.set(...)<br/> |
| * - Tween.call(...) |
| * <p/> |
| * |
| * <h2>Example - firing a Tween</h2> |
| * |
| * The following example will move the target horizontal position from its |
| * current value to x=200 and y=300, during 500ms, but only after a delay of |
| * 1000ms. The animation will also be repeated 2 times (the starting position |
| * is registered at the end of the delay, so the animation will automatically |
| * restart from this registered position). |
| * <p/> |
| * |
| * <pre> {@code |
| * Tween.to(myObject, POSITION_XY, 0.5f) |
| * .target(200, 300) |
| * .ease(Quad.INOUT) |
| * .delay(1.0f) |
| * .repeat(2, 0.2f) |
| * .start(myManager); |
| * }</pre> |
| * |
| * Tween life-cycles can be automatically managed for you, thanks to the |
| * {@link TweenManager} class. If you choose to manage your tween when you start |
| * it, then you don't need to care about it anymore. <b>Tweens are |
| * <i>fire-and-forget</i>: don't think about them anymore once you started |
| * them (if they are managed of course).</b> |
| * <p/> |
| * |
| * You need to periodicaly update the tween engine, in order to compute the new |
| * values. If your tweens are managed, only update the manager; else you need |
| * to call {@link #update()} on your tweens periodically. |
| * <p/> |
| * |
| * <h2>Example - setting up the engine</h2> |
| * |
| * The engine cannot directly change your objects attributes, since it doesn't |
| * know them. Therefore, you need to tell him how to get and set the different |
| * attributes of your objects: <b>you need to implement the {@link |
| * TweenAccessor} interface for each object class you will animate</b>. Once |
| * done, don't forget to register these implementations, using the static method |
| * {@link registerAccessor()}, when you start your application. |
| * |
| * @see TweenAccessor |
| * @see TweenManager |
| * @see TweenEquation |
| * @see Timeline |
| * @author Aurelien Ribon | http://www.aurelienribon.com/ |
| */ |
| public final class Tween extends BaseTween<Tween> { |
| // ------------------------------------------------------------------------- |
| // Static -- misc |
| // ------------------------------------------------------------------------- |
| |
| /** |
| * Used as parameter in {@link #repeat(int, float)} and |
| * {@link #repeatYoyo(int, float)} methods. |
| */ |
| public static final int INFINITY = -1; |
| |
| private static int combinedAttrsLimit = 3; |
| private static int waypointsLimit = 0; |
| |
| /** |
| * Changes the limit for combined attributes. Defaults to 3 to reduce |
| * memory footprint. |
| */ |
| public static void setCombinedAttributesLimit(int limit) { |
| Tween.combinedAttrsLimit = limit; |
| } |
| |
| /** |
| * Changes the limit of allowed waypoints for each tween. Defaults to 0 to |
| * reduce memory footprint. |
| */ |
| public static void setWaypointsLimit(int limit) { |
| Tween.waypointsLimit = limit; |
| } |
| |
| /** |
| * Gets the version number of the library. |
| */ |
| public static String getVersion() { |
| return "6.3.3"; |
| } |
| |
| // ------------------------------------------------------------------------- |
| // Static -- pool |
| // ------------------------------------------------------------------------- |
| |
| private static final Pool.Callback<Tween> poolCallback = new Pool.Callback<Tween>() { |
| @Override public void onPool(Tween obj) {obj.reset();} |
| @Override public void onUnPool(Tween obj) {obj.reset();} |
| }; |
| |
| private static final Pool<Tween> pool = new Pool<Tween>(20, poolCallback) { |
| @Override protected Tween create() {return new Tween();} |
| }; |
| |
| /** |
| * Used for debug purpose. Gets the current number of objects that are |
| * waiting in the Tween pool. |
| */ |
| public static int getPoolSize() { |
| return pool.size(); |
| } |
| |
| /** |
| * Increases the minimum capacity of the pool. Capacity defaults to 20. |
| */ |
| public static void ensurePoolCapacity(int minCapacity) { |
| pool.ensureCapacity(minCapacity); |
| } |
| |
| // ------------------------------------------------------------------------- |
| // Static -- tween accessors |
| // ------------------------------------------------------------------------- |
| |
| private static final Map<Class<?>, TweenAccessor<?>> registeredAccessors = new HashMap<Class<?>, TweenAccessor<?>>(); |
| |
| /** |
| * Registers an accessor with the class of an object. This accessor will be |
| * used by tweens applied to every objects implementing the registered |
| * class, or inheriting from it. |
| * |
| * @param someClass An object class. |
| * @param defaultAccessor The accessor that will be used to tween any |
| * object of class "someClass". |
| */ |
| public static void registerAccessor(Class<?> someClass, TweenAccessor<?> defaultAccessor) { |
| registeredAccessors.put(someClass, defaultAccessor); |
| } |
| |
| /** |
| * Gets the registered TweenAccessor associated with the given object class. |
| * |
| * @param someClass An object class. |
| */ |
| public static TweenAccessor<?> getRegisteredAccessor(Class<?> someClass) { |
| return registeredAccessors.get(someClass); |
| } |
| |
| // ------------------------------------------------------------------------- |
| // Static -- factories |
| // ------------------------------------------------------------------------- |
| |
| /** |
| * Factory creating a new standard interpolation. This is the most common |
| * type of interpolation. The starting values are retrieved automatically |
| * after the delay (if any). |
| * <br/><br/> |
| * |
| * <b>You need to set the target values of the interpolation by using one |
| * of the target() methods</b>. The interpolation will run from the |
| * starting values to these target values. |
| * <br/><br/> |
| * |
| * The common use of Tweens is "fire-and-forget": you do not need to care |
| * for tweens once you added them to a TweenManager, they will be updated |
| * automatically, and cleaned once finished. Common call: |
| * <br/><br/> |
| * |
| * <pre> {@code |
| * Tween.to(myObject, POSITION, 1.0f) |
| * .target(50, 70) |
| * .ease(Quad.INOUT) |
| * .start(myManager); |
| * }</pre> |
| * |
| * Several options such as delay, repetitions and callbacks can be added to |
| * the tween. |
| * |
| * @param target The target object of the interpolation. |
| * @param tweenType The desired type of interpolation. |
| * @param duration The duration of the interpolation, in milliseconds. |
| * @return The generated Tween. |
| */ |
| public static Tween to(Object target, int tweenType, float duration) { |
| Tween tween = pool.get(); |
| tween.setup(target, tweenType, duration); |
| tween.ease(Quad.INOUT); |
| tween.path(TweenPaths.catmullRom); |
| return tween; |
| } |
| |
| /** |
| * Factory creating a new reversed interpolation. The ending values are |
| * retrieved automatically after the delay (if any). |
| * <br/><br/> |
| * |
| * <b>You need to set the starting values of the interpolation by using one |
| * of the target() methods</b>. The interpolation will run from the |
| * starting values to these target values. |
| * <br/><br/> |
| * |
| * The common use of Tweens is "fire-and-forget": you do not need to care |
| * for tweens once you added them to a TweenManager, they will be updated |
| * automatically, and cleaned once finished. Common call: |
| * <br/><br/> |
| * |
| * <pre> {@code |
| * Tween.from(myObject, POSITION, 1.0f) |
| * .target(0, 0) |
| * .ease(Quad.INOUT) |
| * .start(myManager); |
| * }</pre> |
| * |
| * Several options such as delay, repetitions and callbacks can be added to |
| * the tween. |
| * |
| * @param target The target object of the interpolation. |
| * @param tweenType The desired type of interpolation. |
| * @param duration The duration of the interpolation, in milliseconds. |
| * @return The generated Tween. |
| */ |
| public static Tween from(Object target, int tweenType, float duration) { |
| Tween tween = pool.get(); |
| tween.setup(target, tweenType, duration); |
| tween.ease(Quad.INOUT); |
| tween.path(TweenPaths.catmullRom); |
| tween.isFrom = true; |
| return tween; |
| } |
| |
| /** |
| * Factory creating a new instantaneous interpolation (thus this is not |
| * really an interpolation). |
| * <br/><br/> |
| * |
| * <b>You need to set the target values of the interpolation by using one |
| * of the target() methods</b>. The interpolation will set the target |
| * attribute to these values after the delay (if any). |
| * <br/><br/> |
| * |
| * The common use of Tweens is "fire-and-forget": you do not need to care |
| * for tweens once you added them to a TweenManager, they will be updated |
| * automatically, and cleaned once finished. Common call: |
| * <br/><br/> |
| * |
| * <pre> {@code |
| * Tween.set(myObject, POSITION) |
| * .target(50, 70) |
| * .delay(1.0f) |
| * .start(myManager); |
| * }</pre> |
| * |
| * Several options such as delay, repetitions and callbacks can be added to |
| * the tween. |
| * |
| * @param target The target object of the interpolation. |
| * @param tweenType The desired type of interpolation. |
| * @return The generated Tween. |
| */ |
| public static Tween set(Object target, int tweenType) { |
| Tween tween = pool.get(); |
| tween.setup(target, tweenType, 0); |
| tween.ease(Quad.INOUT); |
| return tween; |
| } |
| |
| /** |
| * Factory creating a new timer. The given callback will be triggered on |
| * each iteration start, after the delay. |
| * <br/><br/> |
| * |
| * The common use of Tweens is "fire-and-forget": you do not need to care |
| * for tweens once you added them to a TweenManager, they will be updated |
| * automatically, and cleaned once finished. Common call: |
| * <br/><br/> |
| * |
| * <pre> {@code |
| * Tween.call(myCallback) |
| * .delay(1.0f) |
| * .repeat(10, 1000) |
| * .start(myManager); |
| * }</pre> |
| * |
| * @param callback The callback that will be triggered on each iteration |
| * start. |
| * @return The generated Tween. |
| * @see TweenCallback |
| */ |
| public static Tween call(TweenCallback callback) { |
| Tween tween = pool.get(); |
| tween.setup(null, -1, 0); |
| tween.setCallback(callback); |
| tween.setCallbackTriggers(TweenCallback.START); |
| return tween; |
| } |
| |
| /** |
| * Convenience method to create an empty tween. Such object is only useful |
| * when placed inside animation sequences (see {@link Timeline}), in which |
| * it may act as a beacon, so you can set a callback on it in order to |
| * trigger some action at the right moment. |
| * |
| * @return The generated Tween. |
| * @see Timeline |
| */ |
| public static Tween mark() { |
| Tween tween = pool.get(); |
| tween.setup(null, -1, 0); |
| return tween; |
| } |
| |
| // ------------------------------------------------------------------------- |
| // Attributes |
| // ------------------------------------------------------------------------- |
| |
| // Main |
| private Object target; |
| private Class<?> targetClass; |
| private TweenAccessor<Object> accessor; |
| private int type; |
| private TweenEquation equation; |
| private TweenPath path; |
| |
| // General |
| private boolean isFrom; |
| private boolean isRelative; |
| private int combinedAttrsCnt; |
| private int waypointsCnt; |
| |
| // Values |
| private final float[] startValues = new float[combinedAttrsLimit]; |
| private final float[] targetValues = new float[combinedAttrsLimit]; |
| private final float[] waypoints = new float[waypointsLimit * combinedAttrsLimit]; |
| |
| // Buffers |
| private float[] accessorBuffer = new float[combinedAttrsLimit]; |
| private float[] pathBuffer = new float[(2+waypointsLimit)*combinedAttrsLimit]; |
| |
| // ------------------------------------------------------------------------- |
| // Setup |
| // ------------------------------------------------------------------------- |
| |
| private Tween() { |
| reset(); |
| } |
| |
| @Override |
| protected void reset() { |
| super.reset(); |
| |
| target = null; |
| targetClass = null; |
| accessor = null; |
| type = -1; |
| equation = null; |
| path = null; |
| |
| isFrom = isRelative = false; |
| combinedAttrsCnt = waypointsCnt = 0; |
| |
| if (accessorBuffer.length != combinedAttrsLimit) { |
| accessorBuffer = new float[combinedAttrsLimit]; |
| } |
| |
| if (pathBuffer.length != (2+waypointsLimit)*combinedAttrsLimit) { |
| pathBuffer = new float[(2+waypointsLimit)*combinedAttrsLimit]; |
| } |
| } |
| |
| private void setup(Object target, int tweenType, float duration) { |
| if (duration < 0) throw new RuntimeException("Duration can't be negative"); |
| |
| this.target = target; |
| this.targetClass = target != null ? findTargetClass() : null; |
| this.type = tweenType; |
| this.duration = duration; |
| } |
| |
| private Class<?> findTargetClass() { |
| if (registeredAccessors.containsKey(target.getClass())) return target.getClass(); |
| if (target instanceof TweenAccessor) return target.getClass(); |
| |
| Class<?> parentClass = target.getClass().getSuperclass(); |
| while (parentClass != null && !registeredAccessors.containsKey(parentClass)) |
| parentClass = parentClass.getSuperclass(); |
| |
| return parentClass; |
| } |
| |
| // ------------------------------------------------------------------------- |
| // Public API |
| // ------------------------------------------------------------------------- |
| |
| /** |
| * Sets the easing equation of the tween. Existing equations are located in |
| * <i>aurelienribon.tweenengine.equations</i> package, but you can of course |
| * implement your owns, see {@link TweenEquation}. You can also use the |
| * {@link TweenEquations} static instances to quickly access all the |
| * equations. Default equation is Quad.INOUT. |
| * <p/> |
| * |
| * <b>Proposed equations are:</b><br/> |
| * - Linear.INOUT,<br/> |
| * - Quad.IN | OUT | INOUT,<br/> |
| * - Cubic.IN | OUT | INOUT,<br/> |
| * - Quart.IN | OUT | INOUT,<br/> |
| * - Quint.IN | OUT | INOUT,<br/> |
| * - Circ.IN | OUT | INOUT,<br/> |
| * - Sine.IN | OUT | INOUT,<br/> |
| * - Expo.IN | OUT | INOUT,<br/> |
| * - Back.IN | OUT | INOUT,<br/> |
| * - Bounce.IN | OUT | INOUT,<br/> |
| * - Elastic.IN | OUT | INOUT |
| * |
| * @return The current tween, for chaining instructions. |
| * @see TweenEquation |
| * @see TweenEquations |
| */ |
| public Tween ease(TweenEquation easeEquation) { |
| this.equation = easeEquation; |
| return this; |
| } |
| |
| /** |
| * Forces the tween to use the TweenAccessor registered with the given |
| * target class. Useful if you want to use a specific accessor associated |
| * to an interface, for instance. |
| * |
| * @param targetClass A class registered with an accessor. |
| * @return The current tween, for chaining instructions. |
| */ |
| public Tween cast(Class<?> targetClass) { |
| if (isStarted()) throw new RuntimeException("You can't cast the target of a tween once it is started"); |
| this.targetClass = targetClass; |
| return this; |
| } |
| |
| /** |
| * Sets the target value of the interpolation. The interpolation will run |
| * from the <b>value at start time (after the delay, if any)</b> to this |
| * target value. |
| * <p/> |
| * |
| * To sum-up:<br/> |
| * - start value: value at start time, after delay<br/> |
| * - end value: param |
| * |
| * @param targetValue The target value of the interpolation. |
| * @return The current tween, for chaining instructions. |
| */ |
| public Tween target(float targetValue) { |
| targetValues[0] = targetValue; |
| return this; |
| } |
| |
| /** |
| * Sets the target values of the interpolation. The interpolation will run |
| * from the <b>values at start time (after the delay, if any)</b> to these |
| * target values. |
| * <p/> |
| * |
| * To sum-up:<br/> |
| * - start values: values at start time, after delay<br/> |
| * - end values: params |
| * |
| * @param targetValue1 The 1st target value of the interpolation. |
| * @param targetValue2 The 2nd target value of the interpolation. |
| * @return The current tween, for chaining instructions. |
| */ |
| public Tween target(float targetValue1, float targetValue2) { |
| targetValues[0] = targetValue1; |
| targetValues[1] = targetValue2; |
| return this; |
| } |
| |
| /** |
| * Sets the target values of the interpolation. The interpolation will run |
| * from the <b>values at start time (after the delay, if any)</b> to these |
| * target values. |
| * <p/> |
| * |
| * To sum-up:<br/> |
| * - start values: values at start time, after delay<br/> |
| * - end values: params |
| * |
| * @param targetValue1 The 1st target value of the interpolation. |
| * @param targetValue2 The 2nd target value of the interpolation. |
| * @param targetValue3 The 3rd target value of the interpolation. |
| * @return The current tween, for chaining instructions. |
| */ |
| public Tween target(float targetValue1, float targetValue2, float targetValue3) { |
| targetValues[0] = targetValue1; |
| targetValues[1] = targetValue2; |
| targetValues[2] = targetValue3; |
| return this; |
| } |
| |
| /** |
| * Sets the target values of the interpolation. The interpolation will run |
| * from the <b>values at start time (after the delay, if any)</b> to these |
| * target values. |
| * <p/> |
| * |
| * To sum-up:<br/> |
| * - start values: values at start time, after delay<br/> |
| * - end values: params |
| * |
| * @param targetValues The target values of the interpolation. |
| * @return The current tween, for chaining instructions. |
| */ |
| public Tween target(float... targetValues) { |
| if (targetValues.length > combinedAttrsLimit) throwCombinedAttrsLimitReached(); |
| System.arraycopy(targetValues, 0, this.targetValues, 0, targetValues.length); |
| return this; |
| } |
| |
| /** |
| * Sets the target value of the interpolation, relatively to the <b>value |
| * at start time (after the delay, if any)</b>. |
| * <p/> |
| * |
| * To sum-up:<br/> |
| * - start value: value at start time, after delay<br/> |
| * - end value: param + value at start time, after delay |
| * |
| * @param targetValue The relative target value of the interpolation. |
| * @return The current tween, for chaining instructions. |
| */ |
| public Tween targetRelative(float targetValue) { |
| isRelative = true; |
| targetValues[0] = isInitialized() ? targetValue + startValues[0] : targetValue; |
| return this; |
| } |
| |
| /** |
| * Sets the target values of the interpolation, relatively to the <b>values |
| * at start time (after the delay, if any)</b>. |
| * <p/> |
| * |
| * To sum-up:<br/> |
| * - start values: values at start time, after delay<br/> |
| * - end values: params + values at start time, after delay |
| * |
| * @param targetValue1 The 1st relative target value of the interpolation. |
| * @param targetValue2 The 2nd relative target value of the interpolation. |
| * @return The current tween, for chaining instructions. |
| */ |
| public Tween targetRelative(float targetValue1, float targetValue2) { |
| isRelative = true; |
| targetValues[0] = isInitialized() ? targetValue1 + startValues[0] : targetValue1; |
| targetValues[1] = isInitialized() ? targetValue2 + startValues[1] : targetValue2; |
| return this; |
| } |
| |
| /** |
| * Sets the target values of the interpolation, relatively to the <b>values |
| * at start time (after the delay, if any)</b>. |
| * <p/> |
| * |
| * To sum-up:<br/> |
| * - start values: values at start time, after delay<br/> |
| * - end values: params + values at start time, after delay |
| * |
| * @param targetValue1 The 1st relative target value of the interpolation. |
| * @param targetValue2 The 2nd relative target value of the interpolation. |
| * @param targetValue3 The 3rd relative target value of the interpolation. |
| * @return The current tween, for chaining instructions. |
| */ |
| public Tween targetRelative(float targetValue1, float targetValue2, float targetValue3) { |
| isRelative = true; |
| targetValues[0] = isInitialized() ? targetValue1 + startValues[0] : targetValue1; |
| targetValues[1] = isInitialized() ? targetValue2 + startValues[1] : targetValue2; |
| targetValues[2] = isInitialized() ? targetValue3 + startValues[2] : targetValue3; |
| return this; |
| } |
| |
| /** |
| * Sets the target values of the interpolation, relatively to the <b>values |
| * at start time (after the delay, if any)</b>. |
| * <p/> |
| * |
| * To sum-up:<br/> |
| * - start values: values at start time, after delay<br/> |
| * - end values: params + values at start time, after delay |
| * |
| * @param targetValues The relative target values of the interpolation. |
| * @return The current tween, for chaining instructions. |
| */ |
| public Tween targetRelative(float... targetValues) { |
| if (targetValues.length > combinedAttrsLimit) throwCombinedAttrsLimitReached(); |
| for (int i=0; i<targetValues.length; i++) { |
| this.targetValues[i] = isInitialized() ? targetValues[i] + startValues[i] : targetValues[i]; |
| } |
| |
| isRelative = true; |
| return this; |
| } |
| |
| /** |
| * Adds a waypoint to the path. The default path runs from the start values |
| * to the end values linearly. If you add waypoints, the default path will |
| * use a smooth catmull-rom spline to navigate between the waypoints, but |
| * you can change this behavior by using the {@link #path(TweenPath)} |
| * method. |
| * |
| * @param targetValue The target of this waypoint. |
| * @return The current tween, for chaining instructions. |
| */ |
| public Tween waypoint(float targetValue) { |
| if (waypointsCnt == waypointsLimit) throwWaypointsLimitReached(); |
| waypoints[waypointsCnt] = targetValue; |
| waypointsCnt += 1; |
| return this; |
| } |
| |
| /** |
| * Adds a waypoint to the path. The default path runs from the start values |
| * to the end values linearly. If you add waypoints, the default path will |
| * use a smooth catmull-rom spline to navigate between the waypoints, but |
| * you can change this behavior by using the {@link #path(TweenPath)} |
| * method. |
| * <p/> |
| * Note that if you want waypoints relative to the start values, use one of |
| * the .targetRelative() methods to define your target. |
| * |
| * @param targetValue1 The 1st target of this waypoint. |
| * @param targetValue2 The 2nd target of this waypoint. |
| * @return The current tween, for chaining instructions. |
| */ |
| public Tween waypoint(float targetValue1, float targetValue2) { |
| if (waypointsCnt == waypointsLimit) throwWaypointsLimitReached(); |
| waypoints[waypointsCnt*2] = targetValue1; |
| waypoints[waypointsCnt*2+1] = targetValue2; |
| waypointsCnt += 1; |
| return this; |
| } |
| |
| /** |
| * Adds a waypoint to the path. The default path runs from the start values |
| * to the end values linearly. If you add waypoints, the default path will |
| * use a smooth catmull-rom spline to navigate between the waypoints, but |
| * you can change this behavior by using the {@link #path(TweenPath)} |
| * method. |
| * <p/> |
| * Note that if you want waypoints relative to the start values, use one of |
| * the .targetRelative() methods to define your target. |
| * |
| * @param targetValue1 The 1st target of this waypoint. |
| * @param targetValue2 The 2nd target of this waypoint. |
| * @param targetValue3 The 3rd target of this waypoint. |
| * @return The current tween, for chaining instructions. |
| */ |
| public Tween waypoint(float targetValue1, float targetValue2, float targetValue3) { |
| if (waypointsCnt == waypointsLimit) throwWaypointsLimitReached(); |
| waypoints[waypointsCnt*3] = targetValue1; |
| waypoints[waypointsCnt*3+1] = targetValue2; |
| waypoints[waypointsCnt*3+2] = targetValue3; |
| waypointsCnt += 1; |
| return this; |
| } |
| |
| /** |
| * Adds a waypoint to the path. The default path runs from the start values |
| * to the end values linearly. If you add waypoints, the default path will |
| * use a smooth catmull-rom spline to navigate between the waypoints, but |
| * you can change this behavior by using the {@link #path(TweenPath)} |
| * method. |
| * <p/> |
| * Note that if you want waypoints relative to the start values, use one of |
| * the .targetRelative() methods to define your target. |
| * |
| * @param targetValues The targets of this waypoint. |
| * @return The current tween, for chaining instructions. |
| */ |
| public Tween waypoint(float... targetValues) { |
| if (waypointsCnt == waypointsLimit) throwWaypointsLimitReached(); |
| System.arraycopy(targetValues, 0, waypoints, waypointsCnt*targetValues.length, targetValues.length); |
| waypointsCnt += 1; |
| return this; |
| } |
| |
| /** |
| * Sets the algorithm that will be used to navigate through the waypoints, |
| * from the start values to the end values. Default is a catmull-rom spline, |
| * but you can find other paths in the {@link TweenPaths} class. |
| * |
| * @param path A TweenPath implementation. |
| * @return The current tween, for chaining instructions. |
| * @see TweenPath |
| * @see TweenPaths |
| */ |
| public Tween path(TweenPath path) { |
| this.path = path; |
| return this; |
| } |
| |
| // ------------------------------------------------------------------------- |
| // Getters |
| // ------------------------------------------------------------------------- |
| |
| /** |
| * Gets the target object. |
| */ |
| public Object getTarget() { |
| return target; |
| } |
| |
| /** |
| * Gets the type of the tween. |
| */ |
| public int getType() { |
| return type; |
| } |
| |
| /** |
| * Gets the easing equation. |
| */ |
| public TweenEquation getEasing() { |
| return equation; |
| } |
| |
| /** |
| * Gets the target values. The returned buffer is as long as the maximum |
| * allowed combined values. Therefore, you're surely not interested in all |
| * its content. Use {@link #getCombinedTweenCount()} to get the number of |
| * interesting slots. |
| */ |
| public float[] getTargetValues() { |
| return targetValues; |
| } |
| |
| /** |
| * Gets the number of combined animations. |
| */ |
| public int getCombinedAttributesCount() { |
| return combinedAttrsCnt; |
| } |
| |
| /** |
| * Gets the TweenAccessor used with the target. |
| */ |
| public TweenAccessor<?> getAccessor() { |
| return accessor; |
| } |
| |
| /** |
| * Gets the class that was used to find the associated TweenAccessor. |
| */ |
| public Class<?> getTargetClass() { |
| return targetClass; |
| } |
| |
| // ------------------------------------------------------------------------- |
| // Overrides |
| // ------------------------------------------------------------------------- |
| |
| @Override |
| public Tween build() { |
| if (target == null) return this; |
| |
| accessor = (TweenAccessor<Object>) registeredAccessors.get(targetClass); |
| if (accessor == null && target instanceof TweenAccessor) accessor = (TweenAccessor<Object>) target; |
| if (accessor != null) combinedAttrsCnt = accessor.getValues(target, type, accessorBuffer); |
| else throw new RuntimeException("No TweenAccessor was found for the target"); |
| |
| if (combinedAttrsCnt > combinedAttrsLimit) throwCombinedAttrsLimitReached(); |
| return this; |
| } |
| |
| @Override |
| public void free() { |
| pool.free(this); |
| } |
| |
| @Override |
| protected void initializeOverride() { |
| if (target == null) return; |
| |
| accessor.getValues(target, type, startValues); |
| |
| for (int i=0; i<combinedAttrsCnt; i++) { |
| targetValues[i] += isRelative ? startValues[i] : 0; |
| |
| for (int ii=0; ii<waypointsCnt; ii++) { |
| waypoints[ii*combinedAttrsCnt+i] += isRelative ? startValues[i] : 0; |
| } |
| |
| if (isFrom) { |
| float tmp = startValues[i]; |
| startValues[i] = targetValues[i]; |
| targetValues[i] = tmp; |
| } |
| } |
| } |
| |
| @Override |
| protected void updateOverride(int step, int lastStep, boolean isIterationStep, float delta) { |
| if (target == null || equation == null) return; |
| |
| // Case iteration end has been reached |
| |
| if (!isIterationStep && step > lastStep) { |
| accessor.setValues(target, type, isReverse(lastStep) ? startValues : targetValues); |
| return; |
| } |
| |
| if (!isIterationStep && step < lastStep) { |
| accessor.setValues(target, type, isReverse(lastStep) ? targetValues : startValues); |
| return; |
| } |
| |
| // Validation |
| |
| assert isIterationStep; |
| assert getCurrentTime() >= 0; |
| assert getCurrentTime() <= duration; |
| |
| // Case duration equals zero |
| |
| if (duration < 0.00000000001f && delta > -0.00000000001f) { |
| accessor.setValues(target, type, isReverse(step) ? targetValues : startValues); |
| return; |
| } |
| |
| if (duration < 0.00000000001f && delta < 0.00000000001f) { |
| accessor.setValues(target, type, isReverse(step) ? startValues : targetValues); |
| return; |
| } |
| |
| // Normal behavior |
| |
| float time = isReverse(step) ? duration - getCurrentTime() : getCurrentTime(); |
| float t = equation.compute(time/duration); |
| |
| if (waypointsCnt == 0 || path == null) { |
| for (int i=0; i<combinedAttrsCnt; i++) { |
| accessorBuffer[i] = startValues[i] + t * (targetValues[i] - startValues[i]); |
| } |
| |
| } else { |
| for (int i=0; i<combinedAttrsCnt; i++) { |
| pathBuffer[0] = startValues[i]; |
| pathBuffer[1+waypointsCnt] = targetValues[i]; |
| for (int ii=0; ii<waypointsCnt; ii++) { |
| pathBuffer[ii+1] = waypoints[ii*combinedAttrsCnt+i]; |
| } |
| |
| accessorBuffer[i] = path.compute(t, pathBuffer, waypointsCnt+2); |
| } |
| } |
| |
| accessor.setValues(target, type, accessorBuffer); |
| } |
| |
| // ------------------------------------------------------------------------- |
| // BaseTween impl. |
| // ------------------------------------------------------------------------- |
| |
| @Override |
| protected void forceStartValues() { |
| if (target == null) return; |
| accessor.setValues(target, type, startValues); |
| } |
| |
| @Override |
| protected void forceEndValues() { |
| if (target == null) return; |
| accessor.setValues(target, type, targetValues); |
| } |
| |
| @Override |
| protected boolean containsTarget(Object target) { |
| return this.target == target; |
| } |
| |
| @Override |
| protected boolean containsTarget(Object target, int tweenType) { |
| return this.target == target && this.type == tweenType; |
| } |
| |
| // ------------------------------------------------------------------------- |
| // Helpers |
| // ------------------------------------------------------------------------- |
| |
| private void throwCombinedAttrsLimitReached() { |
| String msg = "You cannot combine more than " + combinedAttrsLimit + " " |
| + "attributes in a tween. You can raise this limit with " |
| + "Tween.setCombinedAttributesLimit(), which should be called once " |
| + "in application initialization code."; |
| throw new RuntimeException(msg); |
| } |
| |
| private void throwWaypointsLimitReached() { |
| String msg = "You cannot add more than " + waypointsLimit + " " |
| + "waypoints to a tween. You can raise this limit with " |
| + "Tween.setWaypointsLimit(), which should be called once in " |
| + "application initialization code."; |
| throw new RuntimeException(msg); |
| } |
| } |