Hi everyone. I hope this is the right forum to post this.
I'm not really good at java and this is my first project.
I'm trying to make a simple chess program. It's not finished yet. What you basically can do is to move a pawn from one square to another.
I need help on how to structure the code. I find myself mixing a lot of gui stuff with logic but I really don't know how to do it properly. I guess my code is also kind of badly written. I could really use some suggestions on what to do different.
import javax.swing.*; import java.awt.*; import java.awt.event.MouseEvent; import java.awt.event.MouseListener; import java.awt.event.MouseMotionListener; public class Chess extends JFrame { public Piece[] piece = new Piece[32]; private GridBagConstraints c = new GridBagConstraints(); private HandlerClass handler = new HandlerClass(); private int[][] position = new int[8][8]; private JPanel boardPanel = new JPanel(); private JPanel[][] squares = new JPanel[8][8]; private Point hotSpot = new Point(15, 20); private Toolkit toolkit = Toolkit.getDefaultToolkit(); private int[] initCoord = new int[2]; public static void main(String[] args) { new Chess(); } Chess() { setVisible(true); setDefaultCloseOperation(EXIT_ON_CLOSE); JPanel mainPanel = new JPanel(); boardPanel.setLayout(new GridBagLayout()); boardPanel.addMouseListener(handler); mainPanel.setBackground(Color.BLACK); mainPanel.add(boardPanel); add(mainPanel); createBoard(); createPieces(); updatePosition(); // setSize(600, 600); pack(); setResizable(true); } // Grid of JPanel with 8x8 rows and columns which are added to the // boardPanel private void createBoard() { for (int i = 0; i < 8; i++) { for (int j = 0; j < 8; j++) { squares[i][j] = new JPanel(); if (((i & 1) == 0 && (j & 1) == 1) || ((i & 1) == 1 && (j & 1) == 0)) squares[i][j].setBackground(Color.red); else squares[i][j].setBackground(new Color(211, 240, 254)); squares[i][j].setPreferredSize(new Dimension(75, 75)); c.gridx = j; c.gridy = i; c.ipady = 0; c.ipadx = 0; boardPanel.add(squares[i][j], c); // Adds the current squares to // boardPanel } } } // Calls piece class to create pieces. At the moment only white pawns. // The piece constructor needs to know whether piece should be black or white. // A new parameter will be added to fix that (will be done later). private void createPieces() { for (int i = 0; i < 8; i++) { piece[i] = (Piece) new Pawn(i, 1); } } // Updates the positions of the pieces. This method will be initially called and then every time a piece is moved. private void updatePosition() { deletePosition(); // First clear all the all positions, then rebuild the array with updated ones. for (int i = 0; i < 8; i++) { squares[piece[i].getY()][piece[i].getX()].add(piece[i] .getPieceLabel()); storePosition(piece[i].getX(), piece[i].getY(), i); } } // To keep track of where the pieces are, the updatePosition method calls this one with the // current piece's position which is then stored in an 8x8 array. The value corresponding to each index // is the piece number (int k, defined in the createPieces()-method (in that method its called i)) private void storePosition(int i, int j, int k) { position[i][j] = k; } // Array values are by default 0. This is why I need to change them to -1. If I didn't, it would seem like piece[0] would be in every // unoccupied square. private void deletePosition() { for (int i = 0; i < 8; i++) { for (int j = 0; j < 8; j++) { position[i][j] = -1; } } } // Kind of unnecessary because the position[][]-array is "transparent" through the class. private int getPosition(int x, int y) { return position[x][y]; } // MOUSE EVENTS : // Every square is 75x75 pixels. This method returns the square coordinates based on where i click on the board. private int coord(int x) { if (x >= 0 && x < 75) { x = 0; } else if (x >= 75 && x < 150) { x = 1; } else if (x >= 150 && x <= 225) { x = 2; } else if (x >= 225 && x <= 300) { x = 3; } else if (x >= 300 && x <= 375) { x = 4; } else if (x >= 375 && x <= 450) { x = 5; } else if (x >= 450 && x <= 525) { x = 6; } else if (x >= 525 && x <= 600) { x = 7; } return x; } // Store initial positions of moving piece private void storeInit(int x, int y) { initCoord = new int[2]; initCoord[0] = x; initCoord[1] = y; } private class HandlerClass implements MouseListener, MouseMotionListener { boolean test = false; @Override public void mouseDragged(MouseEvent e) { // TODO Auto-generated method stub } @Override public void mouseMoved(MouseEvent e) { // TODO Auto-generated method stub } @Override public void mouseClicked(MouseEvent e) { } @Override public void mouseEntered(MouseEvent e) { // TODO Auto-generated method stub } @Override public void mouseExited(MouseEvent e) { // TODO Auto-generated method stub } @Override public void mousePressed(MouseEvent e) { int x = coord(e.getX()); //Calls the coord() method to convert coordinates on the board to square coordinates int y = coord(e.getY()); if (position[x][y] != -1) { setCursor(toolkit.createCustomCursor(piece[position[x][y]] .getIcon().getImage(), hotSpot, "")); // "Drag and drop": change cursor to piece image piece[position[x][y]].getPieceLabel().setVisible(false); // then hide the piece until dropped on new square (see mouseReleased()) storeInit(x, y); test = true; } } @Override public void mouseReleased(MouseEvent e) { int x = coord(e.getX()); int y = coord(e.getY()); setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR)); // Set default cursor as soon as mouse is released if (test) { // If there was a piece to move, set that piece to its new coordinates piece[getPosition(initCoord[0], initCoord[1])].setX(x); // Here is where the storeInit() method comes in. piece[getPosition(initCoord[0], initCoord[1])].setY(y); piece[getPosition(initCoord[0], initCoord[1])].getPieceLabel() .setVisible(true); updatePosition(); repaint(); test = false; } } } }
Piece class:
import javax.swing.ImageIcon; import javax.swing.JLabel; public abstract class Piece { public abstract int getX(); public abstract int getY(); public abstract String getType(); public abstract ImageIcon getIcon(); public abstract JLabel getPieceLabel(); public abstract void setX(int x); public abstract void setY(int y); }
Pawn class:
import javax.swing.ImageIcon; import javax.swing.JLabel; public class Pawn extends Piece { private int x; private int y; private ImageIcon icon; private JLabel pieceHolder; public Pawn(int x, int y) { this.x = x; this.y = y; this.icon = new ImageIcon("PATH_TO_IMAGE"); // REPLACE WITH IMAGE PATH this.pieceHolder = new JLabel(); this.pieceHolder.setIcon(icon); } @Override public int getX() { return this.x; } @Override public int getY() { return this.y; } @Override public String getType() { return "Pawn"; } @Override public ImageIcon getIcon() { return this.icon; } public JLabel getPieceLabel() { return this.pieceHolder; } @Override public void setX(int x) { this.x = x; } @Override public void setY(int y) { this.y = y; } }
To run program, you need an image of a pawn (or whatever you want to use instead). I used this one http://upload.wikimedia.org/wikipedi..._plt45.svg.png - download and then in the Pawn class: this.icon = new ImageIcon("PATH_TO_IMAGE"); (for some reason i had to put the whole path, even if the image was in the same folder as the class-file).
Oh, and one more question: Should I make a new class for the rules (to see if a move is valid, castleing, en passant etc) or is it better to do this in each piece's class?