简体   繁体   中英

Using the thread.sleep method in painting

I have a working code which basically paints 15 rectangles on the screen that you can drag around. I made it so that the rectangles falls to the bottom of the screen as time passes. While I have the thread.sleep method at bigger numbers such as 500, I can still drag the rectangles around the screen as they fall with no problems. But as I start to decrease the thread.sleep method to smaller numbers such as 50, suddenly problems arises. Problems such as I can only drag up to 2 rectangles before the rectangles start glitching back to the places where I did not drag them. Sometimes I can only drag up to one rectangles, and once I selected that rectangle, I can't select any other rectangles to drag. I know my codes are definitely right, since it works while the thread.sleep method is at at bigger number, so my question is: why does it start glitching when I make thread.sleep to smaller numbers? Here's part of my code.

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. 

So based off of your comment, it seems like you just really need a hand with figuring out how to calculate the distance as a function of time.

By adding 1 each frame loop, you're really saying the speed of each square is 1 pixel / 1 frame .

Instead, you should utilize time and update the distance by a function of time, so that it will be 1 pixel / unit of time . This means the velocity of the squares will then be independent of the frames per second.


I whipped up a code example. The important method is the Square#doUpdate() method. This pertains to exactly what you're looking for.

The procedure it follows is:

  1. Calculate time from last update, store it in delta .
  2. Update the time of the last update to the current time
  3. Calculate deltaX , which is deltaX = delta * velocityX
  4. Calculate deltaY , which is deltaY = delta * velocityY
  5. Add deltaX to x - this updates the x coordinate
  6. Add deltaY to y - this updates the y coordinate

The code is as follows:

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

    }
}

And it in action:

抱歉,MadProgrammer,最初需要做首选尺寸

This might seem a bit overwhelming. Step through it, change some things up. Go crazy and see what the results are.

There are also some websites that can help with velocity and how to calculate things like this. If you need further help, just drop a comment down below and I'll see what I can do.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM