Так основаны от вашего комментария, кажется, что вы просто действительно нужна рука с выяснить, как рассчитать расстояние в зависимости от времени.
При добавлении 1
каждой петли кадра, вы действительно говорите, что скорость каждого квадрата равна 1 pixel/1 frame
.
Вместо этого вы должны использовать время и обновить расстояние по функции времени, чтобы оно было 1 pixel/unit of time
. Это означает, что скорость квадратов будет тогда независима от кадров в секунду.
Я взломал пример кода. Важным методом является метод Square#doUpdate()
. Это касается именно того, что вы ищете.
Процедура следует есть: время
- Рассчитайте из последнего обновления, сохраните его в
delta
.
- обновление времени последнего обновления к текущему времени
- Calculate
deltaX
, который deltaX = delta * velocityX
- Вычислить
deltaY
, что deltaY = delta * velocityY
- Добавить
deltaX
в x
- это обновляет x
координат
- Добавить
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;
}
}
}
И это в действии:
Это может показаться немного подавляющим. Пройдите через него, измените некоторые вещи. Сходите с ума и посмотрите, какие результаты.
Есть также некоторые websites that can help with velocity и как рассчитать такие вещи. Если вам нужна дополнительная помощь, просто оставьте комментарий ниже, и я увижу, что я могу сделать.
Задержка в 500 миллисекундов означает, что вы получите 2 кадра в секунду ... Кроме того, «P.fY» не совсем понятен. Если это фактическая координата y, вы должны изменить ее, чтобы переместить время простоя, а не фиксированную скорость. – Obicere
P.fY [i] - это местоположение всех прямоугольников. Все они увеличиваются на 1 пиксель за 500 миллисекунд. – Ski
В этом проблема. Это означает, что, если вам нужны более высокие кадры в секунду, изменяется скорость прямоугольников. Это нежелательное поведение в симуляции, подобной этому. Вместо этого вам нужно отметить последний раз, когда обновляется каждый прямоугольник, а затем, когда вы снова обновляетесь, получите изменение во времени, умножьте его на некоторую скорость и затем измените значение. Это будет поддерживать скорость 1px/500ms независимо от того, ставка. – Obicere