Home | History | Annotate | Download | only in g2d
      1 /*******************************************************************************
      2  * Copyright 2011 See AUTHORS file.
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *   http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  ******************************************************************************/
     16 
     17 package com.badlogic.gdx.graphics.g2d;
     18 
     19 import com.badlogic.gdx.math.MathUtils;
     20 import com.badlogic.gdx.utils.Array;
     21 
     22 /** <p>
     23  * An Animation stores a list of {@link TextureRegion}s representing an animated sequence, e.g. for running or jumping. Each
     24  * region of an Animation is called a key frame, multiple key frames make up the animation.
     25  * </p>
     26  *
     27  * @author mzechner */
     28 public class Animation {
     29 
     30 	/** Defines possible playback modes for an {@link Animation}. */
     31 	public enum PlayMode {
     32 		NORMAL,
     33 		REVERSED,
     34 		LOOP,
     35 		LOOP_REVERSED,
     36 		LOOP_PINGPONG,
     37 		LOOP_RANDOM,
     38 	}
     39 
     40 	final TextureRegion[] keyFrames;
     41 	private float frameDuration;
     42 	private float animationDuration;
     43 	private int lastFrameNumber;
     44 	private float lastStateTime;
     45 
     46 	private PlayMode playMode = PlayMode.NORMAL;
     47 
     48 	/** Constructor, storing the frame duration and key frames.
     49 	 *
     50 	 * @param frameDuration the time between frames in seconds.
     51 	 * @param keyFrames the {@link TextureRegion}s representing the frames. */
     52 	public Animation (float frameDuration, Array<? extends TextureRegion> keyFrames) {
     53 		this.frameDuration = frameDuration;
     54 		this.animationDuration = keyFrames.size * frameDuration;
     55 		this.keyFrames = new TextureRegion[keyFrames.size];
     56 		for (int i = 0, n = keyFrames.size; i < n; i++) {
     57 			this.keyFrames[i] = keyFrames.get(i);
     58 		}
     59 
     60 		this.playMode = PlayMode.NORMAL;
     61 	}
     62 
     63 	/** Constructor, storing the frame duration, key frames and play type.
     64 	 *
     65 	 * @param frameDuration the time between frames in seconds.
     66 	 * @param keyFrames the {@link TextureRegion}s representing the frames.
     67 	 * @param playMode the animation playback mode. */
     68 	public Animation (float frameDuration, Array<? extends TextureRegion> keyFrames, PlayMode playMode) {
     69 
     70 		this.frameDuration = frameDuration;
     71 		this.animationDuration = keyFrames.size * frameDuration;
     72 		this.keyFrames = new TextureRegion[keyFrames.size];
     73 		for (int i = 0, n = keyFrames.size; i < n; i++) {
     74 			this.keyFrames[i] = keyFrames.get(i);
     75 		}
     76 
     77 		this.playMode = playMode;
     78 	}
     79 
     80 	/** Constructor, storing the frame duration and key frames.
     81 	 *
     82 	 * @param frameDuration the time between frames in seconds.
     83 	 * @param keyFrames the {@link TextureRegion}s representing the frames. */
     84 	public Animation (float frameDuration, TextureRegion... keyFrames) {
     85 		this.frameDuration = frameDuration;
     86 		this.animationDuration = keyFrames.length * frameDuration;
     87 		this.keyFrames = keyFrames;
     88 		this.playMode = PlayMode.NORMAL;
     89 	}
     90 
     91 	/** Returns a {@link TextureRegion} based on the so called state time. This is the amount of seconds an object has spent in the
     92 	 * state this Animation instance represents, e.g. running, jumping and so on. The mode specifies whether the animation is
     93 	 * looping or not.
     94 	 *
     95 	 * @param stateTime the time spent in the state represented by this animation.
     96 	 * @param looping whether the animation is looping or not.
     97 	 * @return the TextureRegion representing the frame of animation for the given state time. */
     98 	public TextureRegion getKeyFrame (float stateTime, boolean looping) {
     99 		// we set the play mode by overriding the previous mode based on looping
    100 		// parameter value
    101 		PlayMode oldPlayMode = playMode;
    102 		if (looping && (playMode == PlayMode.NORMAL || playMode == PlayMode.REVERSED)) {
    103 			if (playMode == PlayMode.NORMAL)
    104 				playMode = PlayMode.LOOP;
    105 			else
    106 				playMode = PlayMode.LOOP_REVERSED;
    107 		} else if (!looping && !(playMode == PlayMode.NORMAL || playMode == PlayMode.REVERSED)) {
    108 			if (playMode == PlayMode.LOOP_REVERSED)
    109 				playMode = PlayMode.REVERSED;
    110 			else
    111 				playMode = PlayMode.LOOP;
    112 		}
    113 
    114 		TextureRegion frame = getKeyFrame(stateTime);
    115 		playMode = oldPlayMode;
    116 		return frame;
    117 	}
    118 
    119 	/** Returns a {@link TextureRegion} based on the so called state time. This is the amount of seconds an object has spent in the
    120 	 * state this Animation instance represents, e.g. running, jumping and so on using the mode specified by
    121 	 * {@link #setPlayMode(PlayMode)} method.
    122 	 *
    123 	 * @param stateTime
    124 	 * @return the TextureRegion representing the frame of animation for the given state time. */
    125 	public TextureRegion getKeyFrame (float stateTime) {
    126 		int frameNumber = getKeyFrameIndex(stateTime);
    127 		return keyFrames[frameNumber];
    128 	}
    129 
    130 	/** Returns the current frame number.
    131 	 * @param stateTime
    132 	 * @return current frame number */
    133 	public int getKeyFrameIndex (float stateTime) {
    134 		if (keyFrames.length == 1) return 0;
    135 
    136 		int frameNumber = (int)(stateTime / frameDuration);
    137 		switch (playMode) {
    138 		case NORMAL:
    139 			frameNumber = Math.min(keyFrames.length - 1, frameNumber);
    140 			break;
    141 		case LOOP:
    142 			frameNumber = frameNumber % keyFrames.length;
    143 			break;
    144 		case LOOP_PINGPONG:
    145 			frameNumber = frameNumber % ((keyFrames.length * 2) - 2);
    146 			if (frameNumber >= keyFrames.length) frameNumber = keyFrames.length - 2 - (frameNumber - keyFrames.length);
    147 			break;
    148 		case LOOP_RANDOM:
    149 			int lastFrameNumber = (int) ((lastStateTime) / frameDuration);
    150 			if (lastFrameNumber != frameNumber) {
    151 				frameNumber = MathUtils.random(keyFrames.length - 1);
    152 			} else {
    153 				frameNumber = this.lastFrameNumber;
    154 			}
    155 			break;
    156 		case REVERSED:
    157 			frameNumber = Math.max(keyFrames.length - frameNumber - 1, 0);
    158 			break;
    159 		case LOOP_REVERSED:
    160 			frameNumber = frameNumber % keyFrames.length;
    161 			frameNumber = keyFrames.length - frameNumber - 1;
    162 			break;
    163 		}
    164 
    165 		lastFrameNumber = frameNumber;
    166 		lastStateTime = stateTime;
    167 
    168 		return frameNumber;
    169 	}
    170 
    171 	/** Returns the keyFrames[] array where all the TextureRegions of the animation are stored.
    172 	 * @return keyFrames[] field */
    173 	public TextureRegion[] getKeyFrames () {
    174 		return keyFrames;
    175 	}
    176 
    177 	/** Returns the animation play mode. */
    178 	public PlayMode getPlayMode () {
    179 		return playMode;
    180 	}
    181 
    182 	/** Sets the animation play mode.
    183 	 *
    184 	 * @param playMode The animation {@link PlayMode} to use. */
    185 	public void setPlayMode (PlayMode playMode) {
    186 		this.playMode = playMode;
    187 	}
    188 
    189 	/** Whether the animation would be finished if played without looping (PlayMode#NORMAL), given the state time.
    190 	 * @param stateTime
    191 	 * @return whether the animation is finished. */
    192 	public boolean isAnimationFinished (float stateTime) {
    193 		int frameNumber = (int)(stateTime / frameDuration);
    194 		return keyFrames.length - 1 < frameNumber;
    195 	}
    196 
    197 	/** Sets duration a frame will be displayed.
    198 	 * @param frameDuration in seconds */
    199 	public void setFrameDuration (float frameDuration) {
    200 		this.frameDuration = frameDuration;
    201 		this.animationDuration = keyFrames.length * frameDuration;
    202 	}
    203 
    204 	/** @return the duration of a frame in seconds */
    205 	public float getFrameDuration () {
    206 		return frameDuration;
    207 	}
    208 
    209 	/** @return the duration of the entire animation, number of frames times frame duration, in seconds */
    210 	public float getAnimationDuration () {
    211 		return animationDuration;
    212 	}
    213 }
    214