package org.gbcpainter.game.view.animations;
import net.jcip.annotations.GuardedBy;
import org.gbcpainter.env.GraphicsEnv;
import org.gbcpainter.loaders.textures.TextureNotFoundException;
import org.gbcpainter.game.view.AbstractResourceDrawable;
import org.gbcpainter.loaders.textures.TextureLoader;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.awt.*;
import java.awt.geom.Point2D;
import java.util.Iterator;
/**
* Defines an animated element that changes its texture when {@link #endStep()} is called selecting the new texture from an {@link Iterable}.
* <p/>
* The position of the element is fetched via {@link #getPosition()}.
*
* @author Lorenzo Pellegrini
*/
public abstract class SingleSlotAnimatedElement extends AbstractResourceDrawable implements AnimatedElement {
@NotNull
private final Iterable<String> textures;
@Nullable
@GuardedBy ("this")
private EntityMovementAnimation animation = null;
@NotNull
private Iterator<String> nextTexture;
@NotNull
private String actualTexture;
@NotNull
private Point previousPosition;
/**
* Creates an animated element with a defined initial position and the resources name's
* {@link java.lang.Iterable}.
*
* @param initialPosition The initial position of the element
* @param resources An iterable that returns the names of the textures to use
*
* @throws Exception if an error occurs while loading textures
*/
public SingleSlotAnimatedElement( @NotNull final Point initialPosition,
@NotNull final Iterable<String> resources ) throws Exception {
super( );
this.textures = resources;
this.previousPosition = new Point( initialPosition );
final TextureLoader loader = GraphicsEnv.getInstance().getTextureLoader();
for (String resource : resources) {
try {
loader.loadTexture( resource, true );
} catch ( Exception e ) {
throw new TextureNotFoundException( e );
}
}
this.nextTexture = this.textures.iterator();
this.actualTexture = this.nextTexture.next();
}
@Nullable
@Override
protected synchronized Rectangle getDrawingRect() throws Exception {
Point2D animationPosition = null;
EntityMovementAnimation animation = this.getAnimation();
if ( animation != null ) {
try {
animationPosition = animation.getActualPosition();
} catch ( TerminatedAnimationException e ) {
this.applyAnimation( null );
animation = null;
}
}
if ( animation == null || animation.isTerminated() ) {
return super.getDrawingRect( this.previousPosition );
}
final String resourceName = this.getResourceName();
if ( resourceName == null ) {
return null;
}
final TextureLoader loader = GraphicsEnv.getInstance().getTextureLoader();
final Dimension dimension = loader.getDimension( resourceName );
return GraphicsEnv.getInstance().gamePointAndTextureToScreen( animationPosition, dimension );
}
@Override
public synchronized String toString() {
return "AnimatedElement{" +
", animations=" + this.animation +
"} " + super.toString();
}
@Override
protected synchronized String getResourceName() {
return this.actualTexture;
}
@Override
public synchronized void startStep() throws Exception {
this.previousPosition = this.getPosition();
}
@Override
public synchronized void endStep() throws Exception {
this.previousPosition = this.getPosition();
this.applyAnimation( null );
this.nextTexture();
}
@Override
@NotNull
public abstract Point getPosition();
@Override
public synchronized void applyAnimation( @Nullable EntityMovementAnimation animation ) {
this.animation = animation;
}
@Override
@Nullable
public synchronized EntityMovementAnimation getAnimation() {
return this.animation;
}
/**
* Retrieves the next texture
*
* @return The new txture
*/
protected synchronized String nextTexture() {
if ( ! this.nextTexture.hasNext() ) {
this.nextTexture = this.textures.iterator();
}
this.actualTexture = this.nextTexture.next();
return this.actualTexture;
}
}