2

我正在尝试使用线程在小程序中移动一个球,但它没有移动。任何人都可以帮助我作为小程序的新手并继续进行游戏开发..这里是我的代码供参考

public class ballGame extends JApplet implements Runnable
{
    int x_pos=50;
    int y_pos=100;
    int rad=10;
    Thread t;

    public void start() 
    {
        super.start();
        t=new Thread("t");
        t.start();
    }

    public void paint(Graphics g) 
    {
        super.paint(g);
        g.setColor(Color.red);
        setBackground(Color.BLACK);
        g.drawOval(x_pos,y_pos,2*rad,2*rad); 

        while(true)
        {
            x_pos++;

            //validate();
            repaint();

            try
            {
                Thread.sleep(100);
            }
            catch(Exception e)
            {
                e.printStackTrace();
            }

        }//end of while
    }//end of paint()
}
4

6 回答 6

2

有一个无限循环paint 意味着无法完成该方法的单次传递。

此外,您永远不应该调用Thread.sleep(100)paint方法。这会阻塞EDT并降低性能。

而是使用Swing Timer来进行更新和重绘工作。我也将子类 aJComponent并覆盖paintComponent

于 2013-01-22T10:18:04.853 回答
2

Swing 是一个单线程环境。也就是说,所有更新和交互都在单个线程中执行。Swing 也不是线程安全的。这意味着对 UI 的所有更新都必须在该线程(事件调度线程或 ETD)的上下文中执行。

任何阻止 EDT 的代码都会阻止它(除其他外)重新绘制 UI 并响应用户的输入。

您的绘制代码将永远不会更新屏幕,实际上它会使您的应用程序看起来“挂起”,因为该paint方法不允许完成并且阻塞了 ETD。

paint方法被调用后会快速返回,并且可能会快速连续重复调用,这是一个例外。

一般来说,aThread可能有点过头了,javax.swing.Timer在这种情况下,像 a 这样的东西会更合适。

在此处输入图像描述

public class AnimatedBoat {

    public static void main(String[] args) {
        new AnimatedBoat();
    }

    public AnimatedBoat() {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                try {
                    UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
                } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
                }

                JFrame frame = new JFrame("Test");
                frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                frame.setLayout(new BorderLayout());
                frame.add(new AnimationPane());
                frame.pack();
                frame.setLocationRelativeTo(null);
                frame.setVisible(true);
            }

        });
    }

    public class AnimationPane extends JPanel {

        private BufferedImage boat;
        private int xPos = 0;
        private int direction = 1;

        public AnimationPane() {
            try {
                boat = ImageIO.read(new File("boat.png"));
                Timer timer = new Timer(40, new ActionListener() {
                    @Override
                    public void actionPerformed(ActionEvent e) {
                        xPos += direction;
                        if (xPos + boat.getWidth() > getWidth()) {
                            xPos = getWidth() - boat.getWidth();
                            direction *= -1;
                        } else if (xPos < 0) {
                            xPos = 0;
                            direction *= -1;
                        }
                        repaint();
                    }

                });
                timer.setRepeats(true);
                timer.setCoalesce(true);
                timer.start();
            } catch (IOException ex) {
                ex.printStackTrace();
            }
        }

        @Override
        public Dimension getPreferredSize() {
            return boat == null ? super.getPreferredSize() : new Dimension(boat.getWidth() * 4, boat.getHeight());
        }

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

            int y = getHeight() - boat.getHeight();
            g.drawImage(boat, xPos, y, this);

        }

    }

}

作为旁注。您应该很少需要覆盖像orpaint这样的顶级容器的方法,虽然这样做有很多充分的理由,但您最感兴趣的一个事实是它们不是双缓冲的,这意味着当屏幕更新时,您可能会看到闪烁。JAppletJFrame

最好使用类似的东西JPanel并覆盖它的paintComponent方法。

看一眼

了解更多信息

nb 虽然我在JFrame示例中使用了 a ,但将动画面板放入 a 将是一件简单的事情JApplet,这是您不需要/不想从顶级容器扩展的另一个原因;)

于 2013-01-22T10:49:03.007 回答
1

您不能在paint() 中调用repaint() 方法。而且你不能在paint() 方法中组织无限循环——这样做,你会阻止在你的小程序中绘图。

于 2013-01-22T10:17:35.447 回答
0

在 Runnable 的 run 方法中有 while 循环。

更新:

在 start 方法中有这个。

t=new Thread(this);
t.start();
于 2013-01-22T10:19:00.370 回答
0

x_pos是一个 int 值,因此它通过值而不是引用传递给方法。这就是为什么当你改变它的值时,你圈内的值不会更新......

于 2013-01-22T10:19:26.363 回答
0

You create a Thread without a run() method. This method should contain the runnable code... Furthermore, the paint() method is to paint stuff, not update stuff!

So move your while loop from the paint() method into the run() method of your thread:

t=new Thread("t") {
    @Override
    public void run()
    {
        while(true)
        {
            x_pos++;

            //validate();
            repaint();

            try
            {
                Thread.sleep(100);
            }
            catch(Exception e)
            {
                e.printStackTrace();
            }
        }//end of while
    }
};

Note that ballGame does not require the implement Runnable part. As the thread you created will provide it.

于 2013-01-22T10:23:43.533 回答