package com.pointcliki.core;
import java.util.Arrays;
import org.newdawn.slick.Color;
import org.newdawn.slick.Graphics;
import org.newdawn.slick.Image;
import org.newdawn.slick.SpriteSheet;
import org.newdawn.slick.geom.Rectangle;
import org.newdawn.slick.geom.Vector2f;
import com.pointcliki.event.Dispatcher;
import com.pointcliki.event.FrameEvent;
import com.pointcliki.event.IEvent;
import com.pointcliki.event.Minion;
public class AnimatedSprite extends Entity {
/**
* Serial key
*/
private static final long serialVersionUID = 2045313939433270170L;
protected Image[] fImages;
protected Vector2f[] fOffsets = null;
protected int[] fDurations;
protected int fFrame = 0;
protected long fNextFrame = 0;
protected Minion<FrameEvent> fMinion;
protected int fFrames = 0;
public AnimatedSprite(String sheet, int x, int y, int number) {
super();
image(sheet, x, y, number);
}
public AnimatedSprite(String file) {
super();
image(file);
}
public AnimatedSprite(Image img) {
super();
image(img);
}
public AnimatedSprite(Image[] images) {
super();
image(images, null);
}
public AnimatedSprite(Image[] images, Vector2f[] offsets) {
super();
image(images, offsets);
}
public AnimatedSprite(Image[] images, Vector2f[] offsets, int[] timeDurations) {
super();
image(images, offsets, timeDurations);
}
public AnimatedSprite image(String file) {
return image(PointClikiGame.resourceManager().image(file));
}
public AnimatedSprite image(Image img) {
return image(new Image[]{img});
}
public AnimatedSprite image(Image[] images) {
return image(images, null);
}
public AnimatedSprite image(Image[] images, Vector2f[] offsets) {
image(images, offsets, new int[images.length]);
for (int i = 0; i < fDurations.length; i++) fDurations[i] = 100;
fFrames = images.length;
return this;
}
public AnimatedSprite image(String sheet, int x, int y, int number) {
return image(PointClikiGame.resourceManager().spritesheet(sheet, x, y), number);
}
public AnimatedSprite image(SpriteSheet sheet, int number) {
fImages = new Image[number];
for (int i = 0; i < number; i++) {
fImages[i] = sheet.getSprite(i % sheet.getHorizontalCount(), (int) Math.floor(i / sheet.getHorizontalCount()));
}
image(fImages, null, null);
return this;
}
public AnimatedSprite image(Image[] images, Vector2f[] offsets, int[] timeDurations) {
fImages = images;
fOffsets = offsets;
fDurations = timeDurations;
fFrames = 0;
fFrame = 0;
if (fOffsets == null) {
fOffsets = new Vector2f[images.length];
for (int i = 0; i < images.length; i++) {
fOffsets[i] = new Vector2f(0, 0);
}
}
// Calculate span
fSpan = new Rectangle(0, 0, 0, 0);
for (int i = 0; i < images.length; i++) {
if (fImages[i] == null) continue;
fSpan.setX(Math.min(fSpan.getX(), fOffsets[i].x - fImages[i].getWidth() / 2));
fSpan.setY(Math.min(fSpan.getY(), fOffsets[i].y - fImages[i].getHeight() / 2));
fFrames++;
}
for (int i = 0; i < images.length; i++) {
if (fImages[i] == null) continue;
fSpan.setWidth(Math.max(fSpan.getWidth(), fImages[i].getWidth() + fOffsets[i].x - fImages[i].getWidth() / 2 - fSpan.getX()));
fSpan.setHeight(Math.max(fSpan.getHeight(), fImages[i].getHeight() + fOffsets[i].y - fImages[i].getHeight() / 2 - fSpan.getY()));
}
return this;
}
public AnimatedSprite duration(int delay) {
fDurations = new int[fFrames];
for (int i = 0; i < fFrames; i++) {
fDurations[i] = delay;
}
return duration(fDurations);
}
public AnimatedSprite duration(int[] durations) {
fDurations = durations;
return this;
}
public void release() {
fImages = null;
fOffsets = null;
fDurations = null;
}
@Override
public void cleanup() {
stop();
super.cleanup();
/*
* The animation should be shared by the ResourceManager, so
* we shouldn't destroy its internals here
*/
release();
}
@Override
public ISavable snapshot() throws CloneNotSupportedException {
return (ISavable) super.clone();
}
@Override
public void render(Graphics graphics, long currentTime) {
super.render(graphics, currentTime);
if (fImages == null) return;
if (fImages.length < fFrame + 1 || fImages[fFrame] == null) return;
if (fOffsets == null) fImages[fFrame].draw(0, 0);
else fImages[fFrame].draw(-fImages[fFrame].getWidth() / 2 + fOffsets[fFrame].x, -fImages[fFrame].getHeight() / 2 + fOffsets[fFrame].y, new Color(1f, 1f, 1f, fOpacity));
}
public void start() {
// Can't start if no duration
if (fFrames == 0) return;
fMinion = new Minion<FrameEvent>() {
@Override
public long run(Dispatcher<FrameEvent> dispatcher, String type, FrameEvent event) {
if (fParent == null) return Minion.FINISH;
fFrame = (fFrame + 1) % fImages.length;
fDispatcher.dispatchEvent("animation.frame", new AnimationEvent());
fDispatcher.dispatchEvent("animation.frame." + fFrame, new AnimationEvent());
if (fFrame == 0) fDispatcher.dispatchEvent("animation.looped", new AnimationEvent());
// Check we haven't cleaned up since
if (fParent == null) return Minion.FINISH;
fNextFrame = timeManager().frameIn((long) timeManager().frameDuration(fDurations[fFrame]));
return (long) timeManager().frameDuration(fDurations[fFrame]);
}
@Override
public String toString() {
return "[#" + fID + " " + "AnimatedSprite Frame Minion]";
}
};
frameManager().queue(fMinion, (long) timeManager().frameDuration(fDurations[fFrame]));
fNextFrame = timeManager().frameIn((long) timeManager().frameDuration(fDurations[fFrame]));
}
public int frame() {
return fFrame;
}
public void frame(int i) {
fFrame = i;
}
public int frames() {
return fFrames;
}
public int frameDuration() {
// Calculate frame duration
float dur = 0;
for (int i = 0; i < fFrames; i++) if (fImages[i] != null) dur += timeManager().frameDuration(fDurations[i]);
return (int) Math.ceil(dur);
}
public void stop() {
if (fScene != null) frameManager().dequeue(fMinion, fNextFrame);
fFrame = 0;
}
public Image image(int i) {
return fImages[i];
}
public class AnimationEvent implements IEvent {
protected AnimationEvent() {}
public AnimatedSprite sprite() {
return AnimatedSprite.this;
}
public int frame() {
return sprite().frame();
}
}
public void splice(int start, int end) {
fImages = Arrays.copyOfRange(fImages, start, end);
fDurations = Arrays.copyOfRange(fDurations, start, end);
fOffsets = Arrays.copyOfRange(fOffsets, start, end);
fFrames = end - start;
}
}