在绘画中使用thread.sleep方法

时间:2015-03-21 18:10:21

标签: java multithreading concurrency

我有一个工作代码,基本上可以在屏幕上绘制15个可以拖动的矩形。我做了这样,随着时间的推移,矩形落到了屏幕的底部。虽然我有更大的数字,如500的thread.sleep方法,我仍然可以拖动屏幕周围的矩形,因为它们没有问题。但是当我开始将thread.sleep方法减少到较小的数字(例如50)时,突然出现了问题。诸如我之前的问题只能在矩形开始向我没有拖动它们的位置开始毛刺之前拖动到2个矩形。有时我只能拖动到一个矩形,一旦我选择了那个矩形,我就无法选择任何其他矩形进行拖动。我知道我的代码肯定是正确的,因为它在thread.sleep方法处于更大的数字时有效,所以我的问题是:为什么当我将thread.sleep设置为较小的数字时它会开始出现故障?这是我的代码的一部分。

while (true) {

        for (int i = 0; i < 15; i++) {

            P.fY[i]++;
        }
        Thread.sleep(500);
        frame.repaint();

    } //the 15 stands for 15 rectangles, and the P.fY stands for the position of y. 

1 个答案:

答案 0 :(得分:1)

因此,基于您的评论,您似乎真的需要一只手来弄清楚如何计算距离作为时间的函数。

通过添加1每个帧循环,你真的说每个方块的速度是1 pixel / 1 frame

相反,您应该利用时间并通过时间函数更新距离,以便它为1 pixel / unit of time。这意味着方块的速度将与每秒帧数无关。


我掀起了一个代码示例。重要的方法是Square#doUpdate()方法。这与您正在寻找的内容完全相关。

它遵循的程序是:

  
      
  1. 计算上次更新的时间,将其存储在delta
  2.   
  3. 将上次更新的时间更新为当前时间
  4.   
  5. 计算deltaX,即deltaX = delta * velocityX
  6.   
  7. 计算deltaY,即deltaY = delta * velocityY
  8.   
  9. deltaX添加到x - 这会更新x坐标
  10.   
  11. deltaY添加到y - 这会更新y坐标
  12.   

代码如下:

import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
import javax.swing.Timer;
import javax.swing.WindowConstants;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.event.ComponentAdapter;
import java.awt.event.ComponentEvent;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.util.LinkedList;

/**
 * @author Obicere
 */
public class MovingSquare {

    private volatile int viewportWidth;
    private volatile int viewportHeight;

    private final LinkedList<Square> squares = new LinkedList<>();

    public MovingSquare() {
        final JFrame frame = new JFrame("Moving Square");
        final JPanel displayPanel = new JPanel() {
            @Override
            protected void paintComponent(final Graphics g) {
                synchronized (squares) {
                    for (final Square square : squares) {

                        // Update the square's locations, ideally this will
                        // be separate of the painting thread
                        square.doUpdate();
                        final int x = (int) square.getX();
                        final int y = (int) square.getY();

                        g.setColor(square.getColor());
                        g.drawRect(x, y, square.squareSize, square.squareSize);

                    }
                }
            }
        };

        displayPanel.addMouseListener(new MouseAdapter() {
            @Override
            public void mouseReleased(final MouseEvent e) {
                final Color nextColor = Color.getHSBColor((float) Math.random(), 1, 0.5f);
                final float speedX = (float) Math.random();
                final float speedY = (float) Math.random();

                synchronized (squares) {
                    final Square newSquare = new Square(nextColor, speedX, speedY);
                    squares.add(newSquare);
                    newSquare.x = e.getX();
                    newSquare.y = e.getY();
                }
            }
        });

        displayPanel.addComponentListener(new ComponentAdapter() {
            @Override
            public void componentResized(ComponentEvent e) {
                viewportWidth = displayPanel.getWidth();
                viewportHeight = displayPanel.getHeight();
            }
        });

        final Timer repaintTimer = new Timer(20, null);

        repaintTimer.addActionListener(e -> {
            if (!frame.isVisible()) {
                repaintTimer.stop();
                return;
            }
            frame.repaint();
        });
        repaintTimer.start();

        displayPanel.setPreferredSize(new Dimension(200, 200)); // Sorry MadProgrammer
        frame.add(displayPanel);
        frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
        frame.pack();
        frame.setLocationByPlatform(true);
        frame.setVisible(true);
    }

    public static void main(final String[] args) {
        SwingUtilities.invokeLater(MovingSquare::new);
    }


    private class Square {

        private final int squareSize = 25;

        private volatile float x;
        private volatile float y;

        private volatile long lastUpdateTime;

        private volatile boolean negateX;
        private volatile boolean negateY;

        private final float speedX;
        private final float speedY;

        private final Color color;

        public Square(final Color color, final float speedX, final float speedY) {
            this.color = color;
            this.speedX = speedX;
            this.speedY = speedY;

            lastUpdateTime = System.currentTimeMillis();
        }

        /**
         * Important method here!!
         * <p>
         * This updates the location of the squares based off of a set
         * velocity and the difference in times between updates.
         */

        public void doUpdate() {

            // Gets the change in time from last update
            final long currentTime = System.currentTimeMillis();
            final long delta = currentTime - lastUpdateTime;
            if (delta == 0) {
                return;
            }
            // be sure to update the last time it was updated
            lastUpdateTime = currentTime;

            // Calculate the speed based off of the change in time
            final float deltaX = getSpeedX(delta);
            final float deltaY = getSpeedY(delta);

            // Move each square by the change of distance, calculated from
            // the change in time and the velocity.
            final float nextX = x + deltaX;
            final float nextY = y + deltaY;

            handleBouncing(nextX, nextY);
        }

        private void handleBouncing(final float nextX, final float nextY) {

            if (nextX < 0) {
                x = 0;
                flipX();
            } else if (nextX + squareSize >= viewportWidth) {
                x = viewportWidth - squareSize;
                flipX();
            } else {
                x = nextX;
            }

            if (nextY < 0) {
                y = 0;
                flipY();
            } else if (nextY + squareSize >= viewportHeight) {
                y = viewportHeight - squareSize;
                flipY();
            } else {
                y = nextY;
            }
        }

        private float getSpeedX(final long delta) {
            return (negateX ? -1 : 1) * delta * speedX;
        }

        private float getSpeedY(final long delta) {
            return (negateY ? -1 : 1) * delta * speedY;
        }

        protected void flipX() {
            negateX = !negateX;
        }

        protected void flipY() {
            negateY = !negateY;
        }

        public float getX() {
            return x;
        }

        public float getY() {
            return y;
        }

        public Color getColor() {
            return color;
        }

    }
}

它在行动中:

Sorry MadProgrammer, needed to do preferred size initially

这看起来有点压倒性。一步一步,改变一些事情。发疯,看看结果如何。

还有一些websites that can help with velocity以及如何计算这样的事情。如果您需要进一步的帮助,只需在下面发表评论,我就会知道我能做些什么。