0

I'm trying to develop a java chess engine using Swing for the GUI and for the last couple of days I've found some setbacks. The engine is already fully functional and works perfectly with click moves (1 click on the Tile-JPanel with the piece you desire to move, another click on the Tile-JPanel where you want to place the piece). Now I'm willing to take it a step further and decided to implement drag and drop moves (click and hold mouse, drag, and release on desired JPanel).

This is where I find my problems. My move class has the following arguments: the chessboard configuration, the starting tile for the move, and the ending tile. It takes the source tile id when I press the mouse, but when I release it, what would be the destination tile id, is instead the source tile id as well. This makes my engine think that I am trying to move the pieces to the same tile resulting in an illegal move. I've tried using destinationTile = chessBoard.getTile(tileId) the same concept I've used for the click moves but it takes de source tile instead. I've tried using TilePanel obj = (TilePanel)e.getSource(); destinationTile = chessBoard.getTile(obj.getTileId()); and with this, both source and destination tile get the value of the piece identifier? So if I try to drag and drop a pawn, they both get "P" as value, if I try to move the queen they get "Q". So yeah, I am completely lost.

The second problem I'm facing is when dragging the Piece-JLabel around, it is limited to the boundaries of the the Tile-JPanel in which it resides. That's was to be expected, so I tried using a JLayeredPane. My approach was, clone the moved piece-JLabel, set the original one to invisible. Add the cloned one to the JLayeredPane.DRAG_LAYER, drag it around following the mouse. And on release, if the given move was legal, place this JLabel on the destination tile JPanel and delete the invisible JLabel on the source tile. This was also to no success, as no matter how I tried to add the JLabel to the DRAG_LAYER I could not get it to work. No matter what I tried, I couldn't get a piece image to follow my cursor around over the board.

Here is the majority of my Tile class with all the MouseEvent Handlers:

private class TilePanel extends JPanel {

        private final int tileId;

        public int getTileId() {
            return tileId;
        }

        TilePanel(final BoardPanel boardPanel, final int tileId) throws IOException {
            super(new GridBagLayout());
            this.tileId = tileId;
            setPreferredSize(TILE_PANEL_DIMENSION);
            assignTileColor();
            assignTilePieceIcon(chessBoard);
            highlightTileBorder(chessBoard);
            addMouseListener(new MouseListener() {

                @Override
                public void mouseClicked(final MouseEvent e) {
                    if(isRightMouseButton(e)) {
                        sourceTile = null;
                        destinationTile = null;
                        humanMovedPiece = null;
                        try {
                            boardPanel.drawBoard(chessBoard);
                        } catch (IOException ioException) {
                            ioException.printStackTrace();
                        }
                        System.out.println("piece deselected");
                    }
                    else if (isLeftMouseButton(e)) {
                        if(sourceTile == null) {
                            //first click
                            sourceTile = chessBoard.getTile(tileId);
                            humanMovedPiece = sourceTile.getPiece();
                            if (humanMovedPiece == null) {
                                sourceTile = null;
                            }
                            System.out.println("piece selected");
                        }
                        else {
                            //second click
                            destinationTile = chessBoard.getTile(tileId);
                            final Move move = Move.MoveFactory.createMove(chessBoard, sourceTile.getTileCoordinate(), destinationTile.getTileCoordinate());
                            final MoveTransition transition = chessBoard.getCurrentPlayer().makeMove(move);
                            if (transition.getMoveStatus() == MoveStatus.DONE) {
                                chessBoard = transition.getTransitionBoard();
                                moveLog.addMove(move);
                                SFXUtils.playSound("move");
                                System.out.println(chessBoard);
                                System.out.println("█████ move done: " + move.toString() + " █████");

                            }
                            sourceTile = null;
                            destinationTile = null;
                            humanMovedPiece = null;

                        }
                        SwingUtilities.invokeLater(new Runnable() {
                            @Override
                            public void run() {
                                try {
                                    gameHistoryPanel.redo(chessBoard, moveLog);
                                    takenPiecesPanel.redo(moveLog);
                                    boardPanel.drawBoard(chessBoard);
                                } catch (IOException ioException) {
                                    ioException.printStackTrace();
                                }
                            }
                        });
                    }
                }

                @Override
                public void mousePressed(final MouseEvent e) {
                    if(sourceTile == null) {
                        //first click
                        sourceTile = chessBoard.getTile(tileId);
                        System.out.println(tileId);
                        System.out.println(sourceTile.getTileCoordinate());
                        humanMovedPiece = sourceTile.getPiece();
                        if (humanMovedPiece == null) {
                            sourceTile = null;
                        }
                        System.out.println("piece selected");
                    }
                    SwingUtilities.invokeLater(new Runnable() {
                        @Override
                        public void run() {
                            try {
                                gameHistoryPanel.redo(chessBoard, moveLog);
                                takenPiecesPanel.redo(moveLog);
                                boardPanel.drawBoard(chessBoard);
                            } catch (IOException ioException) {
                                ioException.printStackTrace();
                            }
                        }
                    });
                }

                @Override
                public void mouseReleased(final MouseEvent e) {

                   /* TilePanel obj = (TilePanel)e.getSource();
                    destinationTile = chessBoard.getTile(obj.getTileId());*/
                    destinationTile = chessBoard.getTile(tileId);

                    final Move move = Move.MoveFactory.createMove(chessBoard, sourceTile.getTileCoordinate(), destinationTile.getTileCoordinate());

                    final MoveTransition transition = chessBoard.getCurrentPlayer().makeMove(move);

                    if (transition.getMoveStatus() == MoveStatus.DONE) {
                        chessBoard = transition.getTransitionBoard();
                        moveLog.addMove(move);
                        SFXUtils.playSound("move");
                        System.out.println(chessBoard);
                        System.out.println("█████ move done: " + move.toString() + " █████");

                    }
                    sourceTile = null;
                    destinationTile = null;
                    humanMovedPiece = null;

                    SwingUtilities.invokeLater(new Runnable() {
                        @Override
                        public void run() {
                            try {
                                gameHistoryPanel.redo(chessBoard, moveLog);
                                takenPiecesPanel.redo(moveLog);
                                boardPanel.drawBoard(chessBoard);
                            } catch (IOException ioException) {
                                ioException.printStackTrace();
                            }
                        }
                    });

                }

                @Override
                public void mouseEntered(final MouseEvent e) {

                }

                @Override
                public void mouseExited(final MouseEvent e) {

                }
            });

            addMouseMotionListener(new MouseMotionListener() {

                @Override
                public void mouseDragged(final MouseEvent e) {
                    System.out.println("im draggin");
                    TilePanel obj = (TilePanel)e.getSource();
                    JLabel draggedPieceImageLabel = (JLabel) obj.getComponent(0);
                    //obj.getComponent(0).setVisible(false);
                    draggedPieceImageLabel.setLocation(e.getX()-25,e.getY()-25);
                    add(draggedPieceImageLabel);
                }

                @Override
                public void mouseMoved(MouseEvent e) {

                }
            });


            validate();
        }
Jason Aller
  • 3,541
  • 28
  • 38
  • 38
  • Your MouseMotionListener is doing `add(draggedPieceImageLabel);`. The dragged piece can’t be in both a JLayeredPane and a TilePanel. You only want it in the JLayeredPane. – VGR Feb 03 '21 at 13:01
  • I remember years ago having exactly this problem. I think my solution was to just use 1 JPanel for the whole board with a gridLayout. You will want to override paintBackground, but in many ways this simplifies things. – ControlAltDel Feb 03 '21 at 13:09
  • Maybe this is appropriate? [Drag and Drop and Data Transfer](https://docs.oracle.com/javase/tutorial/uiswing/dnd/) which is a lesson in the trail entitled _Creating a GUI With JFC/Swing_ which is part of Oracle's Java tutorials. – Abra Feb 03 '21 at 13:16
  • @VGR I failed to mention that the code I posted is the version that is not using the JLayeredPane. When using a JLayeredPane I try adding the JLabel to it but to no avail. I did it like this `boardLayeredPane.add(draggedPieceImageLabel, JLayeredPane.DRAG_LAYER);`, boardLayeredPane default layer was the board. – nunomartinsesilva Feb 03 '21 at 13:42
  • @Abra I will check it out, thank you! – nunomartinsesilva Feb 03 '21 at 13:44
  • @ControlAltDel Yeah, guess that solution will be my go-to. I will try it later today, thank you for your time! – nunomartinsesilva Feb 03 '21 at 13:46
  • *I tried to add the JLabel to the DRAG_LAYER* check out: https://stackoverflow.com/questions/6811247/drawing-in-jlayeredpane-over-exising-jpanels/6811800#6811800 for an example using this approach. – camickr Feb 03 '21 at 15:01
  • @camickr I've spent the last hours fiddling with my project, trying to implement a solution similar to yours, and finally got it to work! I still cannot understand what I was doing wrong, besides hard coding the piece drag motions, but I will investigate it further in the next couple of days. Thank you for the help! – nunomartinsesilva Feb 04 '21 at 11:59

0 Answers0