package org.gbcpainter.game.view.animations;
import net.jcip.annotations.GuardedBy;
import org.gbcpainter.env.GraphicsEnv;
import org.gbcpainter.game.view.SlotResourceDrawable;
import org.gbcpainter.geom.PERPENDICULAR_DIRECTION;
import org.gbcpainter.loaders.textures.TextureLoader;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.awt.*;
import java.awt.geom.Point2D;
import java.util.Map;
/**
* Defines an animated element that changes its texture when {@link #endStep()} is called.
* <p/>
* The texture is selected from a different {@link Iterable}, specific for the direction of the
* entity. The position is fetched from {@link #getPosition()}.
*
* @author Lorenzo Pellegrini
*/
public abstract class SlotAnimatedElement extends SlotResourceDrawable<PERPENDICULAR_DIRECTION> implements AnimatedElement {
@Nullable
@GuardedBy ("this")
private EntityMovementAnimation animation = null;
@NotNull
private Point previousPosition;
/**
* Creates an animated element with a defined textures names map.
*
* @param resources A map where each direction is linked to an {@link java.lang.Iterable} that returns
* the names of the textures to use if the element is following
* that direction
* @param initialSlot The initial direction to use
*
* @throws java.lang.Exception If an error occurs while loading textures
*/
public SlotAnimatedElement( @NotNull final Point initialPosition,
@NotNull Map<PERPENDICULAR_DIRECTION, Iterable<String>> resources,
@NotNull PERPENDICULAR_DIRECTION initialSlot ) throws Exception {
super( resources, initialSlot );
this.previousPosition = new Point( initialPosition );
}
@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 void resetState() {
this.applyAnimation( null );
}
@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();
}
@NotNull
@Override
public abstract Point getPosition();
@Override
protected synchronized String getResourceName() {
EntityMovementAnimation animation = this.getAnimation();
boolean changedDirection;
PERPENDICULAR_DIRECTION newDirection;
final PERPENDICULAR_DIRECTION previousDirection = this.getSlot();
if ( animation == null || animation.isTerminated() ) {
newDirection = this.getActualDirection();
changedDirection = true;
} else {
try {
newDirection = animation.getActualDirection();
changedDirection = ( newDirection != previousDirection );
} catch ( TerminatedAnimationException e ) {
this.applyAnimation( null );
newDirection = this.getActualDirection();
changedDirection = true;
}
}
if ( changedDirection && newDirection != null ) {
this.switchSlot( newDirection );
}
return super.getResourceName();
}
@Override
public synchronized void applyAnimation( @Nullable EntityMovementAnimation animation ) {
this.animation = animation;
}
@Override
@Nullable
public synchronized EntityMovementAnimation getAnimation() {
return this.animation;
}
@Override
@NonNls
public synchronized String toString() {
return "SlotAnimatedElement{" +
", animation=" + this.getAnimation() +
", previousPosition=" + this.previousPosition +
"} " + super.toString();
}
}