Java - 在paint方法或单独的线程while循环中进行游戏循环吗?

时间:2014-08-20 03:08:20

标签: java multithreading jpanel paint

我正在尝试编写一个获取用户鼠标输入的应用程序,并在每次单击时绘制一个点(不是那个特别重要)。游戏循环功能应该在哪里,在paint方法中还是在单独的while循环中?这是我的代码:

import java.awt.*;
import java.awt.geom.*;

import javax.swing.*;


@SuppressWarnings("serial")
public class Main extends JPanel{

    static Rectangle scrnSize = GraphicsEnvironment.getLocalGraphicsEnvironment().getMaximumWindowBounds();
    //static Dimension wholeScreenSize = Toolkit.getDefaultToolkit().getScreenSize();
    //public static int taskbarHeight = wholeScreenSize.height - scrnSize.height;

    @Override
    public void paint(Graphics g) {
        Graphics2D g2d = (Graphics2D) g;
        g2d.setColor(Color.RED);
        g2d.fillOval(0, 0, 30, 30);
        g2d.drawOval(0, 50, 30, 30);        
        g2d.fillRect(50, 0, 30, 30);
        g2d.drawRect(50, 50, 30, 30);

        g2d.draw(new Ellipse2D.Double(0, 100, 30, 30));
        //do loop stuff here?
    }

    public static void main(String[] args) throws InterruptedException {
        //init
        JFrame frame = new JFrame("DrillSweet");
        frame.setLayout(new GridLayout());
        Main main = new Main();
        frame.add(main);
        frame.setSize(new Dimension(scrnSize.width, scrnSize.height));
        frame.setPreferredSize(new Dimension(scrnSize.width, scrnSize.height));
        frame.setMaximumSize(new Dimension(scrnSize.width, scrnSize.height));
        frame.setVisible(true);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        //game loop
        while(true){
            //do loop stuff here?
            main.repaint();
            Thread.sleep(10);
        }
    }

}

2 个答案:

答案 0 :(得分:2)

你需要知道的第一件事......

  1. 你不能控制油漆过程,所以不要搞砸它。绘画由RepaintManager完成,您可以向RepaintManager提出有关应该绘制内容的建议,但RepaintManager有责任决定什么时候应该被涂上颜色。
  2. Swing不是一个线程安全的框架。也就是说,UI的所有更新必须在事件调度线程的上下文中完成...请查看Concurrency in Swing以获取更多详细信息...
  3. Swing中的绘画是一系列复杂的方法调用,它们链接在一起产生最终结果,不尊重这个链将导致令人讨厌的绘画文物......
  4. 所以,考虑到所有这些......

    1. 不要在任何可能需要时间执行的paint方法中执行任何操作,包括无限循环,加载资源或使用Thread.sleep
    2. 之类的内容
    3. 如果必须更改UI,请在“事件调度线程”
    4. 的上下文中执行此操作
    5. 致电super.paint或更好,改为覆盖paintComponent(并在进行任何自定义绘画之前致电super.paintComponent
    6. 而不是Thread,根据您的需要,考虑使用Swing Timer,这将允许您安排定期回调,这将在EDT上下文中完成。这将确保一定程度的同步,因为您对UI属性所做的任何更改都不能在任何绘制方法中使用(因为您的回调和paint方法是从同一个线程调用的)并且有助于防止肮脏的油漆...

      您可能还想查看Painting in AWT and SwingInitial Threads以及Should I avoid the use of set(Preferred|Maximum|Minimum)Size methods in Java Swing?以获取更多信息......

答案 1 :(得分:0)

我不是java的专家,但我发现将一个独立的Timer重新绘制,另一个用于计算非常有用。

类似的东西:

ActionListener counter = new ActionListener() 
{
    public void actionPerformed(ActionEvent ev)
    {   
        repaint();
    }
};  
new Timer(40, counter).start();

和另一个计算计时器

ActionListener counter = new ActionListener() 
{
    public void actionPerformed(ActionEvent ev)
    {   
        for(Enemies en: enemies)
        {
            en.moveEnemies();
        }

        turret.moveShoots();
        checkColision();
    }
};  
new Timer(5, counter).start();

有了这个,我确保在计算和恒定游戏速度方面有一定的精确度,而不是拥有良好的fps或流畅的动画。