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を使用して、更新と再描画作業を行います。JComponentまた、 aと overrideをサブクラス化します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);

        }

    }

}

補足として。またはのpaintようなトップレベルのコンテナのメソッドをオーバーライドする必要はめったにありません。これには多くの正当な理由がありますが、最も関心のあるのは、それらがダブルバッファリングされていないという事実です。画面が更新されると、ちらつきが発生する可能性があります。JAppletJFrame

のようなものを使用して、代わりにそのメソッドJPanelをオーバーライドすることをお勧めします。paintComponent

を見てみましょう

詳細については

nbJFrame私の例では を使用しましたが、アニメーション パネルを取得して に配置するのは簡単なことJAppletです。これが、最上位のコンテナから拡張する必要がない、または拡張したくないもう 1 つの理由です ;)

于 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

run()メソッドなしでスレッドを作成します。このメソッドには、実行可能なコードが含まれている必要があります...さらに、paint()メソッドは更新ではなく描画です!

したがって、while ループをメソッドからpaint()スレッドのrun()メソッドに移動します。

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
    }
};

ballGameその部分を必要としないことに注意してくださいimplement Runnable。作成したスレッドがそれを提供します。

于 2013-01-22T10:23:43.533 に答える