2015-03-21 3 views
1

У меня есть рабочий код, который в основном рисует 15 прямоугольников на экране, которые вы можете перетащить. Я сделал так, чтобы с течением времени прямоугольники попадали в нижнюю часть экрана. Хотя у меня есть метод thread.sleep при больших числах, таких как 500, я все еще могу перетаскивать прямоугольники вокруг экрана, когда они падают без проблем. Но когда я начинаю уменьшать метод thread.sleep до меньших чисел, таких как 50, внезапно возникают проблемы. Такие проблемы, как я могу перетащить до двух прямоугольников, прежде чем прямоугольники начнут сжиматься до тех мест, где я их не перетаскивал. Иногда я могу перетащить только до одного прямоугольника, и как только я выбрал этот прямоугольник, я не могу выбрать любые другие прямоугольники для перетаскивания. Я знаю, что мои коды определенно правильны, поскольку он работает, когда метод thread.sleep имеет большее число, поэтому мой вопрос: почему он начинает сжиматься, когда я делаю 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, вы должны изменить ее, чтобы переместить время простоя, а не фиксированную скорость. – Obicere

+0

P.fY [i] - это местоположение всех прямоугольников. Все они увеличиваются на 1 пиксель за 500 миллисекунд. – Ski

+1

В этом проблема. Это означает, что, если вам нужны более высокие кадры в секунду, изменяется скорость прямоугольников. Это нежелательное поведение в симуляции, подобной этому. Вместо этого вам нужно отметить последний раз, когда обновляется каждый прямоугольник, а затем, когда вы снова обновляетесь, получите изменение во времени, умножьте его на некоторую скорость и затем измените значение. Это будет поддерживать скорость 1px/500ms независимо от того, ставка. – Obicere

ответ

1

Так основаны от вашего комментария, кажется, что вы просто действительно нужна рука с выяснить, как рассчитать расстояние в зависимости от времени.

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

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


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

Процедура следует есть: время

  1. Рассчитайте из последнего обновления, сохраните его в delta.
  2. обновление времени последнего обновления к текущему времени
  3. Calculate 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'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 и как рассчитать такие вещи. Если вам нужна дополнительная помощь, просто оставьте комментарий ниже, и я увижу, что я могу сделать.

Смежные вопросы