Hallo Leute, kurze Frage:
Wir versuchen ein Auto (Shape-Objekt) auf einem Pfad entlangfahren zu lassen. Das klappt soweit auch super, indem wir ein Path2D-Objekt mit dem PathIterator zerlegen, die entstandenen Punkte in einer Arraylist speichern und die Autoposition dann auf die der Pfadpunkte setzen (mit neu berechnetem Winkel).
So sieht das in Code aus:
Problem:
Unser Problem ist jetzt, dass anscheinend nur der Pfadbereich mit der Kurve zerlegt und abgefahren wird. Bei der Anfangsgerade teleportiert sich das Auto direkt vom Start- zum Endpunkt. Woran liegt das und wie können wir das beheben?
EDIT: Das Problem dürfte sein, dass Geraden aus Anfangs und Endpunkt gezeichnet werden und die Gerade somit vom PathIterator auch nur in die beiden zerlegt wird. Wie könnte man das umgehen. Die Punkte auf der Gerade "per Hand" also per Schleife selbst der Punkte-Arraylist hinzufügen?
Falls jemand das Ganze Programm testen will (nur eine Klasse "PathFollow" mit inneren Klassen):
Wir versuchen ein Auto (Shape-Objekt) auf einem Pfad entlangfahren zu lassen. Das klappt soweit auch super, indem wir ein Path2D-Objekt mit dem PathIterator zerlegen, die entstandenen Punkte in einer Arraylist speichern und die Autoposition dann auf die der Pfadpunkte setzen (mit neu berechnetem Winkel).
So sieht das in Code aus:
Java:
// Erstellt den Pfad, auf dem gefahren werden sollen
Path2D path = new Path2D.Double();
// Anfang des Pfads
path.moveTo(100, 200);
// Form des Pfades wird bestimmt, eine Gerade gefolgt von einer Kurve
path.lineTo(100, 100); // Gerade
path.curveTo(100, 100, 100, 0, 0, 0); // Kurve
// Zerlegen des Pfades in Punkte, Points2D
// Zerlegt den Pfad in Punkte, um ihm folgen zu können. Argument flatness: Abstand der Punkte.
PathIterator pi = pathShape.getPathIterator(null, 0.1);
// Speichert die Punkte ins points-Array
while (!pi.isDone()) {
double[] koordinaten = new double[6];
switch (pi.currentSegment(koordinaten)) {
case PathIterator.SEG_MOVETO:
points.add(new Point2D.Double(koordinaten[0], koordinaten[1]));
break;
case PathIterator.SEG_LINETO:
points.add(new Point2D.Double(koordinaten[0], koordinaten[1]));
break;
}
pi.next();
}
Problem:
Unser Problem ist jetzt, dass anscheinend nur der Pfadbereich mit der Kurve zerlegt und abgefahren wird. Bei der Anfangsgerade teleportiert sich das Auto direkt vom Start- zum Endpunkt. Woran liegt das und wie können wir das beheben?
EDIT: Das Problem dürfte sein, dass Geraden aus Anfangs und Endpunkt gezeichnet werden und die Gerade somit vom PathIterator auch nur in die beiden zerlegt wird. Wie könnte man das umgehen. Die Punkte auf der Gerade "per Hand" also per Schleife selbst der Punkte-Arraylist hinzufügen?
Falls jemand das Ganze Programm testen will (nur eine Klasse "PathFollow" mit inneren Klassen):
Java:
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Rectangle;
import java.awt.Shape;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.geom.AffineTransform;
import java.awt.geom.Path2D;
import java.awt.geom.PathIterator;
import java.awt.geom.Point2D;
import java.util.ArrayList;
import java.util.List;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.Timer;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class PathFollow {
public static void main(String[] args) {
new PathFollow();
}
// JFrame wird wird erstellt
public PathFollow() {
EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
ex.printStackTrace();
}
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new TestPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class TestPane extends JPanel {
private Shape pathShape;
private List<Point2D> points;
private Shape car;
private double angle;
private Point2D pos;
private int index;
protected static final double LAUFZEIT = 5000; // 5 seconds...
private Long startTime;
public TestPane() {
// Erstellt den Pfad, auf dem gefahren werden sollen
Path2D path = new Path2D.Double();
// Anfang des Pfads
path.moveTo(100, 200);
// Form des Pfades wird bestimmt
path.lineTo(100, 100);
path.curveTo(100, 100, 100, 0, 0, 0);
pathShape = path;
car = new Rectangle(0, 0, 10, 10);
points = new ArrayList<>(25);
// Zerlegt den Pfad in Punkte, um ihm folgen zu können. Argument flatness: Abstand der Punkte.
PathIterator pi = pathShape.getPathIterator(null, 0.1);
// Speichert die Punkte ins points-Array
while (!pi.isDone()) {
double[] koordinaten = new double[6];
switch (pi.currentSegment(koordinaten)) {
case PathIterator.SEG_MOVETO:
points.add(new Point2D.Double(koordinaten[0], koordinaten[1]));
break;
case PathIterator.SEG_LINETO:
points.add(new Point2D.Double(koordinaten[0], koordinaten[1]));
break;
}
pi.next();
}
// Erstellt einen Timer, der aufhört, wenn die vorgegebene Laufzeit erreicht wurde (hier 5sek.)
Timer timer = new Timer(40, new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
// Holt aktuelle Zeit in ms
if (startTime == null) {
startTime = System.currentTimeMillis();
}
// Spielzeit ist die aktuelle Zeit minus die Startzeit
long playTime = System.currentTimeMillis() - startTime;
// Fortschritt: 0.0 - 1.0, Prozent. Stoppt, wenn eingestellte Laufzeit erreicht ist.
double progress = playTime / LAUFZEIT;
if (progress >= 1.0) {
progress = 1d;
((Timer) e.getSource()).stop();
}
// i dont even fucking know
int index = Math.min( Math.max(0, (int) (points.size() * progress)) , points.size() - 1 );
// Index gibt an, wo sich das Auto gerade befindet. Außerdem wird der Winkel zwischen dem aktuellen Punkt und dem nächsten berechnet.
pos = points.get(index);
if (index < points.size() - 1) {
angle = angleTo(pos, points.get(index + 1));
}
System.out.println("Index: " + index + " , Winkel: " + angle);
repaint();
}
});
timer.start();
}
// Größe des JPanels. 200x200 Pixel.
@Override
public Dimension getPreferredSize() {
return new Dimension(200, 200);
}
@Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g.create();
// Zeichnet Pfad, kann auch weggelassen werden
g2d.draw(pathShape);
// Objekt, mit dem das Auto gedreht wird
AffineTransform affTransform = new AffineTransform();
if (pos != null) {
// Speichert Grenzen/Größe des Autos als Rechteck ab
Rectangle bounds = car.getBounds();
// AffineTransform-Objekt soll rotieren um den Ursprung, deshalb: bounds.width / 2. (Legt quasi Aufgabe fest)
affTransform.rotate(angle, (bounds.width / 2), (bounds.width / 2));
// Constructs a Path2D object from an Shape object, transformed by an AffineTransform object. (übergibt das Auto und die Transformation, die darauf angewendet werden soll)
Path2D player = new Path2D.Double(car, affTransform);
// Versetzt den Koordinatenursprung
g2d.translate(pos.getX() - (bounds.width / 2), pos.getY() - (bounds.height / 2));
g2d.draw(player);
}
g2d.dispose();
}
// Zu Bogenmaß
protected double angleTo(Point2D from, Point2D to) {
double angle = Math.atan2(to.getY() - from.getY(), to.getX() - from.getX());
return angle;
}
}
}
Zuletzt bearbeitet: