package com.pointcliki.grid;
import org.newdawn.slick.geom.Vector2f;
import com.pointcliki.core.Entity;
import com.pointcliki.event.Minion;
import com.pointcliki.event.ProgressEvent;
import com.pointcliki.input.IArrowKeyMovable;
import com.pointcliki.transition.LerpMovement;
/**
* @author Hugheth
* @since 2
*
* @param <T> The type of entity the movement handles
*/
public abstract class GridAlignedMovement<T extends Entity> extends LerpMovement<T> implements IArrowKeyMovable {
/**
* Serial key
*/
private static final long serialVersionUID = 5007564364884607269L;
/**
* An event passed when the entity starts moving
*/
public static final String PROGRESS_FIRST_START = "firstStart";
/**
* An event passed when the entity stops moving
*/
public static final String PROGRESS_LAST_STOP = "lastStop";
protected boolean fContinue = false;
protected GridCoordinate fNextVelocity;
protected long fTimeDuration;
/**
* @param entity The entity being moved
* @param monitor The monitor that receives events from the movement
* @param renderPriority The render priority
* @param logicPriority The logic priority
*/
public GridAlignedMovement(T entity, Minion<ProgressEvent<T>> monitor, int renderPriority, int logicPriority) {
super(entity, monitor, renderPriority, logicPriority);
}
@Override
public void move(GridCoordinate velocity) {
fNextVelocity = velocity;
fContinue = true;
if (!isRunning()) setup(fNextVelocity, true);
}
@Override
public void stop(GridCoordinate velocity) {
if (fNextVelocity != velocity) return;
fContinue = false;
}
/**
* Stop the entity at the next alignment
*/
public void stop() {
fContinue = false;
}
@Override
public void pause() {
super.pause();
fContinue = false;
}
/**
* Nudge the entity into moving a single grid square
* @param velocity The velocity to nudge the entity in
*/
public void nudge(GridCoordinate velocity) {
if (isRunning()) return;
fNextVelocity = velocity;
fContinue = false;
setup(velocity, true);
}
protected void setup(GridCoordinate velocity, boolean first) {
GridCoordinate nextTile = gridEntity().getTile().add(velocity);
if (!canMove(nextTile)) {
fMonitor.run(null, PROGRESS_LAST_STOP, new ProgressEvent<T>(this));
return;
}
fMonitor.run(null, PROGRESS_FIRST_START, new ProgressEvent<T>(this));
setup(gridEntity().gridManager().tileToVector(nextTile));
begin();
// Set the tile
Vector2f old = fParent.position().copy();
gridEntity().setTile(nextTile);
// Don't actually move there though!
fParent.position(old);
}
@Override
public void end() {
super.end();
// Continue
if (fContinue) {
// If this has already happened as a result of calling end on the minion,
// we don't want to setup again.
if (!isRunning()) setup(fNextVelocity, false);
} else {
fMonitor.run(null, PROGRESS_LAST_STOP, new ProgressEvent<T>(this));
}
}
@Override
public void cancel() {
gridEntity().setTile(gridEntity().gridManager().vectorToTile(fOrigin));
fContinue = false;
super.cancel();
}
protected IGridEntity gridEntity() {
return (IGridEntity) fParent;
}
/**
* @return The target of the movement
*/
public Vector2f GridCoordinate() {
return fTarget;
}
/**
* @return The next velocity of the entity after its next alignment
*/
public GridCoordinate nextVelocity() {
return fNextVelocity;
}
/**
* @return Whether the entity will continue to move after it has next aligned
*/
public boolean willContinue() {
return fContinue;
}
/**
* @param target The target coordinate of the movement
* @return Whether the entity should be allowed to move there
*/
public abstract boolean canMove(GridCoordinate target);
}