/src/helpers/AnimationEngine.java
Java | 429 lines | 306 code | 98 blank | 25 comment | 50 complexity | eff726397f6f13dd2afc2b451d978515 MD5 | raw file
- package helpers;
- import interfaces.Animatable;
- import java.awt.event.ActionEvent;
- import java.awt.event.ActionListener;
- import java.util.ArrayList;
- import java.util.Iterator;
- import javax.swing.Timer;
- public class AnimationEngine {
- private AnimationEngineTimer timer;
- private boolean linear = false;
- private boolean quad = false;
- private boolean powerOfN = false;
- private int N = 2;
-
- private boolean easeIn = false;
- private boolean easeOut = false;
- private boolean easeInOut = false;
- public static enum Direction {
- FORWARD, BACKWARD
- }
- private long startTime; //the start time of animation engine
- private long currentStartTime; // time of current animation cycle
- private long pauseStartTime;
- private int repeatNumTimes = 1;
-
- private boolean running = false;
- private boolean shouldStop = false;
- private boolean hasStarted = false;
- private int initialDelay;
- //the animationDuration of animation
- private int animationDuration;
- private int resolution = 20;
- private Direction defaultDirection = Direction.FORWARD;
- private Direction direction;
- //will hold all object that should be called by the animation engine when there's animations to be done
- private ArrayList<Object> animatableTargets = new ArrayList<Object>();
- public AnimationEngine(int duration) {
- this(duration,null);
- }
- /**
- * @param animationDuration, the animationDuration of the base animation
- * @param obj, the target object that will be called by the AnimationEngine when there occur events to be animated
- */
- public AnimationEngine(int duration,Object animatableTarget) {
- this.animationDuration = duration;
- this.linear = true;
- this.easeIn = true;
- addAnimatableTarget(animatableTarget);
- timer = new AnimationEngineTimer();
- }
- public Direction getDefaultDirection() {
- return defaultDirection;
- }
- public void setDefaultDirection(Direction defaultDirection) {
- if(isRunning()){
- throw new IllegalStateException("Could not set the defaultDirection if the Animation Engine is running!");
- }
- this.defaultDirection = defaultDirection;
- }
-
- public int getRepeatNumTimes() {
- return repeatNumTimes;
- }
- public void setRepeatNumTimes(int repeatNumTimes) {
- this.repeatNumTimes = repeatNumTimes;
- }
- public void setLinear() {
- this.linear = true;
- this.powerOfN = false;
- this.quad = false;
- }
- public void setQuad() {
- this.linear = false;
- this.powerOfN = false;
- this.quad = true;
- }
-
- public void setPowerOfN(int n) {
- this.linear = false;
- this.powerOfN = true;
- this.N = n;
- this.quad = false;
- }
- public float quad(float fraction) {
- return (float)Math.pow(fraction,2);
- }
-
- private float powerOfN(float fraction) {
-
- return (float)Math.pow(fraction, N);
- }
- public boolean isEaseIn() {
- return easeIn;
- }
- public void setEaseIn() {
- this.easeOut = false;
- this.easeInOut = false;
- this.easeIn = true;
- }
- public boolean isEaseOut() {
- return easeOut;
- }
- public void setEaseOut() {
- this.easeIn = false;
- this.easeInOut = false;
- this.easeOut = true;
- }
- public boolean isEaseInOut() {
- return easeInOut;
- }
- public void setEaseInOut() {
- this.easeIn = false;
- this.easeOut = false;
- this.easeInOut = true;
- }
- /**
- *
- * @param animatableTarget, the object to be added to the list that is used by the Animation engine to notify when there's a animation/event to be done.
- */
- public synchronized void addAnimatableTarget(Object animatableTarget) {
- if(animatableTarget != null) {
- if(!animatableTargets.contains(animatableTarget)) {// if the target isn't in the list, add it.
- if(animatableTarget instanceof Animatable)
- animatableTargets.add(animatableTarget);
- }
- }
- }
- /**
- *
- * @param animatableTarget, the object to be removed from the list that is used by the Animation engine to notify when there's a animation/event to be done
- */
- public synchronized void removeAnimatableTarget(Object animatableTarget) {
- if(animatableTarget != null) {
- animatableTargets.remove(animatableTarget);
- }
- }
- /**
- *
- * @return, true if the Animation engine is running, false otherwise
- */
- public boolean isRunning() {
- return running;
- }
- /**
- *
- * @return the animationDuration of the animation in milliseconds, it the animationDuration is < 0 then animations will run forever.
- */
- public int getDuration() {
- return animationDuration;
- }
- public void setDuration(int duration) {
- if(isRunning()) {
- throw new IllegalStateException("Could not set the animationDuration if the Animation Engine is running!");
- }
- this.animationDuration = duration;
- }
- public int getResolution() {
- return resolution;
- }
- public void setResolution(int resolution) {
- if(resolution < 0 ) {
- throw new IllegalArgumentException("the resoltion =" +resolution +" which is < 0 and that is not allowed");
- } else if(isRunning()) {
- throw new IllegalStateException("Could not set the resoltion if the Animation Engine is running!");
- }
- this.resolution = resolution;
- timer.setResolution(resolution);
- }
- public int getInitialDelay() {
- return initialDelay;
- }
- public void setInitialDelay(int initialDelay) {
- if(initialDelay < 0 ) {
- throw new IllegalArgumentException("the initialDelay = "+initialDelay+ " which is smaller < 0 and is not allowed!");
- } else if(isRunning()) {
- throw new IllegalStateException("Could not set the resoltion if the Animation Engine is running!");
- }
- this.initialDelay = initialDelay;
- timer.setInitialDelay(initialDelay);
- }
- public void start() {
- if(isRunning()) {
- throw new IllegalStateException("Could not start the Animation Engine if it is already running!");
- }
- running = true;
- direction = defaultDirection;
- startTime = (System.nanoTime() / 1000000) + getInitialDelay();
- currentStartTime = startTime;
- timer.start();
- }
- public void stop() {
- timer.stop();
- end();
- shouldStop = false;
- running = false;
- hasStarted = false;
- }
-
- public void pause() {
- if (isRunning()) {
- pauseStartTime = System.nanoTime();
- running = false;
- timer.stop();
- }
- }
-
- public void resume() {
- if (pauseStartTime > 0) {
- long pause = (System.nanoTime() - pauseStartTime) / 1000000;
- startTime += pause;
- currentStartTime += pause;
- timer.start();
- pauseStartTime = 0;
- running = true;
- }
- }
- public synchronized void begin() {
- Iterator<Object> iter = animatableTargets.iterator();
- while(iter.hasNext()){
- Object animatableTarget = iter.next();
- if(animatableTarget instanceof Animatable) {
- ((Animatable)animatableTarget).begin();
- }
- }
- }
- public synchronized void end() {
- Iterator<Object> iter = animatableTargets.iterator();
- while(iter.hasNext()){
- Object animatableTarget = iter.next();
- if(animatableTarget instanceof Animatable) {
- ((Animatable)animatableTarget).end();
- }
- }
- }
-
- private synchronized void repeat() {
- Iterator<Object> iter = animatableTargets.iterator();
- while(iter.hasNext()){
- Object animatableTarget = iter.next();
- if(animatableTarget instanceof Animatable) {
- ((Animatable)animatableTarget).repeat();
- }
- }
- }
-
- private synchronized void animationEvent(float fraction) {
- Iterator<Object> iter = animatableTargets.iterator();
- while(iter.hasNext()){
- Object animatableTarget = iter.next();
- if(animatableTarget instanceof Animatable) {
- ((Animatable)animatableTarget).animationEvent(fraction);
- }
- }
- if (shouldStop) {
- stop();
- }
- }
- public float getFraction() {
- float fraction;
- long currentTime = System.nanoTime() / 1000000;
- long animationCycleElapsedTime = currentTime - this.currentStartTime;
- int currentCycle =(int) ((currentTime - startTime) / animationDuration);
- //long animationTotElapsedTime = currentTime - startTime;
- //double currentCycle = (double)animationTotElapsedTime / animationDuration;
- if(!hasStarted) {
- begin();
- hasStarted = true;
- }
-
- boolean isCycle = (animationCycleElapsedTime > animationDuration);
-
- if(repeatNumTimes != 1 && (currentCycle < repeatNumTimes) && isCycle ) { // repeat
- long actualCycleTime = animationCycleElapsedTime % animationDuration;
- fraction = (float)actualCycleTime / animationDuration;
- p.print("repeatNumTimes"+repeatNumTimes);
- currentStartTime = currentTime - actualCycleTime;
-
- repeat();
- } else if(animationDuration >= 0 && isCycle) {
- if (direction == Direction.BACKWARD) {
- fraction = 0.0f;
- } else {
- fraction = 1.0f;
- }
- shouldStop = true;
- } else { // in the middle of start and end time
- fraction = 0.0f;
- if(animationDuration >= 0) {
- fraction = (float)animationCycleElapsedTime / animationDuration;
- if(direction == Direction.BACKWARD) {
- fraction = 1.0f-fraction ;
- }
- //make sure that the fraction is between 0 - 1
- fraction = Math.min(fraction, 1.0f);
- fraction = Math.max(fraction, 0.0f);
- }
- }
- if(isEaseOut()){
- if(quad){
- fraction = 1.0f - quad(1- fraction);
- } else if (powerOfN) {
- fraction = 1.0f - powerOfN((1- fraction));
- }
- } else if(isEaseInOut()) {
- if(quad){
- if (fraction <= 0.5) { // the first half of the animation)
- fraction = quad(2 * fraction) / 2;
- } else { // the second half
- fraction = (2 - quad(2 * (1 - fraction))) / 2;
- }
- } else if(powerOfN) {
- if (fraction <= 0.5) {
- fraction = powerOfN(2 * fraction) / 2;
- } else {
- fraction = (2 - powerOfN(2 * (1 - fraction))) / 2;
- }
- }
- }
- return fraction;
- }
- private class AnimationEngineTimer implements ActionListener {
- Timer timer;
- public AnimationEngineTimer () {
- timer = new Timer(resolution,this);
- timer.setInitialDelay(0);
- }
- public void start() {
- timer.start();
- }
- public void stop() {
- timer.stop();
- }
- public void setResolution(int resolution) {
- timer.setDelay(resolution);
- }
- public void setInitialDelay(int delay){
- timer.setInitialDelay(delay);
- }
- @Override
- public void actionPerformed(ActionEvent arg0) {
- animationEvent(getFraction());
- }
- }
- }