package org.andengine.entity.sprite;
import org.andengine.entity.sprite.vbo.ITiledSpriteVertexBufferObject;
import org.andengine.opengl.shader.PositionColorTextureCoordinatesShaderProgram;
import org.andengine.opengl.shader.ShaderProgram;
import org.andengine.opengl.texture.region.ITiledTextureRegion;
import org.andengine.opengl.vbo.DrawType;
import org.andengine.opengl.vbo.VertexBufferObjectManager;
import org.andengine.util.time.TimeConstants;
/**
* (c) 2010 Nicolas Gramlich
* (c) 2011 Zynga Inc.
*
* @author Nicolas Gramlich
* @since 15:25:46 - 10.03.2010
*/
public class AnimatedSprite extends TiledSprite {
// ===========================================================
// Constants
// ===========================================================
private static final int FRAMEINDEX_INVALID = -1;
// ===========================================================
// Fields
// ===========================================================
private boolean mAnimationRunning;
private boolean mAnimationStartedFired;
private int mCurrentFrameIndex;
private long mAnimationProgress;
private int mRemainingLoopCount;
@SuppressWarnings("deprecation")
private final IAnimationData mAnimationData = new AnimationData();
private IAnimationListener mAnimationListener;
// ===========================================================
// Constructors
// ===========================================================
public AnimatedSprite(final float pX, final float pY, final ITiledTextureRegion pTiledTextureRegion, final VertexBufferObjectManager pVertexBufferObjectManager) {
super(pX, pY, pTiledTextureRegion, pVertexBufferObjectManager, DrawType.DYNAMIC);
}
public AnimatedSprite(final float pX, final float pY, final ITiledTextureRegion pTiledTextureRegion, final VertexBufferObjectManager pVertexBufferObjectManager, final ShaderProgram pShaderProgram) {
super(pX, pY, pTiledTextureRegion, pVertexBufferObjectManager, DrawType.DYNAMIC, pShaderProgram);
}
public AnimatedSprite(final float pX, final float pY, final ITiledTextureRegion pTiledTextureRegion, final VertexBufferObjectManager pVertexBufferObjectManager, final DrawType pDrawType) {
super(pX, pY, pTiledTextureRegion, pVertexBufferObjectManager, pDrawType);
}
public AnimatedSprite(final float pX, final float pY, final ITiledTextureRegion pTiledTextureRegion, final VertexBufferObjectManager pVertexBufferObjectManager, final DrawType pDrawType, final ShaderProgram pShaderProgram) {
super(pX, pY, pTiledTextureRegion, pVertexBufferObjectManager, pDrawType, pShaderProgram);
}
public AnimatedSprite(final float pX, final float pY, final ITiledTextureRegion pTiledTextureRegion, final ITiledSpriteVertexBufferObject pTiledSpriteVertexBufferObject) {
super(pX, pY, pTiledTextureRegion, pTiledSpriteVertexBufferObject);
}
public AnimatedSprite(final float pX, final float pY, final ITiledTextureRegion pTiledTextureRegion, final ITiledSpriteVertexBufferObject pTiledSpriteVertexBufferObject, final ShaderProgram pShaderProgram) {
super(pX, pY, pTiledTextureRegion, pTiledSpriteVertexBufferObject, pShaderProgram);
}
public AnimatedSprite(final float pX, final float pY, final float pWidth, final float pHeight, final ITiledTextureRegion pTiledTextureRegion, final VertexBufferObjectManager pVertexBufferObjectManager) {
super(pX, pY, pWidth, pHeight, pTiledTextureRegion, pVertexBufferObjectManager, DrawType.DYNAMIC);
}
public AnimatedSprite(final float pX, final float pY, final float pWidth, final float pHeight, final ITiledTextureRegion pTiledTextureRegion, final VertexBufferObjectManager pVertexBufferObjectManager, final ShaderProgram pShaderProgram) {
super(pX, pY, pWidth, pHeight, pTiledTextureRegion, pVertexBufferObjectManager, DrawType.DYNAMIC, pShaderProgram);
}
public AnimatedSprite(final float pX, final float pY, final float pWidth, final float pHeight, final ITiledTextureRegion pTiledTextureRegion, final VertexBufferObjectManager pVertexBufferObjectManager, final DrawType pDrawType) {
super(pX, pY, pWidth, pHeight, pTiledTextureRegion, pVertexBufferObjectManager, pDrawType);
}
public AnimatedSprite(final float pX, final float pY, final float pWidth, final float pHeight, final ITiledTextureRegion pTiledTextureRegion, final VertexBufferObjectManager pVertexBufferObjectManager, final DrawType pDrawType, final ShaderProgram pShaderProgram) {
super(pX, pY, pWidth, pHeight, pTiledTextureRegion, pVertexBufferObjectManager, pDrawType, pShaderProgram);
}
public AnimatedSprite(final float pX, final float pY, final float pWidth, final float pHeight, final ITiledTextureRegion pTiledTextureRegion, final ITiledSpriteVertexBufferObject pTiledSpriteVertexBufferObject) {
super(pX, pY, pWidth, pHeight, pTiledTextureRegion, pTiledSpriteVertexBufferObject, PositionColorTextureCoordinatesShaderProgram.getInstance());
}
public AnimatedSprite(final float pX, final float pY, final float pWidth, final float pHeight, final ITiledTextureRegion pTiledTextureRegion, final ITiledSpriteVertexBufferObject pTiledSpriteVertexBufferObject, final ShaderProgram pShaderProgram) {
super(pX, pY, pWidth, pHeight, pTiledTextureRegion, pTiledSpriteVertexBufferObject, pShaderProgram);
}
// ===========================================================
// Getter & Setter
// ===========================================================
public boolean isAnimationRunning() {
return this.mAnimationRunning;
}
// ===========================================================
// Methods for/from SuperClass/Interfaces
// ===========================================================
@Override
protected void onManagedUpdate(final float pSecondsElapsed) {
super.onManagedUpdate(pSecondsElapsed);
if(this.mAnimationRunning) {
final int loopCount = this.mAnimationData.getLoopCount();
final int[] frames = this.mAnimationData.getFrames();
final long animationDuration = this.mAnimationData.getAnimationDuration();
if(!this.mAnimationStartedFired && (this.mAnimationProgress == 0)) {
this.mAnimationStartedFired = true;
if(frames == null) {
this.setCurrentTileIndex(this.mAnimationData.getFirstFrameIndex());
} else {
this.setCurrentTileIndex(frames[0]);
}
this.mCurrentFrameIndex = 0;
if(this.mAnimationListener != null) {
this.mAnimationListener.onAnimationStarted(this, loopCount);
this.mAnimationListener.onAnimationFrameChanged(this, AnimatedSprite.FRAMEINDEX_INVALID, 0);
}
}
final long nanoSecondsElapsed = (long) (pSecondsElapsed * TimeConstants.NANOSECONDS_PER_SECOND);
this.mAnimationProgress += nanoSecondsElapsed;
if(loopCount == IAnimationData.LOOP_CONTINUOUS) {
while(this.mAnimationProgress > animationDuration ) {
this.mAnimationProgress -= animationDuration;
if(this.mAnimationListener != null) {
this.mAnimationListener.onAnimationLoopFinished(this, this.mRemainingLoopCount, loopCount);
}
}
} else {
while(this.mAnimationProgress > animationDuration) {
this.mAnimationProgress -= animationDuration;
this.mRemainingLoopCount--;
if(this.mRemainingLoopCount < 0) {
break;
} else if(this.mAnimationListener != null) {
this.mAnimationListener.onAnimationLoopFinished(this, this.mRemainingLoopCount, loopCount);
}
}
}
if((loopCount == IAnimationData.LOOP_CONTINUOUS) || (this.mRemainingLoopCount >= 0)) {
final int newFrameIndex = this.mAnimationData.calculateCurrentFrameIndex(this.mAnimationProgress);
if(this.mCurrentFrameIndex != newFrameIndex) {
if(frames == null) {
this.setCurrentTileIndex(this.mAnimationData.getFirstFrameIndex() + newFrameIndex);
} else {
this.setCurrentTileIndex(frames[newFrameIndex]);
}
if(this.mAnimationListener != null) {
this.mAnimationListener.onAnimationFrameChanged(this, this.mCurrentFrameIndex, newFrameIndex);
}
}
this.mCurrentFrameIndex = newFrameIndex;
} else {
this.mAnimationRunning = false;
if(this.mAnimationListener != null) {
this.mAnimationListener.onAnimationFinished(this);
}
}
}
}
// ===========================================================
// Methods
// ===========================================================
public void stopAnimation() {
this.mAnimationRunning = false;
}
public void stopAnimation(final int pTileIndex) {
this.mAnimationRunning = false;
this.setCurrentTileIndex(pTileIndex);
}
public void animate(final long pFrameDurationEach) {
this.animate(pFrameDurationEach, null);
}
public void animate(final long pFrameDurationEach, final IAnimationListener pAnimationListener) {
this.mAnimationData.set(pFrameDurationEach, this.getTileCount());
this.initAnimation(pAnimationListener);
}
public void animate(final long pFrameDurationEach, final boolean pLoop) {
this.animate(pFrameDurationEach, pLoop, null);
}
public void animate(final long pFrameDurationEach, final boolean pLoop, final IAnimationListener pAnimationListener) {
this.mAnimationData.set(pFrameDurationEach, this.getTileCount(), pLoop);
this.initAnimation(pAnimationListener);
}
public void animate(final long pFrameDurationEach, final int pLoopCount) {
this.animate(pFrameDurationEach, pLoopCount, null);
}
public void animate(final long pFrameDurationEach, final int pLoopCount, final IAnimationListener pAnimationListener) {
this.mAnimationData.set(pFrameDurationEach, this.getTileCount(), pLoopCount);
this.initAnimation(pAnimationListener);
}
public void animate(final long[] pFrameDurations) {
this.animate(pFrameDurations, (IAnimationListener)null);
}
public void animate(final long[] pFrameDurations, final IAnimationListener pAnimationListener) {
this.mAnimationData.set(pFrameDurations);
this.initAnimation(pAnimationListener);
}
public void animate(final long[] pFrameDurations, final boolean pLoop) {
this.animate(pFrameDurations, pLoop, null);
}
public void animate(final long[] pFrameDurations, final boolean pLoop, final IAnimationListener pAnimationListener) {
this.mAnimationData.set(pFrameDurations, pLoop);
this.initAnimation(pAnimationListener);
}
public void animate(final long[] pFrameDurations, final int pLoopCount) {
this.animate(pFrameDurations, pLoopCount, null);
}
public void animate(final long[] pFrameDurations, final int pLoopCount, final IAnimationListener pAnimationListener) {
this.mAnimationData.set(pFrameDurations, pLoopCount);
this.initAnimation(pAnimationListener);
}
public void animate(final long[] pFrameDurations, final int pFirstTileIndex, final int pLastTileIndex, final boolean pLoop) {
this.animate(pFrameDurations, pFirstTileIndex, pLastTileIndex, pLoop, null);
}
public void animate(final long[] pFrameDurations, final int pFirstTileIndex, final int pLastTileIndex, final boolean pLoop, final IAnimationListener pAnimationListener) {
this.mAnimationData.set(pFrameDurations, pFirstTileIndex, pLastTileIndex, pLoop);
this.initAnimation(pAnimationListener);
}
public void animate(final long[] pFrameDurations, final int pFirstTileIndex, final int pLastTileIndex, final int pLoopCount) {
this.animate(pFrameDurations, pFirstTileIndex, pLastTileIndex, pLoopCount, null);
}
public void animate(final long[] pFrameDurations, final int pFirstTileIndex, final int pLastTileIndex, final int pLoopCount, final IAnimationListener pAnimationListener) {
this.mAnimationData.set(pFrameDurations, pFirstTileIndex, pLastTileIndex, pLoopCount);
this.initAnimation(pAnimationListener);
}
/**
* Animate specifics frames.
*
* @param pFrameDurations must have the same length as pFrames.
* @param pFrames indices of the frames to animate.
*/
public void animate(final long[] pFrameDurations, final int[] pFrames) {
this.animate(pFrameDurations, pFrames, null);
}
/**
* Animate specifics frames.
*
* @param pFrameDurations must have the same length as pFrames.
* @param pFrames indices of the frames to animate.
* @param pAnimationListener
*/
public void animate(final long[] pFrameDurations, final int[] pFrames, final IAnimationListener pAnimationListener) {
this.mAnimationData.set(pFrameDurations, pFrames);
this.initAnimation(pAnimationListener);
}
/**
* Animate specifics frames.
*
* @param pFrameDurations must have the same length as pFrames.
* @param pFrames indices of the frames to animate.
* @param pLoop
*/
public void animate(final long[] pFrameDurations, final int[] pFrames, final boolean pLoop) {
this.animate(pFrameDurations, pFrames, pLoop, null);
}
/**
* Animate specifics frames.
*
* @param pFrameDurations must have the same length as pFrames.
* @param pFrames indices of the frames to animate.
* @param pLoop
* @param pAnimationListener
*/
public void animate(final long[] pFrameDurations, final int[] pFrames, final boolean pLoop, final IAnimationListener pAnimationListener) {
this.mAnimationData.set(pFrameDurations, pFrames, pLoop);
this.initAnimation(pAnimationListener);
}
/**
* Animate specifics frames.
*
* @param pFrameDurations must have the same length as pFrames.
* @param pFrames indices of the frames to animate.
* @param pLoopCount
*/
public void animate(final long[] pFrameDurations, final int[] pFrames, final int pLoopCount) {
this.animate(pFrameDurations, pFrames, pLoopCount, null);
}
/**
* Animate specifics frames.
*
* @param pFrameDurations must have the same length as pFrames.
* @param pFrames indices of the frames to animate.
* @param pLoopCount
* @param pAnimationListener
*/
public void animate(final long[] pFrameDurations, final int[] pFrames, final int pLoopCount, final IAnimationListener pAnimationListener) {
this.mAnimationData.set(pFrameDurations, pFrames, pLoopCount);
this.initAnimation(pAnimationListener);
}
public void animate(final IAnimationData pAnimationData) {
this.animate(pAnimationData, null);
}
public void animate(final IAnimationData pAnimationData, final IAnimationListener pAnimationListener) {
this.mAnimationData.set(pAnimationData);
this.initAnimation(pAnimationListener);
}
private void initAnimation(final IAnimationListener pAnimationListener) {
this.mAnimationStartedFired = false;
this.mAnimationListener = pAnimationListener;
this.mRemainingLoopCount = this.mAnimationData.getLoopCount();
this.mAnimationProgress = 0;
this.mAnimationRunning = true;
}
// ===========================================================
// Inner and Anonymous Classes
// ===========================================================
public static interface IAnimationListener {
// ===========================================================
// Constants
// ===========================================================
// ===========================================================
// Fields
// ===========================================================
/**
* @param pAnimatedSprite
* @param pInitialLoopCount is {@link AnimatedSprite#LOOP_CONTINUOUS} when {@link AnimatedSprite} loops infinitely.
*/
public void onAnimationStarted(final AnimatedSprite pAnimatedSprite, final int pInitialLoopCount);
/**
* @param pAnimatedSprite
* @param pOldFrameIndex equals {@link AnimatedSprite#FRAMEINDEX_INVALID}, the first time {@link IAnimationListener#onAnimationFrameChanged(AnimatedSprite, int, int)} is called.
* @param pNewFrameIndex the new frame index of the currently active animation.
*/
public void onAnimationFrameChanged(final AnimatedSprite pAnimatedSprite, final int pOldFrameIndex, final int pNewFrameIndex);
/**
* @param pAnimatedSprite
* @param pRemainingLoopCount is {@link AnimatedSprite#LOOP_CONTINUOUS} when {@link AnimatedSprite} loops infinitely.
* @param pInitialLoopCount is {@link AnimatedSprite#LOOP_CONTINUOUS} when {@link AnimatedSprite} loops infinitely.
*/
public void onAnimationLoopFinished(final AnimatedSprite pAnimatedSprite, final int pRemainingLoopCount, final int pInitialLoopCount);
public void onAnimationFinished(final AnimatedSprite pAnimatedSprite);
}
}