interpolate zu animate umbenannt

Animation erbt zur Vereinfachung nun auch von Constants und dort gibt es schon eine interpolate Methode.
This commit is contained in:
ngb
2022-07-25 17:42:06 +02:00
parent 20fe700756
commit ecbe2b4f6b
12 changed files with 260 additions and 73 deletions

View File

@@ -2,15 +2,16 @@ package schule.ngb.zm.anim;
import schule.ngb.zm.Constants;
import schule.ngb.zm.Updatable;
import schule.ngb.zm.util.Validator;
import schule.ngb.zm.util.events.EventDispatcher;
import java.util.function.DoubleUnaryOperator;
public abstract class Animation<T> implements Updatable {
public abstract class Animation<T> extends Constants implements Updatable {
protected int runtime;
protected int elapsed_time = 0;
protected int elapsedTime = 0;
protected boolean running = false, finished = false;
@@ -23,7 +24,7 @@ public abstract class Animation<T> implements Updatable {
public Animation( DoubleUnaryOperator easing ) {
this.runtime = Constants.DEFAULT_ANIM_RUNTIME;
this.easing = easing;
this.easing = Validator.requireNotNull(easing);
}
public Animation( int runtime ) {
@@ -33,7 +34,7 @@ public abstract class Animation<T> implements Updatable {
public Animation( int runtime, DoubleUnaryOperator easing ) {
this.runtime = runtime;
this.easing = easing;
this.easing = Validator.requireNotNull(easing);
}
public int getRuntime() {
@@ -56,17 +57,17 @@ public abstract class Animation<T> implements Updatable {
public final void start() {
this.initialize();
elapsed_time = 0;
elapsedTime = 0;
running = true;
finished = false;
interpolate(easing.applyAsDouble(0.0));
animate(easing.applyAsDouble(0.0));
initializeEventDispatcher().dispatchEvent("start", this);
}
public final void stop() {
running = false;
// Make sure the last animation frame was interpolated correctly
interpolate(easing.applyAsDouble((double) elapsed_time / (double) runtime));
animate(easing.applyAsDouble((double) elapsedTime / (double) runtime));
this.finish();
finished = true;
initializeEventDispatcher().dispatchEvent("stop", this);
@@ -82,11 +83,7 @@ public abstract class Animation<T> implements Updatable {
public final void await() {
while( !finished ) {
try {
Thread.sleep(1);
} catch( InterruptedException ex ) {
// Keep waiting
}
Thread.yield();
}
}
@@ -97,16 +94,16 @@ public abstract class Animation<T> implements Updatable {
@Override
public void update( double delta ) {
elapsed_time += (int) (delta * 1000);
if( elapsed_time > runtime )
elapsed_time = runtime;
elapsedTime += (int) (delta * 1000);
if( elapsedTime > runtime )
elapsedTime = runtime;
double t = (double) elapsed_time / (double) runtime;
double t = (double) elapsedTime / (double) runtime;
if( t >= 1.0 ) {
running = false;
stop();
} else {
interpolate(easing.applyAsDouble(t));
animate(easing.applyAsDouble(t));
}
}
@@ -124,7 +121,7 @@ public abstract class Animation<T> implements Updatable {
* @param e Fortschritt der Animation nachdem die Easingfunktion angewandt
* wurde.
*/
public abstract void interpolate( double e );
public abstract void animate( double e );
EventDispatcher<Animation, AnimationListener> eventDispatcher;

View File

@@ -19,8 +19,8 @@ public class AnimationFacade<S> extends Animation<S> {
}
@Override
public void interpolate( double e ) {
anim.interpolate(e);
public void animate( double e ) {
anim.animate(e);
}
@Override

View File

@@ -1,76 +1,116 @@
package schule.ngb.zm.anim;
import schule.ngb.zm.shapes.Shape;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
import java.util.function.DoubleUnaryOperator;
public class AnimationGroup extends Animation<Shape> {
@SuppressWarnings( "unused" )
public class AnimationGroup<T> extends Animation<T> {
Animation<? extends Shape>[] anims;
private boolean overrideRuntime = false;
List<Animation<T>> anims;
public AnimationGroup( DoubleUnaryOperator easing, Animation<? extends Shape>... anims ) {
super(easing);
this.anims = anims;
private boolean overrideEasing = false;
int maxRuntime = Arrays.stream(this.anims).mapToInt((a) -> a.getRuntime()).reduce(0, Integer::max);
setRuntime(maxRuntime);
private int overrideRuntime = -1;
private int lag = 0;
private int active = 0;
public AnimationGroup( Collection<Animation<T>> anims ) {
this(0, -1, null, anims);
}
public AnimationGroup( int runtime, DoubleUnaryOperator easing, Animation<? extends Shape>... anims ) {
super(runtime, easing);
this.anims = anims;
overrideRuntime = true;
public AnimationGroup( int lag, Collection<Animation<T>> anims ) {
this(lag, -1, null, anims);
}
public AnimationGroup( DoubleUnaryOperator easing, Collection<Animation<T>> anims ) {
this(0, -1, easing, anims);
}
public AnimationGroup( int lag, DoubleUnaryOperator easing, Collection<Animation<T>> anims ) {
this(lag, -1, easing, anims);
}
public AnimationGroup( int lag, int runtime, DoubleUnaryOperator easing, Collection<Animation<T>> anims ) {
super();
this.anims = List.copyOf(anims);
this.lag = lag;
if( easing != null ) {
this.easing = easing;
overrideEasing = true;
}
if( runtime > 0 ) {
this.runtime = anims.size() * lag + runtime;
this.overrideRuntime = runtime;
} else {
this.runtime = 0;
for( int i = 0; i < this.anims.size(); i++ ) {
if( i * lag + this.anims.get(i).getRuntime() > this.runtime ) {
this.runtime = i * lag + this.anims.get(i).getRuntime();
}
}
}
}
@Override
public Shape getAnimationTarget() {
return null;
public T getAnimationTarget() {
for( Animation<T> anim : anims ) {
if( anim.isActive() ) {
return anim.getAnimationTarget();
}
}
return anims.get(anims.size() - 1).getAnimationTarget();
}
@Override
public void update( double delta ) {
if( overrideRuntime ) {
synchronized( anims ) {
for( Animation<? extends Shape> anim: anims ) {
if( anim.isActive() ) {
anim.update(delta);
elapsedTime += (int) (delta * 1000);
// Animation is done. Stop all Animations.
if( elapsedTime > runtime ) {
for( int i = 0; i < anims.size(); i++ ) {
if( anims.get(i).isActive() ) {
anims.get(i).elapsedTime = anims.get(i).runtime;
anims.get(i).stop();
}
}
running = false;
this.stop();
}
while( active < anims.size() && elapsedTime >= active * lag ) {
anims.get(active).start();
active += 1;
}
for( int i = 0; i < active; i++ ) {
double t = 0.0;
if( overrideRuntime > 0 ) {
t = (double) (elapsedTime - i*lag) / (double) overrideRuntime;
} else {
super.update(delta);
}
t = (double) (elapsedTime - i*lag) / (double) anims.get(i).getRuntime();
}
@Override
public void interpolate( double e ) {
synchronized( anims ) {
for( Animation<? extends Shape> anim: anims ) {
anim.interpolate(e);
if( t >= 1.0 ) {
anims.get(i).elapsedTime = anims.get(i).runtime;
anims.get(i).stop();
} else {
double e = overrideEasing ?
easing.applyAsDouble(t) :
anims.get(i).easing.applyAsDouble(t);
anims.get(i).animate(e);
}
}
}
@Override
public void initialize() {
synchronized( anims ) {
for( Animation<? extends Shape> anim: anims ) {
anim.initialize();
}
}
}
@Override
public void finish() {
synchronized( anims ) {
for( Animation<? extends Shape> anim: anims ) {
anim.finish();
}
}
public void animate( double e ) {
}
}

View File

@@ -0,0 +1,39 @@
package schule.ngb.zm.anim;
import schule.ngb.zm.Constants;
import schule.ngb.zm.Vector;
import schule.ngb.zm.shapes.Shape;
import java.util.function.DoubleUnaryOperator;
public class CircleAnimation extends Animation<Shape> {
private Shape object;
private double centerx, centery, radius, startangle;
public CircleAnimation( Shape target, double cx, double cy, int runtime, DoubleUnaryOperator easing ) {
super(runtime, easing);
object = target;
centerx = cx;
centery = cy;
Vector vec = new Vector(target.getX(), target.getY()).sub(cx, cy);
startangle = vec.heading();
radius = vec.length();
}
@Override
public Shape getAnimationTarget() {
return object;
}
@Override
public void animate( double e ) {
double angle = startangle + Constants.radians(Constants.interpolate(0, 360, e));
double x = centerx + radius * Constants.cos(angle);
double y = centery + radius * Constants.sin(angle);
object.moveTo(x, y);
}
}

View File

@@ -0,0 +1,74 @@
package schule.ngb.zm.anim;
@SuppressWarnings( "unused" )
public class ContinousAnimation<T> extends Animation<T> {
private final Animation<T> baseAnimation;
private int lag = 0;
/**
* Speichert eine Approximation der aktuellen Steigung der Easing-Funktion,
* um im Fall {@code easeInOnly == true} nach dem ersten Durchlauf die
* passende Geschwindigkeit beizubehalten.
*/
private double m = 1.0, lastEase = 0.0;
private boolean easeInOnly = false;
public ContinousAnimation( Animation<T> baseAnimation ) {
this(baseAnimation, 0, false);
}
public ContinousAnimation( Animation<T> baseAnimation, int lag ) {
this(baseAnimation, lag, false);
}
public ContinousAnimation( Animation<T> baseAnimation, boolean easeInOnly ) {
this(baseAnimation, 0, easeInOnly);
}
private ContinousAnimation( Animation<T> baseAnimation, int lag, boolean easeInOnly ) {
super(baseAnimation.getRuntime(), baseAnimation.getEasing());
this.baseAnimation = baseAnimation;
this.lag = lag;
this.easeInOnly = easeInOnly;
}
@Override
public T getAnimationTarget() {
return baseAnimation.getAnimationTarget();
}
@Override
public void update( double delta ) {
elapsedTime += (int) (delta * 1000);
if( elapsedTime >= runtime + lag ) {
elapsedTime %= (runtime + lag);
if( easeInOnly && easing != null ) {
easing = null;
// runtime = (int)((1.0/m)*(runtime + lag));
}
}
double t = (double) elapsedTime / (double) runtime;
if( t >= 1.0 ) {
t = 1.0;
}
if( easing != null ) {
double e = easing.applyAsDouble(t);
animate(e);
m = (e-lastEase)/(delta*1000/(asDouble(runtime)));
lastEase = e;
} else {
animate(t);
}
}
@Override
public void animate( double e ) {
baseAnimation.animate(e);
}
}

View File

@@ -36,7 +36,7 @@ public class FadeAnimation extends Animation<Shape> {
}
@Override
public void interpolate( double e ) {
public void animate( double e ) {
object.setFillColor(new Color(fill, (int) Constants.interpolate(fillAlpha, tAlpha, e)));
object.setStrokeColor(new Color(stroke, (int) Constants.interpolate(strokeAlpha, tAlpha, e)));
}

View File

@@ -26,7 +26,7 @@ public class FillAnimation extends Animation<Shape> {
}
@Override
public void interpolate( double e ) {
public void animate( double e ) {
object.setFillColor(Color.interpolate(oFill, tFill, e));
}

View File

@@ -27,7 +27,7 @@ public class MorphAnimation extends Animation<Shape> {
}
@Override
public void interpolate( double e ) {
public void animate( double e ) {
object.setX(Constants.interpolate(original.getX(), target.getX(), e));
object.setY(Constants.interpolate(original.getY(), target.getY(), e));
object.setFillColor(Color.interpolate(original.getFillColor(), target.getFillColor(), e));

View File

@@ -31,7 +31,7 @@ public class MoveAnimation extends Animation<Shape> {
}
@Override
public void interpolate( double e ) {
public void animate( double e ) {
object.setX(Constants.interpolate(oX, tX, e));
object.setY(Constants.interpolate(oY, tY, e));
}

View File

@@ -25,7 +25,7 @@ public class RotateAnimation extends Animation<Shape> {
}
@Override
public void interpolate( double e ) {
public void animate( double e ) {
object.rotateTo(Constants.interpolate(oA, tA, e));
}

View File

@@ -25,7 +25,7 @@ public class StrokeAnimation extends Animation<Shape> {
}
@Override
public void interpolate( double e ) {
public void animate( double e ) {
object.setStrokeColor(Color.interpolate(oFill, tFill, e));
}

View File

@@ -0,0 +1,37 @@
package schule.ngb.zm.anim;
import schule.ngb.zm.Constants;
import schule.ngb.zm.Options;
import schule.ngb.zm.shapes.Shape;
import java.util.function.DoubleUnaryOperator;
public class WaveAnimation extends Animation<Shape> {
private Shape object;
private double strength, sinOffset, previousDelta = 0.0;
private Options.Direction dir;
public WaveAnimation( Shape target, double strength, Options.Direction dir, double sinOffset, int runtime, DoubleUnaryOperator easing ) {
super(runtime, easing);
this.object = target;
this.dir = dir;
this.strength = strength;
this.sinOffset = sinOffset;
}
@Override
public Shape getAnimationTarget() {
return object;
}
@Override
public void animate( double e ) {
double delta = this.strength * Constants.sin(Constants.interpolate(0.0, Constants.TWO_PI, e) + sinOffset);
object.move((delta - previousDelta) * dir.x, (delta - previousDelta) * dir.y);
previousDelta = delta;
}
}