当前位置:首页 > 后端开发 > 正文

Java棋盘绘制棋子技巧,Java实现棋子棋盘绘制,快速实现Java棋盘棋子绘制

在Java中绘制棋盘和棋子,通常使用Swing或JavaFX的绘图功能,通过重写组件的 paintComponent()方法,利用Graphics2D对象绘制棋盘网格和圆形棋子,棋子坐标需根据网格尺寸计算,通过 fillOval()在指定位置渲染棋子颜色实现落子效果。

Java棋盘棋子绘制教程:实现图形化棋盘与落子功能

在Java中创建棋盘并在其上绘制棋子是一个常见的图形界面编程任务,本教程将详细介绍实现方法,涵盖Swing组件的使用、绘图技术和交互事件处理。

实现思路

我们将采用以下技术方案:

  • 使用JFrame创建主窗口
  • 自定义JPanel作为棋盘绘制区域
  • 重写paintComponent方法绘制棋盘和棋子
  • 使用鼠标事件监听器实现交互式落子
  • 设计美观的UI界面增强用户体验

完整代码实现

import javax.swing.*;
import java.awt.*;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.geom.Ellipse2D;
import java.util.ArrayList;
import java.util.List;
public class ChessBoard extends JFrame {
    // 棋盘设置
    private static final int BOARD_SIZE = 15; // 15x15的棋盘
    private static final int GRID_SIZE = 40;  // 每个格子的像素大小
    private static final int MARGIN = 50;     // 边距
    private static final int WINDOW_SIZE = 2 * MARGIN + (BOARD_SIZE - 1) * GRID_SIZE;
    // 棋子数据
    private enum Piece { EMPTY, BLACK, WHITE }
    private Piece[][] board = new Piece[BOARD_SIZE][BOARD_SIZE];
    private List<Point> moveHistory = new ArrayList<>();
    private Color boardColor = new Color(220, 179, 92); // 棋盘木质颜色
    private boolean isBlackTurn = true; // 当前落子方(黑子先行)
    private JLabel statusLabel; // 状态标签
    public ChessBoard() {
        setTitle("Java 棋盘棋子绘制");
        setSize(WINDOW_SIZE, WINDOW_SIZE + 60); // 额外高度用于状态栏
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        setLocationRelativeTo(null); // 居中显示
        // 初始化棋盘
        for (int i = 0; i < BOARD_SIZE; i++) {
            for (int j = 0; j < BOARD_SIZE; j++) {
                board[i][j] = Piece.EMPTY;
            }
        }
        // 创建棋盘面板
        BoardPanel boardPanel = new BoardPanel();
        boardPanel.addMouseListener(new MouseAdapter() {
            @Override
            public void mouseClicked(MouseEvent e) {
                // 计算点击位置对应的棋盘坐标
                int x = (e.getX() - MARGIN + GRID_SIZE / 2) / GRID_SIZE;
                int y = (e.getY() - MARGIN + GRID_SIZE / 2) / GRID_SIZE;
                // 确保坐标在有效范围内且该位置没有棋子
                if (x >= 0 && x < BOARD_SIZE && y >= 0 && y < BOARD_SIZE && board[x][y] == Piece.EMPTY) {
                    board[x][y] = isBlackTurn ? Piece.BLACK : Piece.WHITE;
                    moveHistory.add(new Point(x, y));
                    isBlackTurn = !isBlackTurn; // 切换玩家
                    updateStatus();
                    boardPanel.repaint(); // 重绘棋盘
                }
            }
        });
        // 创建状态标签
        statusLabel = new JLabel(" ", JLabel.CENTER);
        statusLabel.setFont(new Font("微软雅黑", Font.BOLD, 16));
        statusLabel.setForeground(new Color(50, 50, 50));
        statusLabel.setOpaque(true);
        statusLabel.setBackground(new Color(240, 240, 240));
        updateStatus();
        // 添加组件
        setLayout(new BorderLayout());
        add(boardPanel, BorderLayout.CENTER);
        add(statusLabel, BorderLayout.SOUTH);
        // 添加重置按钮
        JButton resetButton = new JButton("重新开始");
        resetButton.setFont(new Font("微软雅黑", Font.PLAIN, 14));
        resetButton.setBackground(new Color(70, 130, 180));
        resetButton.setForeground(Color.WHITE);
        resetButton.addActionListener(e -> resetGame());
        JPanel buttonPanel = new JPanel();
        buttonPanel.add(resetButton);
        add(buttonPanel, BorderLayout.NORTH);
    }
    private void updateStatus() {
        String player = isBlackTurn ? "黑方" : "白方";
        statusLabel.setText(player + "回合 | 落子位置: " + 
                          (moveHistory.isEmpty() ? "无" : formatPoint(moveHistory.get(moveHistory.size()-1))));
    }
    private String formatPoint(Point p) {
        char col = (char)('A' + p.x);
        return String.format("%c%d", col, p.y + 1);
    }
    private void resetGame() {
        for (int i = 0; i < BOARD_SIZE; i++) {
            for (int j = 0; j < BOARD_SIZE; j++) {
                board[i][j] = Piece.EMPTY;
            }
        }
        moveHistory.clear();
        isBlackTurn = true;
        updateStatus();
        repaint();
    }
    // 自定义棋盘绘制面板
    private class BoardPanel extends JPanel {
        @Override
        protected void paintComponent(Graphics g) {
            super.paintComponent(g);
            Graphics2D g2d = (Graphics2D) g;
            g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
            // 绘制棋盘背景
            g2d.setColor(boardColor);
            g2d.fillRect(0, 0, getWidth(), getHeight());
            // 绘制网格线
            g2d.setColor(Color.BLACK);
            for (int i = 0; i < BOARD_SIZE; i++) {
                int startX = MARGIN + i * GRID_SIZE;
                int startY = MARGIN;
                int endY = MARGIN + (BOARD_SIZE - 1) * GRID_SIZE;
                // 竖线
                g2d.drawLine(startX, startY, startX, endY);
                // 横线
                int startY2 = MARGIN + i * GRID_SIZE;
                int endX = MARGIN + (BOARD_SIZE - 1) * GRID_SIZE;
                g2d.drawLine(MARGIN, startY2, endX, startY2);
            }
            // 绘制天元和星位
            drawBoardMarkers(g2d);
            // 绘制棋子
            for (int i = 0; i < BOARD_SIZE; i++) {
                for (int j = 0; j < BOARD_SIZE; j++) {
                    if (board[i][j] != Piece.EMPTY) {
                        drawPiece(g2d, i, j);
                    }
                }
            }
        }
        private void drawBoardMarkers(Graphics2D g2d) {
            g2d.setColor(Color.BLACK);
            int center = BOARD_SIZE / 2;
            int size = 8;
            // 绘制九个星位
            int[] points = {3, center, BOARD_SIZE - 4};
            for (int x : points) {
                for (int y : points) {
                    g2d.fillOval(
                        MARGIN + x * GRID_SIZE - size/2,
                        MARGIN + y * GRID_SIZE - size/2,
                        size, size
                    );
                }
            }
        }
        private void drawPiece(Graphics2D g2d, int x, int y) {
            int centerX = MARGIN + x * GRID_SIZE;
            int centerY = MARGIN + y * GRID_SIZE;
            int radius = GRID_SIZE / 2 - 2;
            if (board[x][y] == Piece.BLACK) {
                // 绘制黑色棋子(带光泽效果)
                GradientPaint gradient = new GradientPaint(
                    centerX - radius/2, centerY - radius/2, Color.DARK_GRAY,
                    centerX + radius/2, centerY + radius/2, Color.BLACK
                );
                g2d.setPaint(gradient);
                g2d.fill(new Ellipse2D.Double(centerX - radius, centerY - radius, radius*2, radius*2));
                // 绘制光泽
                g2d.setColor(new Color(255, 255, 255, 150));
                g2d.fillOval(centerX - radius/3, centerY - radius/3, radius/2, radius/3);
            } else {
                // 绘制白色棋子(带阴影效果)
                g2d.setColor(Color.WHITE);
                g2d.fill(new Ellipse2D.Double(centerX - radius, centerY - radius, radius*2, radius*2));
                // 绘制边框和阴影
                g2d.setColor(new Color(150, 150, 150));
                g2d.setStroke(new BasicStroke(1.5f));
                g2d.drawOval(centerX - radius, centerY - radius, radius*2, radius*2);
                // 底部阴影
                g2d.setColor(new Color(200, 200, 200));
                g2d.drawArc(centerX - radius, centerY - radius, radius*2, radius*2, 200, 140);
            }
        }
    }
    public static void main(String[] args) {
        SwingUtilities.invokeLater(() -> {
            new ChessBoard().setVisible(true);
        });
    }
}

关键实现解析

棋盘网格绘制

通过计算棋盘位置,使用drawLine方法在面板上绘制横线和竖线:

Java棋盘绘制棋子技巧,Java实现棋子棋盘绘制,快速实现Java棋盘棋子绘制  第1张

for (int i = 0; i < BOARD_SIZE; i++) {
    int startX = MARGIN + i * GRID_SIZE;
    // 绘制竖线
    g2d.drawLine(startX, startY, startX, endY);
    // 绘制横线
    g2d.drawLine(MARGIN, startY2, endX, startY2);
}

棋子绘制技术

使用Ellipse2D.Double绘制圆形棋子,并添加渐变和光泽效果增强视觉效果:

黑色棋子:

GradientPaint gradient = new GradientPaint(
    centerX - radius/2, centerY - radius/2, Color.DARK_GRAY,
    centerX + radius/2, centerY + radius/2, Color.BLACK
);
g2d.setPaint(gradient);
g2d.fill(new Ellipse2D.Double(centerX - radius, centerY - radius, radius*2, radius*2));

白色棋子:

g2d.setColor(Color.WHITE);
g2d.fill(new Ellipse2D.Double(centerX - radius, centerY - radius, radius*2, radius*2));

鼠标交互实现

通过添加鼠标事件监听器实现点击落子功能:

boardPanel.addMouseListener(new MouseAdapter() {
    @Override
    public void mouseClicked(MouseEvent e) {
        // 计算点击位置对应的棋盘坐标
        int x = (e.getX() - MARGIN + GRID_SIZE / 2) / GRID_SIZE;
        int y = (e.getY() - MARGIN + GRID_SIZE / 2) / GRID_SIZE;
        // 落子逻辑
        if (isValidPosition(x, y)) {
            board[x][y] = isBlackTurn ? Piece.BLACK : Piece.WHITE;
            // 更新界面状态
        }
    }
});

游戏状态管理

使用二维数组存储棋盘状态,记录落子历史:

private Piece[][] board = new Piece[BOARD_SIZE][BOARD_SIZE];
private List<Point> moveHistory = new ArrayList<>();

使用指南

  1. 运行程序后,将显示一个15×15的围棋棋盘
  2. 黑色方先行,点击交叉点放置棋子
  3. 落子后自动切换玩家
  4. 状态栏显示当前回合信息
  5. 点击”重新开始”按钮重置棋盘

扩展建议

  1. 游戏规则实现:添加围棋规则判定(如提子、禁着点等)
  2. 保存/加载功能:实现棋局保存和读取
  3. AI对手:添加简单的人工智能实现人机对战
  4. 网络对战:通过Socket编程实现网络对战功能

此实现使用了Java Swing框架进行图形界面开发,遵循了面向对象的设计原则,代码结构清晰,可扩展性强。

参考资料

  1. Java官方Swing教程:https://docs.oracle.com/javase/tutorial/uiswing/
  2. Java 2D图形编程指南:https://docs.oracle.com/javase/tutorial/2d/index.html
  3. 《Java核心技术卷I》第10章 – 图形程序设计

本文提供的代码在Java 8及以上环境测试通过,使用Swing图形库实现棋盘棋子的绘制和交互功能。

0