import java.awt.*; import java.lang.Math; /** An AnimatedSprite is a HardlySprite that cycles through a Sequence of images, either forward or backward, looping or stopping on the last image, at a given animation speed */ public class AnimatedSprite extends HardlySprite { Sequence spriteSeq; int frames, currentFrame, lastFrame; int fps; boolean runsForward; boolean looping; long msPerFrame; long lastFrameTime, nextFrameTime; /** Creates an AnimatedSprite. Calls HardlySprite constructor and then does extra stuff. @param spriteSeq The Sequence of sprite images to be used @param world The SpriteWorld associated with this AnimatedSprite @param x Initial x-coordinate @param y Initial y-coordinate @param direction Initial direction, in radians, from 0 to 2 PI, with 0 as due right @param speed Speed in pixels per second @param fps Animation speed, in frames per second @param runsForward true if you want to start at first image in spriteSeq and go forward, false if you want to start on last image of spriteSeq and go backwards @param looping true if animation is continuous, false if it should stop on first/last image */ public AnimatedSprite (Sequence spriteSeq, SpriteWorld world, int x, int y, float direction, float speed, int fps, boolean runsForward, boolean looping) { super (spriteSeq.imageAt(0), world, x, y, direction, speed); this.spriteSeq = spriteSeq; this.fps = fps; this.runsForward = runsForward; this.looping = looping; this.frames = spriteSeq.getLength(); lastFrame = frames - 1; currentFrame = 0; msPerFrame = 1000 / fps; lastFrameTime = System.currentTimeMillis(); nextFrameTime = lastFrameTime + msPerFrame; } // main constructor /** Calls HardlySprite's updatePosition() to move sprite, then looks at time to see if sprite's image needs to be changed to the next image in the sequence and does so. Known Issue: if so much time has gone by that we should advance two or more images, this routine still only advances by one image */ public final boolean updatePosition() { boolean spriteAlive = true; super.updatePosition(); if (inTime < nextFrameTime) { return true; } else { if (runsForward) { if (currentFrame < lastFrame) { currentFrame++; } else { if (looping) { currentFrame = 0; } else { spriteAlive = end(); } // if looping } // if not on last frame } else { if (currentFrame > 0) { currentFrame--; } else { if (looping) { currentFrame = lastFrame; } else { spriteAlive = end(); } // if looping } // if not on first frame } // if running forward changeImage (spriteSeq.imageAt (currentFrame)); lastFrameTime = inTime; nextFrameTime = lastFrameTime + msPerFrame; return spriteAlive; } // else }// updatePosition /** Called when a non-looping animation finishes showing its last image. Currently does nothing. Sublclasses should override this method if they need to do something special once an animation has finished. @return true if sprite is still alive after end(), false if it has been remove()d from the SpriteWorld */ protected boolean end() { return true; } // no-op. Subclasses override if they want to eliminate sprite after sequence ends /** Changes the Sequence used by the animatedSprite. Notes its new size and number of images. @param newSequence The new Sequence to be used */ public final void changeSequence (Sequence newSequence) { spriteSeq = newSequence; frames = spriteSeq.getLength(); lastFrame = frames - 1; changeImage (spriteSeq.imageAt (0)); width = spriteImage.getWidth(world); height = spriteImage.getWidth(world); } // changeSequence /** Sets the animation speed @param fps Animation speed, in frames per second */ public final void setAnimationSpeed (int fps) { this.fps = fps; msPerFrame = 1000/fps; } // setAnimationSpeed /** Returns the animation speed @return The sprite's animation speed, in frames per second */ public final int getAnimationSpeed () { return this.fps; } // getAnimationSpeed public final Sequence getSequence() { return spriteSeq; } } /* AnimatedSprite */