package org.erikaredmark.monkeyshines;
import java.awt.Graphics2D;
import org.erikaredmark.monkeyshines.resource.WorldResource;
/**
*
* Stores the immutable properties of a conveyer belt. Similiar to Hazards, instances of this class
* are added to the world depending on the size of the conveyer belt sprite sheet. Since there is
* no customisation, this happens automatically.
*
* @author Erika Redmark
*
*/
public final class Conveyer {
// Together, id and rotation can map to a specific row of sprites.
private int id;
private Rotation rotation;
public Conveyer(final int id, final Rotation rotation) {
this.id = id;
this.rotation = rotation;
}
/** Intended for test methods and encoder/decoders*/
public int getId() { return id; }
/** Intended for test methods and encoder/decoders*/
public Rotation getRotation() { return rotation; }
private static final int CONVEYER_SET_SIZE = GameConstants.TILE_SIZE_Y * 2;
/**
*
* Paints this conveyer belt to the given graphics context at the given cordinates. This is used by {@code ConveyerTile}, which
* will compute and provide the position data/graphics context that this needs to draw on.
*
* @param g2
*
* @param drawToX
* x location to draw (in pixels)
*
* @param drawToY
* y location to draw (in pixels)
*
* @param animationStep
* A value between {@code 0 - 4}, as there are no other animation steps in a conveyer belt. If
* assertions are enabled, other values will fail. Otherwise, undefined behaviour.
*
*/
public void paint(Graphics2D g2d, int drawToX, int drawToY, int animationStep, WorldResource rsrc) {
assert animationStep >= 0 && animationStep < 5;
// X position depends 100% on animation step
int drawFromX = animationStep * GameConstants.TILE_SIZE_X;
// ySet indicates the set of conveyer belts an id
// is specified for.
int ySet = CONVEYER_SET_SIZE * id;
// Y position is either the same as ySet for clockwise, or ySet + TILE_SIZE_Y for anti-clockwise
int drawFromY = ySet + rotation.drawYOffset();
g2d.drawImage(rsrc.getConveyerSheet(), drawToX , drawToY, // Destination 1 (top left)
drawToX + GameConstants.TILE_SIZE_X, drawToY + GameConstants.TILE_SIZE_Y, // Destination 2 (bottom right)
drawFromX, drawFromY, // Source 1 (top Left)
drawFromX + GameConstants.TILE_SIZE_X, drawFromY + GameConstants.TILE_SIZE_Y, // Source 2 (bottom right)
null);
}
public enum Rotation {
CLOCKWISE {
@Override public double translationX() {
return GameConstants.CONVEYER_SPEED;
}
@Override public int drawYOffset() { return 0; }
},
ANTI_CLOCKWISE {
@Override public double translationX() {
return -GameConstants.CONVEYER_SPEED;
}
@Override public int drawYOffset() { return GameConstants.TILE_SIZE_Y; }
},
/**
* Special enumeration used for Bonzo when he is on no conveyer belt. Moves him by 0
* amount. Removes need for null checking and extra branching.
*/
NONE {
@Override public double translationX() { return 0; }
@Override public int drawYOffset() { throw new UnsupportedOperationException("NONE is a valid rotation type ONLY for bonzo; cannot draw a non-rotating conveyer belt"); }
};
/**
*
* Returns the number of pixels of translation that should be applied to bonzo
* when on a conveyer belt of this rotation.
*
*/
public abstract double translationX();
/**
*
* Returns the number of pixels in the Y direction from the beginning of a set
* of conveyer belts that this conveyer should be drawn from. This really only
* has two values, {@code 0} for clockwise and {@code GameConstants.TILE_SIZE_Y}
* for anti-clockwise. Makes it easier to draw the right conveyer belt.
*
*/
protected abstract int drawYOffset();
}
@Override public boolean equals(Object o) {
if (o == this) return true;
if (!(o instanceof Conveyer) ) return false;
Conveyer other = (Conveyer) o;
return id == other.id
&& rotation.equals(other.rotation);
}
@Override public int hashCode() {
int result = 17;
result += result * 31 + id;
result += result * 31 + rotation.hashCode();
return result;
}
@Override public String toString() {
return "Conveyer of id " + id + " with rotation " + rotation;
}
}