用画笔(JPanel)画板之后再画东西(Java)。

3

我正在尝试用Java制作一个非常简单的井字游戏。然而,在绘制棋盘后,我无法弄清楚如何绘制其他内容。这是我的游戏结构。

public class ThreeInARowMain extends JPanel {

    public static final int WIDTH = 600, HEIGHT = 640;

    public void paint(Graphics g) {
        g.setColor(Color.white);
        g.fillRect(0, 0, WIDTH, HEIGHT);
        g.setColor(Color.black);
        g.drawString("1.", 0,20);
        g.drawString("2.", 210,20);
        g.drawString("3.", 410,20);
        g.drawString("4.", 0,220);
        g.drawString("5.", 210,220);
        g.drawString("6.", 410,220);
        g.drawString("7.", 0,420);
        g.drawString("8.", 210,420);
        g.drawString("9.", 410,420);
        //Horizontal Lines
        g.drawLine(0, 200, WIDTH, 200);
        g.drawLine(0, 400, WIDTH, 400);
        //Vertical Lines
        g.drawLine(200, 0, 200, HEIGHT);
        g.drawLine(400, 0, 400, HEIGHT);

    }

    public static void main (String [] args) {
    boolean firstorsecond = true;
        JFrame frame = new JFrame("Tic Tac Toe");
        frame.setSize(WIDTH, HEIGHT);
        frame.getContentPane().add(new ThreeInARowMain());
        frame.setLocationRelativeTo(null);
        frame.setBackground(Color.black);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setVisible(true);
        boolean someonewins = false;
        int firstplayerpos, secondplayerpos;
        int [] [] board = new int [3] [3];
        Scanner in = new Scanner(System.in);

        while (!someonewins){
        System.out.println("P1, enter the number of the square you'd like to mark.");
        firstplayerpos = in.nextInt();
        DrawXorO(firstplayerpos,firstorsecond);


        System.out.println("P2, enter the number of the square you'd like to mark.");
        secondplayerpos = in.nextInt();
        DrawXorO(secondplayerpos,!firstorsecond);

        }
    }

    public static void DrawXorO (int position, boolean firstorsecond) {

    }

}

我知道这个游戏目前设计得很糟糕,我稍后会进行改正。然而,我想要的是在玩家输入位置上画出X或O。在使用paint方法后如何添加图形呢?谢谢!


2
开始阅读AWT和Swing中的绘画执行自定义绘画。不要覆盖paint,而是覆盖paintComponent并确保调用super.paintComponent - MadProgrammer
3个回答

4

但是我不能将Scanner与UI混合使用吗?那么按照我想要的方式构建游戏就行不通了吗?我想做的是让用户在控制台中输入他们想要标记的位置。 - Filip
你可以使用按钮、鼠标点击、文本字段或类似的东西。 - MadProgrammer

2

您是指像这样的东西吗?

井字棋GUI

以下是在GUI左侧绘制井字棋图表的一种方法。我有一个模型类,将棋盘位置存储在二维int数组中,还有一个鼠标控制器类,让我知道人们在井字棋图表上点击的位置。

package com.ggl.tictactoe.view;

import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Rectangle;
import java.awt.Stroke;
import java.awt.font.FontRenderContext;
import java.awt.geom.Rectangle2D;
import java.awt.image.BufferedImage;

import javax.swing.JPanel;

import com.ggl.tictactoe.controller.MouseMoveController;
import com.ggl.tictactoe.model.GameStatus;
import com.ggl.tictactoe.model.TicTacToeModel;

public class TicTacToePanel extends JPanel {

    private static final long serialVersionUID = -9150412950439480699L;

    private MouseMoveController controller;

    private TicTacToeModel model;

    public TicTacToePanel(TicTacToeFrame frame, TicTacToeModel model) {
        this.model = model;
        this.controller = new MouseMoveController(frame, model);
        this.addMouseListener(controller);
        this.setPreferredSize(new Dimension(360, 360));
    }

    public void setComputerMove() {
        if (!model.isPlayerGoesFirst()) {
            controller.setComputerMove();
        }
    }

    @Override
    protected void paintComponent(Graphics g) {
        super.paintComponent(g);

        Graphics2D g2d = (Graphics2D) g;
        g2d.setColor(Color.WHITE);
        g2d.fillRect(0, 0, getWidth(), getHeight());

        int[][] board = model.getBoard();
        int width = getWidth() / board.length;
        int height = getHeight() / board[0].length;

        int x = 0;
        int y = 0;

        Stroke stroke = new BasicStroke(7F);
        g2d.setStroke(stroke);
        g2d.setColor(Color.BLACK);

        x += width;
        for (int i = 0; i < (board.length - 1); i++) {
            g2d.drawLine(x, y, x, getHeight());
            x += width;
        }

        x = 0;
        y += width;
        for (int i = 0; i < (board.length - 1); i++) {
            g2d.drawLine(x, y, getWidth(), y);
            y += width;
        }

        float fontSize = (float) height * 72F / 96F;
        Font largeFont = getFont().deriveFont(fontSize);

        for (int i = 0; i < board.length; i++) {
            x = width * i;
            for (int j = 0; j < board[i].length; j++) {
                y = height * j;
                Rectangle r = new Rectangle(x, y, width, height);
                if (board[i][j] == 1) {
                    g2d.setColor(Color.BLUE);
                    centerString(g2d, r, "X", largeFont);
                } else if (board[i][j] == -1) {
                    g2d.setColor(Color.CYAN);
                    centerString(g2d, r, "O", largeFont);
                }
            }
        }

        if (model.getGameStatus() == GameStatus.TIE_GAME) {
            BufferedImage image = GameOverImage.createImage(getWidth(),
                    getHeight(), "Tie Game");
            g2d.drawImage(image, 0, 0, this);
        } else if (model.getGameStatus() == GameStatus.COMPUTER_WINS) {
            BufferedImage image = GameOverImage.createImage(getWidth(),
                    getHeight(), "Computer Wins");
            g2d.drawImage(image, 0, 0, this);
        } else if (model.getGameStatus() == GameStatus.PLAYER_WINS) {
            BufferedImage image = GameOverImage.createImage(getWidth(),
                    getHeight(), "Player Wins");
            g2d.drawImage(image, 0, 0, this);
        }
    }

    /**
     * This method centers a <code>String</code> in a bounding
     * <code>Rectangle</code>.
     * 
     * @param g2d
     *            - The <code>Graphics2D</code> instance.
     * @param r
     *            - The bounding <code>Rectangle</code>.
     * @param s
     *            - The <code>String</code> to center in the bounding rectangle.
     * @param font
     *            - The display font of the <code>String</code>
     * 
     * @see java.awt.Graphics
     * @see java.awt.Rectangle
     * @see java.lang.String
     */
    private void centerString(Graphics2D g2d, Rectangle r, String s, Font font) {
        FontRenderContext frc = new FontRenderContext(null, true, true);

        Rectangle2D r2D = font.getStringBounds(s, frc);
        int rWidth = (int) Math.round(r2D.getWidth());
        int rHeight = (int) Math.round(r2D.getHeight());
        int rX = (int) Math.round(r2D.getX());
        int rY = (int) Math.round(r2D.getY());

        int a = (r.width / 2) - (rWidth / 2) - rX;
        int b = (r.height / 2) - (rHeight / 2) - rY;

        g2d.setFont(font);
        g2d.drawString(s, r.x + a, r.y + b);
    }

}

这是鼠标控制器的代码。

package com.ggl.tictactoe.controller;

import java.awt.Point;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;

import com.ggl.tictactoe.model.GameStatus;
import com.ggl.tictactoe.model.TicTacToeModel;
import com.ggl.tictactoe.view.TicTacToeFrame;

public class MouseMoveController extends MouseAdapter {

    private ComputerMoveRunnable controller;

    private TicTacToeFrame frame;

    private TicTacToeModel model;

    public MouseMoveController(TicTacToeFrame frame, TicTacToeModel model) {
        this.frame = frame;
        this.model = model;
        this.controller = new ComputerMoveRunnable(frame, model);
    }

    @Override
    public void mousePressed(MouseEvent event) {
        if ((model.getGameStatus() == GameStatus.ACTIVE_GAME)
                && (event.getButton() == MouseEvent.BUTTON1)) {
            int width = frame.getTicTacToePanel().getWidth();
            int height = frame.getTicTacToePanel().getHeight();
            int positionWidth = TicTacToeModel.getPositionWidth();

            Point p = event.getPoint();

            int x = getPosition(p.x, width, positionWidth);
            int y = getPosition(p.y, height, positionWidth);

            int[][] board = model.getBoard();
            if (board[x][y] == 0) {
                model.setPlayerMove(x, y);
                setComputerMove();
            }
        }
    }

    public void setComputerMove() {
        controller.run();
        frame.repaintTicTacToePanel();
    }

    private int getPosition(int location, int dimension, int squareWidth) {
        for (int i = 0; i < squareWidth; i++) {
            if (location < (dimension * (i + 1) / squareWidth)) {
                return i;
            }
        }

        return squareWidth - 1;
    }

}

谢谢。这有点超出我的水平。不过非常有用,值得一看。不过我有一个问题:import com.ggl.tictactoe.model.GameStatus; import com.ggl.tictactoe.model.TicTacToeModel; import com.ggl.tictactoe.view.TicTacToeFrame; - Filip
上面那些是外部包吗? - Filip
@Filip:我使用标准的Swing类编写了井字棋代码。我发布了我为游戏编写的9个类中的2个类。com.ggl导入是我自己的Java包。我将模型代码、视图代码和控制器代码保存在不同的包中。 - Gilbert Le Blanc
我刚刚在Github上发布了所有的Java代码。 - Gilbert Le Blanc

1
我会重新设计你的GUI,利用9个JButton,每个方格一个。然后您可以调用JButton方法,例如JButton.setText(“X”),以使方格显示X,这将更简单。如果您真的想覆盖paintComponent,则可以创建变量来存储每个方格当前显示的内容,更新这些变量并在需要更新时调用repaint()。

谢谢,我确实这样做了,并且完全使用JButtons制作了游戏。它不是最好看的游戏,但它确实可以工作。感谢您的提示,给了我很好的训练。 - Filip
没问题,实际上有很多JButton方法,比如设置背景图片/颜色等,你可以尝试使用它们来让你的GUI看起来更好。 - Lightsout

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接