Проблемы с анимацией траектории полета шара (по координатам)
Уважаемые участники сообщества, добрый день. Возникла трудность с анимацией движения шара. Результат работы кода, который отвечает за расчет координат, меня вполне устраивает, но основная проблема заключается в том, что у меня не получается сделать именно анимацию движения шара. При выполнении кода ниже с параметрами 40 (начальная скорость тела) / 90 (угол, под которым брошено тело) (для видимости шара на полотне) сразу отрисовывается вся траектория полета. При этом, если передавать значение переменной X и Y вне цикла FOR (в методе paintComponent) вообще никакой траектории нет, прописывается только одно значение X и Y (оно и понятно), но если же добавить кусок (на данный момент он закомментирован в коде)
x = x + 1; //координаты движения (X)
y = y + 1; //координаты движения (Y)
и убрать вообще цикл FOR(в методе paintComponent), то анимация заработает. В идеале планируется создание полноценной анимации траектории движения шара, которая считается по вводимым пользователем параметрам. У меня есть подозрение, что я где-то уже достаточно близко, но разобраться в течение долгого времени самостоятельно не получается, поэтому прошу подсказать в чем моя основная ошибка/направить в нужное русло. Заранее спасибо. Код прилагаю:
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.geom.Ellipse2D;
import java.util.Scanner;
import javax.swing.JButton;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
import javax.swing.Timer;
@SuppressWarnings("serial")
public class MovingCircle extends JComponent implements ActionListener {
private static CoordinateSetting coordinateSetting;
private double scale;
private Color color;
private Timer timer;
public double x = 0; //стартовые координаты шара (x)
public double y = 0; //стартовые координаты шара (y)
public MovingCircle(Color color, int delay, CoordinateSetting coordinateSetting) {
this.coordinateSetting = coordinateSetting;
scale = 1.0;
timer = new Timer(delay, this);
this.color = color;
setPreferredSize(new Dimension(500, 500));
}
public void start() {
timer.start();
}
public void stop() {
timer.stop();
}
@Override
public void actionPerformed(ActionEvent arg0) {
repaint();
}
@Override
protected void paintComponent(Graphics g) {
Graphics2D g2d = (Graphics2D) g;
g2d.setColor(Color.white);
int width = 1000;
int height = 1000;
g.fillRect(0, 0, width, height); //белый фон, на котором летит шар
g2d.setColor(Color.black);
g2d.drawRect(0, 0, width - 1, height - 1); //левая и правая линии черного цвета
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g2d.setColor(color);
g2d.scale(scale, scale);
//Первоначальные значения, которые позволяют анимировать движение шара (ниже)
//x = x + 1; //координаты движения (X)
//y = y + 1; //координаты движения (Y)
//Первоначальные значения, которые позволяют анимировать движение шара (выше)
//Вводимые параметры: 40 / 90 (которые видны на полотне)
//КУСОК, КОТОРЫЙ ОТРИСОВЫВАЕТ ВСЕ КООРДИНАТЫ (НИЖЕ)
for (int i = 0; i < coordinateSetting.xCoordinates().length; i++){
System.out.println("Координата Х ["+i+"]=:" + coordinateSetting.xCoordinates()[i]);
System.out.println("Координата Y ["+i+"]=:" + coordinateSetting.yCoordinates()[i]);
x = coordinateSetting.xCoordinates()[i];
y = coordinateSetting.yCoordinates()[i];
if (i > 0) {
x0 = coordinateSetting.xCoordinates()[i-1];
y0 = coordinateSetting.yCoordinates()[i-1];
Ellipse2D el = new Ellipse2D.Double(x, y, 15, 15);
g2d.fill(el);
}
}
//КУСОК, КОТОРЫЙ ОТРИСОВЫВАЕТ ВСЕ КООРДИНАТЫ (ВЫШЕ)
}
@FunctionalInterface
interface CoordinateCalculator {
int calculate (double u, double a, double g, double t);
}
//Класс, отвечающий за принятие параметров шара.
static class CoordinateSetting {
/* Расчет вертикального положения тела через 1 сек
*
* @param u - начальная скорость тела (м/с)
* @param a - угол под которым брошено тело
* @param g - сила гравитации
* @param t - время движения (с)
* @param n - кол-во точек на графике
*/
private final double u, a, g, t;
private final int n;
public CoordinateSetting(double u, double a, double g, double t, int n) {
this.u = u;
this.a = a;
this.g = g;
this.t = t;
this.n = n;
}
public int getN() {
return n;
}
public int[] xCoordinates() {
CoordinateCalculator calculator = (t1, t2, t3, t4)-> ((int) ((t1 * t2 * t3)*10));
return coordinates(u, a, g, t, calculator, Math.cos(Math.toRadians(a)));
}
public int[] yCoordinates() {
CoordinateCalculator calculator = (t1, t2, t3, t4)-> ((int)(1000 - ((t1 * t2 * t3 - t4 * t2 * t2 / 2) * 10)));
return coordinates(u, a, g, t, calculator, Math.sin(Math.toRadians(a)));
}
private int[] coordinates(double u, double a, double g, double t,
CoordinateCalculator calculator, double tmp) {
float tpol_100 = (float)(2 * u * Math.sin(Math.toRadians(a)) / g / 100);
int[] coordinates = new int[n];
for (int i = 0; i < n; i++) {
coordinates[i] = calculator.calculate(u, t, tmp, g);
t = t + tpol_100;
}
return coordinates;
}
}
public static void main(String[] args) {
float u = 0, a = 0, g = 9.81f, t = 0f;
int n = 101;
Scanner sc = new Scanner(System.in);
System.out.print("Введите параметр 'Начальная скорость тела' (число): ");
if (sc.hasNextFloat()) {
u = sc.nextFloat();
System.out.println("Вы ввели корректное значение " + u);
} else {
System.out.println("Извините, но это явно не число. Приложение будет закрыто!");
System.exit(0);
}
System.out.print("Введите параметр 'Угол под которым брошено тело' (число): ");
if (sc.hasNextFloat()) {
a = sc.nextFloat();
System.out.println("Вы ввели корректное значение " + a);
} else {
System.out.println("Извините, но это явно не число. Приложение будет закрыто!");
System.exit(0);
}
sc.close();
float finalU = u;
float finalA = a;
SwingUtilities.invokeLater(new Runnable() {
public void run() {
JFrame frame = new JFrame("Moving Circle");
JPanel panel = new JPanel();
//final MovingCircle MovingCircleGreen = new MovingCircle(Color.green, 20, coordinateSetting);
final MovingCircle MovingCircleGreen = new MovingCircle(Color.green, 20, new CoordinateSetting(finalU, finalA, g, t, n));
panel.add(MovingCircleGreen);
frame.getContentPane().add(panel);
final JButton button = new JButton("Start");
button.addActionListener(new ActionListener() {
private boolean pulsing = false;
@Override
public void actionPerformed(ActionEvent e) {
if (pulsing) {
pulsing = false;
MovingCircleGreen.stop();
button.setText("Start");
} else {
pulsing = true;
MovingCircleGreen.start();
button.setText("Stop");
}
}
});
panel.add(button);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(600, 600);
frame.setVisible(true);
}
});
}
}
Ответы (1 шт):
Вот, могу предложить что-то такое:
List<Point> points = new ArrayList<>();
for (int i=0; i < 300; i++)
points.add(new Point(i, 100+(int) (Math.sin(((float)i)/10)*50)));
JFrame frame = new JFrame();
JComponent comp = new JComponent() {
int index = 0;
@Override
protected void paintComponent(Graphics g) {
index = (index + 1) % points.size();
Point p = points.get(index);
((Graphics2D) g).setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
g.drawOval(p.x-10, p.y-10, 20, 20);
}
};
frame.add(comp);
frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
frame.setSize(new Dimension(300, 300));
frame.setLocationRelativeTo(null);
frame.setVisible(true);
Executors.newScheduledThreadPool(1)
.scheduleAtFixedRate(() -> comp.repaint(), 0, 30, TimeUnit.MILLISECONDS);