/******************************************************************************* * Copyright 2011 See AUTHORS file. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the * specific language governing permissions and limitations under the License. ******************************************************************************/ package com.badlogic.gdx.graphics.g2d; import com.badlogic.gdx.math.MathUtils; import com.badlogic.gdx.utils.Array; /** * <p> * An Animation stores a list of {@link TextureRegion}s representing an animated sequence, e.g. for running or jumping. * Each region of an Animation is called a key frame, multiple key frames make up the animation. * </p> * * @author mzechner */ public class Animation { public static final int NORMAL = 0; public static final int REVERSED = 1; public static final int LOOP = 2; public static final int LOOP_REVERSED = 3; public static final int LOOP_PINGPONG = 4; public static final int LOOP_RANDOM = 5; final TextureRegion[] keyFrames; public final float frameDuration; public final float animationDuration; private int playMode = NORMAL; /** * Constructor, storing the frame duration and key frames. * * @param frameDuration * the time between frames in seconds. * @param keyFrames * the {@link TextureRegion}s representing the frames. */ public Animation(float frameDuration, Array<? extends TextureRegion> keyFrames) { this.frameDuration = frameDuration; this.animationDuration = keyFrames.size * frameDuration; this.keyFrames = new TextureRegion[keyFrames.size]; for (int i = 0, n = keyFrames.size; i < n; i++) { this.keyFrames[i] = keyFrames.get(i); } this.playMode = NORMAL; } /** * Constructor, storing the frame duration, key frames and play type. * * @param frameDuration * the time between frames in seconds. * @param keyFrames * the {@link TextureRegion}s representing the frames. * @param playType * the type of animation play (NORMAL, REVERSED, LOOP, LOOP_REVERSED, LOOP_PINGPONG, LOOP_RANDOM) */ public Animation(float frameDuration, Array<? extends TextureRegion> keyFrames, int playType) { this.frameDuration = frameDuration; this.animationDuration = keyFrames.size * frameDuration; this.keyFrames = new TextureRegion[keyFrames.size]; for (int i = 0, n = keyFrames.size; i < n; i++) { this.keyFrames[i] = keyFrames.get(i); } this.playMode = playType; } /** * Constructor, storing the frame duration and key frames. * * @param frameDuration * the time between frames in seconds. * @param keyFrames * the {@link TextureRegion}s representing the frames. */ public Animation(float frameDuration, TextureRegion... keyFrames) { this.frameDuration = frameDuration; this.animationDuration = keyFrames.length * frameDuration; this.keyFrames = keyFrames; this.playMode = NORMAL; } /** * Returns a {@link TextureRegion} based on the so called state time. This is the amount of seconds an object has * spent in the state this Animation instance represents, e.g. running, jumping and so on. The mode specifies * whether the animation is looping or not. * * @param stateTime * the time spent in the state represented by this animation. * @param looping * whether the animation is looping or not. * @return the TextureRegion representing the frame of animation for the given state time. */ public TextureRegion getKeyFrame(float stateTime, boolean looping) { // we set the play mode by overriding the previous mode based on looping // parameter value if (looping && (playMode == NORMAL || playMode == REVERSED)) { if (playMode == NORMAL) playMode = LOOP; else playMode = LOOP_REVERSED; } else if (!looping && !(playMode == NORMAL || playMode == REVERSED)) { if (playMode == LOOP_REVERSED) playMode = REVERSED; else playMode = LOOP; } return getKeyFrame(stateTime); } /** * Returns a {@link TextureRegion} based on the so called state time. This is the amount of seconds an object has * spent in the state this Animation instance represents, e.g. running, jumping and so on using the mode specified * by {@link #setPlayMode(int)} method. * * @param stateTime * @return the TextureRegion representing the frame of animation for the given state time. */ public TextureRegion getKeyFrame(float stateTime) { int frameNumber = getKeyFrameIndex(stateTime); return keyFrames[frameNumber]; } /** * Returns the current frame number. * * @param stateTime * @return current frame number */ public int getKeyFrameIndex(float stateTime) { int frameNumber = (int) (stateTime / frameDuration); if (keyFrames.length == 1) return 0; switch (playMode) { case NORMAL: frameNumber = Math.min(keyFrames.length - 1, frameNumber); break; case LOOP: frameNumber = frameNumber % keyFrames.length; break; case LOOP_PINGPONG: frameNumber = frameNumber % ((keyFrames.length * 2) - 2); if (frameNumber >= keyFrames.length) frameNumber = keyFrames.length - 2 - (frameNumber - keyFrames.length); break; case LOOP_RANDOM: frameNumber = MathUtils.random(keyFrames.length - 1); break; case REVERSED: frameNumber = Math.max(keyFrames.length - frameNumber - 1, 0); break; case LOOP_REVERSED: frameNumber = frameNumber % keyFrames.length; frameNumber = keyFrames.length - frameNumber - 1; break; default: // play normal otherwise frameNumber = Math.min(keyFrames.length - 1, frameNumber); break; } return frameNumber; } /** * Sets the animation play mode. * * @param playMode * can be one of the following: Animation.NORMAL, Animation.REVERSED, Animation.LOOP, * Animation.LOOP_REVERSED, Animation.LOOP_PINGPONG, Animation.LOOP_RANDOM */ public void setPlayMode(int playMode) { this.playMode = playMode; } /** * Whether the animation would be finished if played without looping (PlayMode Animation#NORMAL), given the state * time. * * @param stateTime * @return whether the animation is finished. */ public boolean isAnimationFinished(float stateTime) { if (playMode != NORMAL && playMode != REVERSED) return false; int frameNumber = (int) (stateTime / frameDuration); return keyFrames.length - 1 < frameNumber; } }