Java游戏循环和按钮的图形问题

3
我正在制作一个包含游戏面板的游戏,其中游戏循环绘制游戏。它还包含一个面板,该面板有一个按钮来启动游戏循环。游戏面板的背景只应在游戏开始时绘制一次。这是因为游戏图形不应在每次重绘时被清除。我遇到了两个问题,一个是背景没有初始绘制,另一个是启动循环的按钮被绘制在游戏面板上。
我试图将问题简化为最简单的形式,以下是我的尝试内容:
public class Graphics_Trouble extends JFrame
{
    private MainPanel mainPanel = new MainPanel();
    private JPanel menuPanel = new JPanel();
    private JButton start = new JButton("Start");

    public Graphics_Trouble()
    {
        start.addActionListener(new java.awt.event.ActionListener()
        {
            @Override
            public void actionPerformed(java.awt.event.ActionEvent evt)
            {
                StartActionPerformed(evt);
            }
        });
        menuPanel.add(start);
        add(menuPanel, BorderLayout.PAGE_START);
        add(mainPanel, BorderLayout.CENTER);
        pack();
        setVisible(true);
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    }
    private void StartActionPerformed(java.awt.event.ActionEvent evt)
    {
        mainPanel.start();
    }
    public static void main(String[] args)
    {
        java.awt.EventQueue.invokeLater(new Runnable()
        {
            @Override
            public void run()
            {
                new Graphics_Trouble().setVisible(true);
            }
        });
    }
}
class MainPanel extends JPanel
{
    private Timer timer;
    private boolean first = true;
    public MainPanel()
    {
        timer = new Timer(30, new ActionListener()
        {
            public void actionPerformed(ActionEvent e)
            {
                timedAction();
            }
        });
    }
    @Override
    public Dimension getPreferredSize()
    {
        Dimension size = new Dimension(300, 400);
        return size;
    }
    @Override
    public void paintComponent(Graphics g)
    {
        if(first)
        {
            g.setColor(Color.black);
            g.fillRect(0, 0, 300, 400);
        }
        first = false;
    }
    public void timedAction()
    {
        repaint();
    }
    public void start()
    {
        timer.start();
    }
}

运行代码后,会出现一个带有“开始”按钮的框架,但没有颜色。当按下“开始”按钮时,按钮会被绘制到另一个面板上,这不是我想要的。

谢谢。


请包含所有导入,这样更容易将您的代码复制并粘贴到我们的编译器中,以查看您的代码的结果。 - FailingCoder
“...按钮开始循环被绘制在游戏面板上”——这立即提示我您在paintComponent覆盖中没有调用super.paintComponent(g);。不要犯这个错误——一定要调用该方法。 - Hovercraft Full Of Eels
此外,我不建议仅绘制一次背景。尝试不断地在上一帧上绘制;本质上,每次你都要将背景涂在所有东西上,并绘制部分和其他内容。 - FailingCoder
1个回答

5

你的绘画有误

  • 不仅仅是第一次,每次都需要绘制背景。因此,创建一个BufferedImage,将背景绘制到图像中(仅一次),然后在paintComponent中绘制图像。
  • 始终首先调用super.paintComopnent(g);以覆盖您自己的方法,否则您将看到一些伪影,例如按钮的图像,就像您现在看到的那样。
  • 确保您的计时器侦听器比目前更“聪明”。对象的状态应该从计时器而不是绘画方法中改变。绘画方法只应反映对象的状态,而不是改变它。

另外:

  • 不要将相同的组件添加两次到GUI中。仅添加一次。
  • 如果背景图像仅用于绘制统一颜色的背景-填充JPanel,则可以在JPanel的构造函数中直接调用setBackground(Color.BLACK);

例如:

@SuppressWarnings("serial")
public class MainPanel2 extends JPanel {
    private static final int PREF_W = 300;
    private static final int PREF_H = 400;
    private static final Color RECT_COLOR = Color.BLACK;
    private static final Color COLOR1 = Color.pink;
    private static final Color COLOR2 = new Color(158, 185, 212);
    private BufferedImage background;

    public MainPanel2() {
        background = new BufferedImage(PREF_W, PREF_H, BufferedImage.TYPE_INT_ARGB);
        Graphics2D g2 = background.createGraphics();
        g2.setPaint(new GradientPaint(0, 0, COLOR1, 20, 20, COLOR2, true));
        g2.fillRect(0, 0, PREF_W, PREF_H);
        g2.dispose();
    }

    @Override
    protected void paintComponent(Graphics g) {
        super.paintComponent(g);
        if (background != null) {
            g.drawImage(background, 0, 0, this);
        }

        // do your other drawing here
    }

    @Override
    public Dimension getPreferredSize() {
        if (isPreferredSizeSet()) {
            return super.getPreferredSize();
        }
        return new Dimension(PREF_W, PREF_H);
    }

    // timer code

}

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