1

我正在制作一个带有 GUI 的 A* 寻路应用程序。我有:

- 一个枚举 TileType

START(Color.GREEN), 
WALL(Color.BLACK),
BLANK(new Color(240, 240, 240)),
END(Color.RED);

- 一个网格类

public class Grid extends JPanel {

    private final Color lineColour = new Color(200, 200, 200);
    private Color defaultColour;
    private final int pixelsPerTile;
    private final int rows;
    private final int columns;
    private TileType[][] tiles;

    public Grid(int rows, int columns, int pixelsPerTile) {
        this.pixelsPerTile = pixelsPerTile;
        this.rows = rows;
        this.columns = columns;
        this.tiles = new TileType[rows][columns];
        this.setPreferredSize(new Dimension(rows * pixelsPerTile, columns * pixelsPerTile));
        setTile(rows / 2 - 5, columns / 2, TileType.START);
        setTile(rows / 2 + 5, columns / 2, TileType.END);
    }

    public void resetBoard() {
        for (int i = 0; i < tiles.length; i++) {
            for (int j = 0; j < tiles[0].length; j++) {
                if (getTile(i, j) != TileType.START && getTile(i, j) != TileType.END) {
                    tiles[i][j] = null;
                }
            }
        }
    }

    public void removeTile(int x, int y) {
        tiles[x][y] = TileType.BLANK;
    }

    public TileType getTile(int x, int y) {
        return tiles[x][y];
    }

    public Point getTile(boolean start) {
        for (int x = 0; x < tiles.length; x++) {
            for (int y = 0; y < tiles[0].length; y++) {
                if (tiles[x][y] == (start ? TileType.START : TileType.END)) {
                    return new Point(x, y);
                }
            }
        }
        return null;
    }

    public void setTile(int x, int y, TileType tile) {
        if (getTile(x, y) != TileType.START && getTile(x, y) != TileType.END) {
            tiles[x][y] = tile;
        }
    }

    @Override
    public void paint(Graphics g1) {
        Graphics2D g = (Graphics2D) g1;
        for (int x = 0; x < columns; x++) {
            for (int y = 0; y < columns; y++) {
                if (getTile(x, y) != null) {
                    g.setColor(getTile(x, y).getColour());
                    g.fillRect(x * pixelsPerTile, y * pixelsPerTile, pixelsPerTile, pixelsPerTile);
                }
            }
        }
        // have the grid appear on top of blank tiles
        g.setColor(lineColour);
        for (int x = 0; x < columns; x++) {
            for (int y = 0; y < rows; y++) {
                g.drawLine(x * pixelsPerTile, 0, x * pixelsPerTile, getHeight());
                g.drawLine(0, y * pixelsPerTile, getWidth(), y * pixelsPerTile);
            }
        }
    }

    public int getPixelsPerTile() {
        return pixelsPerTile;
    }

    public int getRows() {
        return rows;
    }

    public int getColumns() {
        return columns;
    }
}

- 框架类

public class Frame extends JFrame {

    private Grid grid;

    public Frame() {
        grid = new Grid(33, 33, 15); // odd so there is a definitive middle point
        this.setAutoRequestFocus(true);
        this.setDefaultCloseOperation(EXIT_ON_CLOSE);
        this.setTitle("A* Path finder");
        this.setBounds(new Rectangle((grid.getRows()) * grid.getPixelsPerTile(),
                                (grid.getColumns() + 2) * grid.getPixelsPerTile()));
        this.setResizable(true);
        this.add(grid);
        this.setVisible(true);
        this.getContentPane().addMouseListener(new MouseLsntr()); // fixes alignment problems
        ScheduledThreadPoolExecutor se = new ScheduledThreadPoolExecutor(5);
        se.scheduleAtFixedRate(new RedrawGrid(), 0L, 20L, TimeUnit.MILLISECONDS);
    }

    private class RedrawGrid implements Runnable {
        @Override
        public void run() {
            grid.repaint();
        }
    }

    private class MouseLsntr implements MouseListener {
        @Override
        public void mouseClicked(MouseEvent me) {
            int x = me.getX() / grid.getPixelsPerTile();
            int y = me.getY() / grid.getPixelsPerTile();
            switch (me.getButton()) {
                case MouseEvent.BUTTON1:
                    if (grid.getTile(x, y) != TileType.WALL) {
                        grid.setTile(x, y, TileType.WALL);
                        System.out.println(String.format("(%d, %d) (%d, %d) wall", x, y, x, y));
                    } else {
                        grid.removeTile(x, y);
                        System.out.println(String.format("(%d, %d) (%d, %d) blank", x, y, x, y));
                    }
                    break;
            }
        }

        @Override
        public void mousePressed(MouseEvent me) {}

        @Override
        public void mouseReleased(MouseEvent me) {}

        @Override
        public void mouseEntered(MouseEvent me) {}

        @Override
        public void mouseExited(MouseEvent me) {}        
    }
}
  • 显然是一个调用 Frame() 的主类

当用户左键单击网格时,他们会在该位置创建一个墙。如果它已经是一堵墙,它就会变成空白。我希望用户能够通过单击它然后拖动到他们想要停止的位置来移动 START 和 END 磁贴,但我无法做到这一点。任何帮助将不胜感激,因为我已经为此困惑了一段时间。

4

1 回答 1

0

您将需要在接口中实现mousePressedmouseReleased处理程序,并在.MouseListenermouseDraggedMouseMotionListener

首先,创建您的MouseLsntr扩展MouseAdapter类,该类MouseListener默认实现MouseMotionListener

private class MouseLsntr extends MouseAdapter {
    private int dragStartX, dragStartY;
    private boolean dragging;

    @Override
    public void mouseClicked(MouseEvent me) {
        int x = me.getX() / grid.getPixelsPerTile();
        int y = me.getY() / grid.getPixelsPerTile();
        switch (me.getButton()) {
            case MouseEvent.BUTTON1:
                if (grid.getTile(x, y) != TileType.WALL) {
                    grid.setTile(x, y, TileType.WALL);
                    System.out.println(String.format("(%d, %d) (%d, %d) wall", x, y, x, y));
                } else {
                    grid.removeTile(x, y);
                    System.out.println(String.format("(%d, %d) (%d, %d) blank", x, y, x, y));
                }
                break;
        }
    }

    @Override
    public void mousePressed(MouseEvent me) {
        switch (me.getButton()) {
            case MouseEvent.BUTTON1:
                // Save the drag starting position.
                this.dragStartX = me.getX() / grid.getPixelsPerTile();
                this.dragStartY = me.getY() / grid.getPixelsPerTile();
                this.dragging = true;

                break;
        }
    }

    @Override
    public void mouseReleased(MouseEvent me) {
        switch (me.getButton()) {
            case MouseEvent.BUTTON1:
                if (this.dragging) {
                    moveTile(me);
                }
                this.dragging = false;

                break;
        }
    }

    @Override
    public void mouseExited(MouseEvent me) {
        this.dragging = false;
    }

    @Override
    public void mouseDragged(MouseEvent me) {
        if (this.dragging) {
            moveTile(me);
        }
    }

    private void moveTile(MouseEvent me) {
        int dragEndX = me.getX() / grid.getPixelsPerTile();
        int dragEndY = me.getY() / grid.getPixelsPerTile();

        TileType dragStartType = grid.getTile(this.dragStartX, this.dragStartY);
        TileType dragEndType = grid.getTile(dragEndX, dragEndY);
        // If the starting tile was either START or END, move the tile to the destination.
        if ((dragEndType == TileType.BLANK || dragEndType == null) &&
            (dragStartType == TileType.START || dragStartType == TileType.END)) {

            grid.removeTile(this.dragStartX, this.dragStartY);
            grid.setTile(dragEndX, dragEndY, dragStartType);

            // update the drag starting points
            this.dragStartX = dragEndX;
            this.dragStartY = dragEndY;
        }
    }
}

接下来,也添加您的MouseLsntr实例MouseMotionListener,以便mouseDragged在您拖动时调用该处理程序。请注意,您不应创建 的两个单独实例MouseLsntr,因为成员字段应该是共享的。您应该在Frame()构造函数中执行以下操作。

    MouseLsntr listener = new MouseLsntr();
    this.getContentPane().addMouseListener(listener);
    this.getContentPane().addMouseMotionListener(listener);

完成此操作后,TileType.START / TileType.END 瓷砖将在拖动时跟随鼠标。

于 2013-08-27T17:55:48.237 回答