You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
458 lines
7.8 KiB
458 lines
7.8 KiB
package mightypork.gamecore.util.math.timing.animation;
|
|
|
|
|
|
import mightypork.dynmath.num.mutable.NumMutable;
|
|
import mightypork.gamecore.util.math.Calc;
|
|
import mightypork.gamecore.util.math.Easing;
|
|
import mightypork.gamecore.util.math.timing.Pauseable;
|
|
import mightypork.gamecore.util.math.timing.Updateable;
|
|
|
|
|
|
/**
|
|
* Double which supports delta timing.<br>
|
|
* When both in and out easings are set differently, then they'll be used for
|
|
* fade-in and fade-out respectively. Otherwise both use the same.
|
|
*
|
|
* @author Ondřej Hruška (MightyPork)
|
|
*/
|
|
public class NumAnimated extends NumMutable implements Updateable, Pauseable {
|
|
|
|
/** target double */
|
|
protected double to = 0;
|
|
|
|
/** last tick double */
|
|
protected double from = 0;
|
|
|
|
/** how long the transition should last */
|
|
protected double duration = 0;
|
|
|
|
/** current anim time */
|
|
protected double elapsedTime = 0;
|
|
|
|
/** True if this animator is paused */
|
|
protected boolean paused = false;
|
|
|
|
/** Easing fn */
|
|
protected Easing easingCurrent = Easing.LINEAR;
|
|
protected Easing easingOut = Easing.LINEAR;
|
|
protected Easing easingIn = Easing.LINEAR;
|
|
|
|
/** Default duration (seconds) */
|
|
private double defaultDuration = 1;
|
|
|
|
|
|
/**
|
|
* With linear easing
|
|
*
|
|
* @param value initial value
|
|
*/
|
|
public NumAnimated(double value)
|
|
{
|
|
setTo(value);
|
|
}
|
|
|
|
|
|
/**
|
|
* Create animator with easing
|
|
*
|
|
* @param value initial value
|
|
* @param easing easing function
|
|
*/
|
|
public NumAnimated(double value, Easing easing)
|
|
{
|
|
this(value);
|
|
setEasing(easing);
|
|
}
|
|
|
|
|
|
/**
|
|
* Create animator with easing
|
|
*
|
|
* @param value initial value
|
|
* @param easingIn easing function (fade in)
|
|
* @param easingOut easing function (fade out)
|
|
*/
|
|
public NumAnimated(double value, Easing easingIn, Easing easingOut)
|
|
{
|
|
this(value);
|
|
setEasing(easingIn, easingOut);
|
|
}
|
|
|
|
|
|
/**
|
|
* Create animator with easing
|
|
*
|
|
* @param value initial value
|
|
* @param easing easing function
|
|
* @param defaultDuration default fade duration
|
|
*/
|
|
public NumAnimated(double value, Easing easing, double defaultDuration)
|
|
{
|
|
this(value);
|
|
setEasing(easing);
|
|
setDefaultDuration(defaultDuration);
|
|
}
|
|
|
|
|
|
/**
|
|
* Create animator with easing
|
|
*
|
|
* @param value initial value
|
|
* @param easingIn easing function (fade in)
|
|
* @param easingOut easing function (fade out)
|
|
* @param defaultDuration default fade duration
|
|
*/
|
|
public NumAnimated(double value, Easing easingIn, Easing easingOut, double defaultDuration)
|
|
{
|
|
this(value);
|
|
setEasing(easingIn, easingOut);
|
|
setDefaultDuration(defaultDuration);
|
|
}
|
|
|
|
|
|
/**
|
|
* Create as copy of another
|
|
*
|
|
* @param other other animator
|
|
*/
|
|
public NumAnimated(NumAnimated other)
|
|
{
|
|
setTo(other);
|
|
}
|
|
|
|
|
|
/**
|
|
* @param easing easing function
|
|
*/
|
|
public void setEasing(Easing easing)
|
|
{
|
|
this.easingCurrent = this.easingIn = this.easingOut = easing;
|
|
}
|
|
|
|
|
|
/**
|
|
* @param easingIn easing for fade in
|
|
* @param easingOut easing for fade out
|
|
*/
|
|
public void setEasing(Easing easingIn, Easing easingOut)
|
|
{
|
|
this.easingIn = easingIn;
|
|
this.easingOut = easingOut;
|
|
this.easingCurrent = easingIn;
|
|
}
|
|
|
|
|
|
/**
|
|
* Get start value
|
|
*
|
|
* @return number
|
|
*/
|
|
public double getStart()
|
|
{
|
|
return from;
|
|
}
|
|
|
|
|
|
/**
|
|
* Get end value
|
|
*
|
|
* @return number
|
|
*/
|
|
public double getEnd()
|
|
{
|
|
return to;
|
|
}
|
|
|
|
|
|
/**
|
|
* @return current animation duration (seconds)
|
|
*/
|
|
public double getDuration()
|
|
{
|
|
return duration;
|
|
}
|
|
|
|
|
|
/**
|
|
* @return elapsed time in current animation (seconds)
|
|
*/
|
|
public double getElapsed()
|
|
{
|
|
return elapsedTime;
|
|
}
|
|
|
|
|
|
/**
|
|
* @return default animation duration (seconds)
|
|
*/
|
|
public double getDefaultDuration()
|
|
{
|
|
return defaultDuration;
|
|
}
|
|
|
|
|
|
/**
|
|
* @param defaultDuration default animation duration (seconds)
|
|
*/
|
|
public void setDefaultDuration(double defaultDuration)
|
|
{
|
|
this.defaultDuration = defaultDuration;
|
|
}
|
|
|
|
|
|
/**
|
|
* Get value at delta time
|
|
*
|
|
* @return the value
|
|
*/
|
|
@Override
|
|
public double value()
|
|
{
|
|
if (duration == 0) return to;
|
|
return Calc.interpolate(from, to, (elapsedTime / duration), easingCurrent);
|
|
}
|
|
|
|
|
|
/**
|
|
* Get how much of the animation is already finished
|
|
*
|
|
* @return completion ratio (0 to 1)
|
|
*/
|
|
public double getProgress()
|
|
{
|
|
if (duration == 0) return 1;
|
|
return elapsedTime / duration;
|
|
}
|
|
|
|
|
|
@Override
|
|
public void update(double delta)
|
|
{
|
|
if (paused || isFinished()) return;
|
|
|
|
elapsedTime = Calc.clamp(elapsedTime + delta, 0, duration);
|
|
if (isFinished()) {
|
|
duration = 0;
|
|
elapsedTime = 0;
|
|
from = to;
|
|
}
|
|
}
|
|
|
|
|
|
/**
|
|
* Get if animation is finished
|
|
*
|
|
* @return is finished
|
|
*/
|
|
public boolean isFinished()
|
|
{
|
|
return duration == 0 || elapsedTime >= duration;
|
|
}
|
|
|
|
|
|
/**
|
|
* Set to a value (without animation)
|
|
*
|
|
* @param value
|
|
*/
|
|
@Override
|
|
public void setTo(double value)
|
|
{
|
|
from = to = value;
|
|
elapsedTime = 0;
|
|
duration = 0;
|
|
}
|
|
|
|
|
|
/**
|
|
* Copy other
|
|
*
|
|
* @param other
|
|
*/
|
|
public void setTo(NumAnimated other)
|
|
{
|
|
this.from = other.from;
|
|
this.to = other.to;
|
|
this.duration = other.duration;
|
|
this.elapsedTime = other.elapsedTime;
|
|
this.paused = other.paused;
|
|
this.easingCurrent = other.easingCurrent;
|
|
this.easingIn = other.easingIn;
|
|
this.easingOut = other.easingOut;
|
|
this.defaultDuration = other.defaultDuration;
|
|
}
|
|
|
|
|
|
/**
|
|
* Animate between two states, start from current value (if it's in between)
|
|
*
|
|
* @param from start value
|
|
* @param to target state
|
|
* @param time animation time (secs)
|
|
*/
|
|
public void animate(double from, double to, double time)
|
|
{
|
|
final double current = value();
|
|
|
|
this.from = from;
|
|
this.to = to;
|
|
|
|
final double progress = getProgressFromValue(current);
|
|
|
|
this.from = (progress > 0 ? current : from);
|
|
|
|
this.duration = time * (1 - progress);
|
|
this.elapsedTime = 0;
|
|
}
|
|
|
|
|
|
/**
|
|
* Get progress already elapsed based on current value.<br>
|
|
* Used to resume animation from current point in fading etc.
|
|
*
|
|
* @param value current value
|
|
* @return progress ratio 0-1
|
|
*/
|
|
protected double getProgressFromValue(double value)
|
|
{
|
|
double p = 0;
|
|
|
|
if (from == to) return 0;
|
|
|
|
if (value >= from && value <= to) { // up
|
|
p = ((value - from) / (to - from));
|
|
} else if (value >= to && value <= from) { // down
|
|
p = ((from - value) / (from - to));
|
|
}
|
|
|
|
return p;
|
|
}
|
|
|
|
|
|
/**
|
|
* Animate to a value from current value
|
|
*
|
|
* @param to target state
|
|
* @param duration animation duration (speeds)
|
|
*/
|
|
public void animate(double to, double duration)
|
|
{
|
|
this.from = value();
|
|
this.to = to;
|
|
this.duration = duration;
|
|
this.elapsedTime = 0;
|
|
}
|
|
|
|
|
|
/**
|
|
* Animate 0 to 1
|
|
*
|
|
* @param time animation time (secs)
|
|
*/
|
|
public void fadeIn(double time)
|
|
{
|
|
easingCurrent = easingIn;
|
|
animate(0, 1, time);
|
|
}
|
|
|
|
|
|
/**
|
|
* Animate 1 to 0
|
|
*
|
|
* @param time animation time (secs)
|
|
*/
|
|
public void fadeOut(double time)
|
|
{
|
|
easingCurrent = easingOut;
|
|
animate(1, 0, time);
|
|
}
|
|
|
|
|
|
/**
|
|
* Animate 0 to 1 with default duration
|
|
*/
|
|
public void fadeIn()
|
|
{
|
|
easingCurrent = easingIn;
|
|
animate(0, 1, defaultDuration);
|
|
}
|
|
|
|
|
|
/**
|
|
* Animate 1 to 0 with default duration
|
|
*/
|
|
public void fadeOut()
|
|
{
|
|
easingCurrent = easingOut;
|
|
animate(1, 0, defaultDuration);
|
|
}
|
|
|
|
|
|
/**
|
|
* Make a copy
|
|
*
|
|
* @return copy
|
|
*/
|
|
@Override
|
|
public NumAnimated clone()
|
|
{
|
|
return new NumAnimated(this);
|
|
}
|
|
|
|
|
|
@Override
|
|
public String toString()
|
|
{
|
|
return "Animation(" + from + " -> " + to + ", t=" + duration + "s, elapsed=" + elapsedTime + "s)";
|
|
}
|
|
|
|
|
|
/**
|
|
* Set to zero and stop animation
|
|
*/
|
|
public void clear()
|
|
{
|
|
from = to = 0;
|
|
elapsedTime = 0;
|
|
duration = 0;
|
|
paused = false;
|
|
}
|
|
|
|
|
|
/**
|
|
* Stop animation, keep current value
|
|
*/
|
|
public void stop()
|
|
{
|
|
from = to = value();
|
|
elapsedTime = 0;
|
|
duration = 0;
|
|
}
|
|
|
|
|
|
@Override
|
|
public void pause()
|
|
{
|
|
paused = true;
|
|
}
|
|
|
|
|
|
@Override
|
|
public void resume()
|
|
{
|
|
paused = false;
|
|
}
|
|
|
|
|
|
@Override
|
|
public boolean isPaused()
|
|
{
|
|
return paused;
|
|
}
|
|
|
|
|
|
public boolean isInProgress()
|
|
{
|
|
return !isFinished() && !isPaused();
|
|
}
|
|
}
|
|
|