• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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. */
Animation(float frameDuration, Array<? extends TextureRegion> keyFrames)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. */
Animation(float frameDuration, Array<? extends TextureRegion> keyFrames, PlayMode playMode)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. */
Animation(float frameDuration, TextureRegion... keyFrames)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. */
getKeyFrame(float stateTime, boolean looping)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. */
getKeyFrame(float stateTime)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 */
getKeyFrameIndex(float stateTime)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 */
getKeyFrames()173 	public TextureRegion[] getKeyFrames () {
174 		return keyFrames;
175 	}
176 
177 	/** Returns the animation play mode. */
getPlayMode()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. */
setPlayMode(PlayMode playMode)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. */
isAnimationFinished(float stateTime)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 */
setFrameDuration(float frameDuration)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 */
getFrameDuration()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 */
getAnimationDuration()210 	public float getAnimationDuration () {
211 		return animationDuration;
212 	}
213 }
214