Использование метода thread.sleep в рисовании

1

У меня есть рабочий код, который в основном рисует 15 прямоугольников на экране, которые вы можете перетащить. Я сделал так, чтобы с течением времени прямоугольники попадали в нижнюю часть экрана. Хотя у меня есть метод thread.sleep при больших числах, таких как 500, я все еще могу перетаскивать прямоугольники вокруг экрана, когда они падают без проблем. Но когда я начинаю уменьшать метод thread.sleep до меньших чисел, таких как 50, внезапно возникают проблемы. Такие проблемы, как я могу перетащить до двух прямоугольников, прежде чем прямоугольники начнут сжиматься до тех мест, где я их не перетаскивал. Иногда я могу перетащить только до одного прямоугольника, и как только я выбрал этот прямоугольник, я не могу выбрать любые другие прямоугольники для перетаскивания. Я знаю, что мои коды определенно правильны, поскольку он работает, когда метод 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. 
  • 0
    500 миллисекундный сон означает, что вы будете получать 2 кадра в секунду ... Кроме того, P.fY не совсем ясен. Если это фактическая координата y, вы должны изменить ее, чтобы она двигалась по истекшему времени, а не по фиксированной ставке.
  • 0
    P.fY [i] - это расположение у всех прямоугольников. Все они увеличиваются на 1 пиксель за 500 миллисекунд.
Показать ещё 3 комментария
Теги:
multithreading
concurrency

1 ответ

1
Лучший ответ

Поэтому, основываясь на вашем комментарии, кажется, что вам просто нужна рука с выяснением того, как рассчитать расстояние как функцию времени.

Добавляя 1 цикл кадров, вы действительно говорите, что скорость каждого квадрата равна 1 pixel/1 frame.

Вместо этого вы должны использовать время и обновлять расстояние с помощью функции времени, чтобы она составляла 1 pixel/unit of time. Это означает, что скорость квадратов будет тогда независима от кадров в секунду.


Я взвесил пример кода. Важным методом является метод Square#doUpdate(). Это касается именно того, что вы ищете.

Процедура:

  1. Вычислите время с последнего обновления, сохраните его в delta.
  2. Обновить время последнего обновления до текущего времени
  3. Вычислить deltaX, который является deltaX = delta * velocityX
  4. Вычислить deltaY, который является deltaY = delta * velocityY
  5. Добавьте deltaX в x - это обновит координату x
  6. Добавьте deltaY в y - это обновит координату y

Код выглядит следующим образом:

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

    }
}

И это в действии:

Изображение 174551

Это может показаться немного подавляющим. Пройдите через него, измените некоторые вещи. Сходите с ума и посмотрите, какие результаты.

Есть также некоторые веб-сайты, которые могут помочь в скорости и как рассчитать такие вещи. Если вам нужна дополнительная помощь, просто оставьте комментарий ниже, и я увижу, что я могу сделать.

Ещё вопросы

Сообщество Overcoder
Наверх
Меню