Chess/src/APiece.java

457 lines
12 KiB
Java

import java.awt.*;
import java.awt.geom.Ellipse2D;
import java.awt.geom.Path2D;
import java.util.Timer;
import java.util.TimerTask;
/**
* Abstract piece class
*/
public abstract class APiece {
/**
* Chessboard instance
*/
protected Chessboard chessboard;
/**
* Piece's X location
*/
protected int x;
/**
* Piece's Y location
*/
protected int y;
/**
* Piece's X override location
*/
public double overrideX;
/**
* Piece's Y override location
*/
public double overrideY;
/**
* Piece's color
*/
protected PieceColor color;
/**
* Player owning the piece
*/
protected Player player;
/**
* Piece's move count
*/
public int moveCount = 0;
/**
* Piece's scale
*/
public double scale = 1;
/**
* Create a new piece
* @param player player
* @param x piece's X location
* @param y piece's Y location
*/
public APiece(Player player, int x, int y) {
this.x = x;
this.y = y;
this.player = player;
this.chessboard = player.getChessboard();
this.color = player.getColor();
chessboard.addPiece(this, x, y);
}
/**
* Create Path2D object from points
* @param points object's points
* @return Path2D object
*/
public Path2D getObject(double[][] points) {
Path2D object = new Path2D.Double();
object.moveTo(points[0][0], points[0][1]);
for (int i = 1; i < points.length; i++) {
if(points[i].length == 2) object.lineTo(points[i][0], points[i][1]);
if(points[i].length == 6) object.curveTo(points[i][2], points[i][3], points[i][4], points[i][5], points[i][0], points[i][1]);
}
object.closePath();
return object;
}
/**
* Create Path2D object from points
* @param xPoints object's X points
* @param yPoints object's Y points
* @return Path2D object
*/
public Path2D getObject(double[] xPoints, double[] yPoints) {
double[][] points = new double[xPoints.length][];
for (int i = 0; i < points.length; i++) {
points[i] = new double[2];
points[i][0] = xPoints[i];
points[i][1] = yPoints[i];
}
return getObject(points);
}
/**
* Create Ellipse2D from specified coordinates
* @param x ellipse's X coordinate
* @param y ellipse's Y coordinate
* @param w ellipse width
* @param h ellipse height
* @return Ellipse2D object
*/
public Ellipse2D getEllipse(double x, double y, double w, double h) {
return new Ellipse2D.Double(x, y, w, h);
}
/**
* Create piece's stand
* @return Path2D stand
*/
public Path2D getStand() {
double[] xStand = new double[]{30, 70, 70, 60, 90, 90, 10, 10, 40, 30};
double[] yStand = new double[]{64, 64, 69, 69, 87, 100, 100, 87, 69, 69};
double[][] points = new double[xStand.length][];
for (int i = 0; i < points.length; i++) {
if(i == 4) {
points[i] = new double[]{xStand[i], yStand[i], 69+3, 80-5, 69-3, 80+5};
} else if(i == 8) {
points[i] = new double[]{xStand[i], yStand[i], 31+3, 80+5, 31-3, 80-5};
} else {
points[i] = new double[2];
points[i][0] = xStand[i];
points[i][1] = yStand[i];
}
}
return getObject(points);
}
/**
* Paint specified objects
* @param g2 Graphics2D
* @param objects painted objects
*/
public void paintObjects(Graphics2D g2, Shape[] objects) {
g2.setStroke(new BasicStroke(8));
for (Shape object : objects) {
g2.setColor(color.draw);
g2.draw(object);
g2.setColor(color.fill);
g2.fill(object);
}
}
/**
* Set piece's new position with animation
* @param newX new X position
* @param newY new Y position
*/
public void setPosition(int newX, int newY) {
setPosition(newX, newY, true);
}
/**
* Set piece's new position
* @param newX new X position
* @param newY new Y position
* @param animate animate piece's move
*/
public void setPosition(int newX, int newY, boolean animate) {
if(animate) animateMove(x, y, newX, newY);
moveCount++;
chessboard.removePiece(x, y);
APiece piece = chessboard.getPiece(newX, newY);
if(piece != null) {
piece.remove(animate);
}
x = newX;
y = newY;
chessboard.addPiece(this, x, y);
}
/**
* Determines if the piece is floating
* @return is floating
*/
public boolean isFloating() {
return overrideX != 0 && overrideY != 0;
}
/**
* Set override location if piece is floating
* @param x floating piece's X location
* @param y floating piece's Y location
*/
public void setOverride(double x, double y) {
overrideX = x;
overrideY = y;
}
/**
* Get X position in px on the chessboard
* @return real X position in px
*/
public double getRealX() {
if(overrideX != 0) return (overrideX-chessboard.startX)/chessboard.boardScale;
return chessboard.SQUARE_SIZE*x;
}
/**
* Get Y position in px on the chessboard
* @return real Y position in px
*/
public double getRealY() {
if(overrideY != 0) return (overrideY-chessboard.startY)/chessboard.boardScale;;
return chessboard.SQUARE_SIZE*y;
}
/**
* Get piece's scale
* @return piece's scale
*/
public double getScale() {
return scale;
}
/**
* Get piece's X location
* @return piece's X location
*/
public int getX() {
return x;
}
/**
* Get piece's Y location
* @return piece's Y location
*/
public int getY() {
return y;
}
/**
* Get piece's player
* @return piece's player
*/
public Player getPlayer() {
return player;
}
/**
* Get piece's move count
* @return move count
*/
public int getMoveCount() {
return moveCount;
}
/**
* Set piece's move count
* @param moveCount new move count
*/
public void setMoveCount(int moveCount) {
this.moveCount = moveCount;
}
/**
* Checks, if passed move is possible
* @param moves two-dimensional array of moves
* @param x new X position
* @param y new Y position
*/
public void setPossibleMove(boolean[][] moves, int x, int y) {
if(x == this.x && y == this.y) return;
if(x < 0 || x >= moves.length || y < 0 || y >= moves.length) return;
APiece piece = chessboard.getPiece(x, y);
if(piece != null && player == piece.getPlayer()) return;
if(tryMove(piece, x, y)) return;
moves[y][x] = true;
}
/**
* Tests whether the player will be in check if the piece moves to a new position
* @param piece piece on the new position
* @param newX new X position
* @param newY new Y position
* @return true, if player will be in check
*/
public boolean tryMove(APiece piece, int newX, int newY) {
chessboard.removePiece(x, y);
chessboard.addPiece(this, newX, newY);
PiecePosition old = new PiecePosition(x, y);
x = newX;
y = newY;
boolean inCheck = player.inCheck();
x = old.x;
y = old.y;
chessboard.addPiece(piece, newX, newY);
chessboard.addPiece(this, old);
return inCheck;
}
/**
* Tests, whether the piece is endangered by another piece
* @return true, if endangered
*/
public boolean isEndangered() {
return chessboard.isEndangered(x, y);
}
/**
* Move the piece to the new position with animation
* @param newX new X position
* @param newY new Y position
*/
public void move(int newX, int newY) {
move(newX, newY, true);
}
/**
* Move the piece to the new position with animation
* @param newX new X position
* @param newY new Y position
* @param animate animate piece's move
*/
public void move(int newX, int newY, boolean animate) {
boolean[][] lastMove = new boolean[chessboard.SQUARE_COUNT][chessboard.SQUARE_COUNT];
lastMove[y][x] = true;
lastMove[newY][newX] = true;
setPosition(newX, newY, animate);
chessboard.showLastMove(lastMove);
}
/**
* Get repaint rectangle containing the piece
* @return repaint rectangle
*/
public Rectangle getRepaintRectangle() {
return getRepaintRectangle(Chess.menuBar.getHeight());
}
/**
* Get repaint rectangle containing the piece with vertical offset
* @param offsetY vertical offset
* @return repaint rectangle
*/
public Rectangle getRepaintRectangle(int offsetY) {
int rectSize = (int) (chessboard.SQUARE_SIZE*chessboard.boardScale);
double x = getRealX()*chessboard.boardScale+chessboard.startX;
double y = getRealY()*chessboard.boardScale+chessboard.startY;
return new Rectangle(
(int) x - 10, (int) y + offsetY - 10,
rectSize + 20, rectSize + 20
);
}
/**
* Trace the piece's path in X, Y direction
* @param moves two-dimensional array of moves
* @param xDirection X direction
* @param yDirection Y direction
*/
public void tracePath(boolean[][] moves, int xDirection, int yDirection) {
int i = x + xDirection;
int j = y + yDirection;
while(i >= 0 && i < moves.length && j >= 0 && j < moves.length) {
setPossibleMove(moves, i, j);
APiece piece = chessboard.getPiece(i, j);
if(piece != null && piece != chessboard.getSelectedPiece()) break;
i += xDirection;
j += yDirection;
}
}
/**
* Get piece's possible moves
* @return two-dimensional array of moves
*/
public boolean[][] getPossibleMoves() {
return getPossibleMoves(false);
}
/**
* Get piece's possible moves
* @param attack force the attack mode
* @return two-dimensional array of moves
*/
abstract public boolean[][] getPossibleMoves(boolean attack);
/**
* Paint the piece
* @param g2 Graphics2D
*/
abstract public void paint(Graphics2D g2);
/**
* Animate piece's move
* @param fromX original X position
* @param fromY original Y position
* @param toX new X position
* @param toY new Y position
*/
public void animateMove(int fromX, int fromY, int toX, int toY) {
double startX = chessboard.startX + (fromX*chessboard.SQUARE_SIZE)*chessboard.boardScale;
double startY = chessboard.startY + (fromY*chessboard.SQUARE_SIZE)*chessboard.boardScale;
double endX = chessboard.startX + (toX*chessboard.SQUARE_SIZE)*chessboard.boardScale;
double endY = chessboard.startY + (toY*chessboard.SQUARE_SIZE)*chessboard.boardScale;
double stepX = (endX-startX)/250;
double stepY = (endY-startY)/250;
Timer timer = new Timer();
timer.scheduleAtFixedRate(new TimerTask() {
int i = 1;
double currentX = 0;
double currentY = 0;
public void run() {
chessboard.repaintRootPane(getRepaintRectangle());
if(i > 250) {
timer.cancel();
setOverride(0, 0);
} else {
currentX = i * stepX + startX;
currentY = i * stepY + startY;
setOverride(currentX, currentY);
}
chessboard.repaintRootPane(getRepaintRectangle());
i++;
}
}, 2, 2);
}
/**
* Remove the piece
* @param animate animate piece's removal
*/
public void remove(boolean animate) {
chessboard.removePiece(x, y);
if(!animate) return;
Timer timer = new Timer();
scale = .99;
timer.scheduleAtFixedRate(new TimerTask() {
double decrement = .01;
public void run() {
scale -= decrement;
decrement *= 1.1;
if(scale < 0) {
timer.cancel();
scale = 0;
}
chessboard.repaintRootPane(getRepaintRectangle());
}
}, 10, 10);
}
}