
Zitat von
Gothicforum
Was ist, wenn es z.b. drei oder vier rectangles gibt, die sich bewegen, hoch und runter, links und rechts,
also ich kann es nicht `hard-coden`, welches zuerst gezeichnet wird.
Wie kann ich das coden, dass immer dasjenige, das am weitesten unten ist (größte Y-Koordinate) als letztes gezeichnet werden soll?
Das ließe sich bewerkstelligen, indem du die Objekte (falls du keine hast, mach dir eine Klasse, s.u.) gemäß ihrer Y-Koordinate sortierst. Du mögest dich also mit Sortieralgorithmen beschäftigen.
Ein einfacher Sortieralgorithmus, der als Bubblesort bezeichnet wird, besteht aus zwei ineinander geschachtelten Schleifen, hier simpel demonstriert (lauffähig (wobei die int-Werte natürlich auch Objekten angehören könnten, auf denen man mit Gettern und Settern arbeitet)):
Code:
class Sortieren {
static final int[] reihenfolge_01 = { -20, 1, 2, 3, 4, 4, -4, 5, 20, 10, -11, 12, 13, 0, 14, 15, 16, -17, 90, 90 };
static final int[] reihenfolge_02 = { -19, -19, -11, 9, -17, -5, -9, -12, 10, -3, 7, 4, 5, -5, 4, 4, 3, 2, 1, 13 };
static void sort(int[] a) {
for (int end = a.length - 1; end > 0; end--) {
for (int i = 0; i < end; i++) {
if (a[i] < a[i + 1]) {
int tmp = a[i];
a[i] = a[i + 1];
a[i + 1] = tmp;
}
}
}
}
static void out(int[] a) {
for (int i : a) System.out.format("%4d", i);
System.out.println();
}
public static void main(String[] args) {
int[] sammlung;
sammlung = reihenfolge_01;
sort(sammlung);
out(sammlung);
sammlung = reihenfolge_02;
sort(sammlung);
out(sammlung);
}
}
Ausgabe:
Code:
90 90 20 16 15 14 13 12 10 5 4 4 3 2 1 0 -4 -11 -17 -20
13 10 9 7 5 4 4 4 3 2 1 -3 -5 -5 -9 -11 -12 -17 -19 -19
Bei kleinen Zahlenmengen ist Bubblesort relativ schnell, bei großen relativ langsam (wegen O(n2)). Doch schnellere Algorithmen sind komplexer, wodurch ein Zusatzaufwand entsteht, der mit abgearbeitet werden muss, weswegen einfache Algorithmen wie dieser lange die Nase vorn haben (und bei großen Mengen irgendwann unbrauchbar werden). Bevor du dir komplexere anguckst (was du irgendwann tun solltest, z.B. Heapsort), solltest du Bubblesort verstanden haben. Natürlich lässt der sich nicht nur auf ein starres Array aus int-Werten anwenden, sondern z.B. auch auf ein ArrayList<T>.
Diese Containerklassen bieten selbst eine Sortiermethode an, aber dazu müsstest du Comparable<T> implementieren und die Methode compareTo überschreiben, was man schon als eine fortgeschrittene Thematik bezeichnen könnte. Wer dazu zu faul ist, kann ab Java 8 ersatzweise mit Comparator.comparing (und einer Lambda-Funktion als Parameter, die sich bequem von einem Methodennamen ableiten lässt) bei standardmäßigen Sortierkriterien, wie sie meistens genügen, eine Menge Schreibarbeit einsparen und den Code damit übersichtlicher halten. Das könnte dann, auf deinen Fall gemünzt (nur Konsolenausgabe, um das Konzept zu verdeutlichen), etwa so aussehen (lauffähig):
Code:
import java.awt.Color;
import java.util.ArrayList;
import java.util.Comparator;
abstract class Primitive
{
protected Primitive (Color color, boolean visible, int posX, int posY) {
this.color = color;
this.visible = visible;
this.posX = posX;
this.posY = posY;
}
public Color getColor() { return this.color; };
public boolean getVisible() { return this.visible; }
public int getPosX() { return this.posX; }
public int getPosY() { return this.posY; }
public void setColor(Color color) { this.color = color; }
public void setVisible(boolean visible) { this.visible = visible; }
public void setPosX(int posX) { this.posX = posX; }
public void setPosY(int posY) { this.posY = posY; }
private Color color;
private boolean visible;
private int posX;
private int posY;
}
class Rectangle extends Primitive
{
public Rectangle (Color color, boolean visible, int posX, int posY, int width, int height) {
super(color, visible, posX, posY);
this.width = width;
this.height = height;
}
public int getWidth() { return this.width; }
public int getHeight() { return this.height; }
public void setWidth(int width) { this.width = width; }
public void setHeight(int height) { this.height = height; }
private int width;
private int height;
}
class Circle extends Primitive
{
public Circle (Color color, boolean visible, int posX, int posY, int diameter) {
super(color, visible, posX, posY);
this.diameter = diameter;
}
public int getDiameter() { return this.diameter; }
public void setDiameter(int diameter) { this.diameter = diameter; }
private int diameter;
}
final class Colors
{
final static Color color_01 = new Color(32, 64, 128);
final static Color color_02 = new Color(64, 128, 32);
final static Color color_03 = new Color(128, 32, 64);
final static Color color_04 = new Color(32, 128, 64);
final static Color color_05 = new Color(128, 64, 32);
final static Color color_06 = new Color(64, 32, 128);
}
public class ListSort
{
public static void printAllPosY(ArrayList<Primitive> list) {
for (Primitive primitive : list) {
if (primitive.getVisible()) {
if (primitive instanceof Circle) {
Circle circ = (Circle)primitive;
System.out.format("PosY: %d - I'm a circle. ", circ.getPosY());
System.out.format("My diameter is: %d%n", circ.getDiameter());
} else if (primitive instanceof Rectangle) {
Rectangle rect = (Rectangle)primitive;
System.out.format("PosY: %d - I'm a rectangle. ", rect.getPosY());
System.out.format("My width and height are: %dx%d%n", rect.getWidth(), rect.getHeight());
} else {
System.out.format("PosY: %d - I'm an unknown primitive!%n", primitive.getPosY());
}
} else {
System.out.format("You don't see me!%n");
}
}
System.out.println();
}
public static void main(String[] args) throws Exception {
ArrayList<Primitive> list = new ArrayList<Primitive>();
list.add(new Rectangle(Colors.color_01, true, 100, 444, 50, 80));
list.add(new Rectangle(Colors.color_02, true, 100, 999, 50, 80));
list.add(new Rectangle(Colors.color_03, false, 100, 777, 50, 80));
list.add(new Rectangle(Colors.color_04, true, 100, 666, 50, 80));
list.add(new Circle(Colors.color_05, true, 100, 888, 77));
list.add(new Circle(Colors.color_06, true, 100, 222, 77));
System.out.format("Vor der Sortierung:%n");
printAllPosY(list);
list.sort(Comparator.comparing(Primitive::getPosY));
System.out.format("Nach aufsteigender Sortierung:%n");
printAllPosY(list);
list.sort(Comparator.comparing(Primitive::getPosY).reversed());
System.out.format("Nach absteigender Sortierung:%n");
printAllPosY(list);
}
}
Ausgabe:
Code:
Vor der Sortierung:
PosY: 444 - I'm a rectangle. My width and height are: 50x80
PosY: 999 - I'm a rectangle. My width and height are: 50x80
You don't see me!
PosY: 666 - I'm a rectangle. My width and height are: 50x80
PosY: 888 - I'm a circle. My diameter is: 77
PosY: 222 - I'm a circle. My diameter is: 77
Nach aufsteigender Sortierung:
PosY: 222 - I'm a circle. My diameter is: 77
PosY: 444 - I'm a rectangle. My width and height are: 50x80
PosY: 666 - I'm a rectangle. My width and height are: 50x80
You don't see me!
PosY: 888 - I'm a circle. My diameter is: 77
PosY: 999 - I'm a rectangle. My width and height are: 50x80
Nach absteigender Sortierung:
PosY: 999 - I'm a rectangle. My width and height are: 50x80
PosY: 888 - I'm a circle. My diameter is: 77
You don't see me!
PosY: 666 - I'm a rectangle. My width and height are: 50x80
PosY: 444 - I'm a rectangle. My width and height are: 50x80
PosY: 222 - I'm a circle. My diameter is: 77
Es gibt also eine flexible Liste, zu der sich beliebig viele Elemente eines selbst definierten Typs hinzufügen lassen, wobei auch der Typ flexibel ist, solange er die abstrakte Klasse Primitive erweitert. Natürlich könntest du alternativ selber, z.B. per Bubblesort (s.o.), sortieren.
[...] wird das ein bisschen viel Code, der immer und immer wieder geprüft wird von graphics g.
Packe den Animationscode besser nicht in die Präsentationsebene. Erinnerst du dich an meinen vorletzten Beitrag, von wegen
Code:
class Animator implements ActionListener
usw. ? Dort ist das, wie gesagt, besser aufgehoben. Außerdem lässt sich der Krempel dann auch steuern (actionPerformed erhält einen Event, den du auswerten kannst). Vielleicht guckst du dir das mal an. Das Schema beantwortet solche Fragen.
Solange die Ausführungszeit deines Animators kurz ist, klappt das innerhalb der Methode actionPerformed, also auf den Timer-Event hin, normalerweise gut. Bei langen Ausführungszeiten, wie sie sich bei komplexen Szenen oder viel Kopierarbeit ergeben können, könnten sich u.U. die Unterschiede in den Ausführungszeiten störend bemerkbar machen. Dann sollte es besser sein, die Berechnungen nach der Präsentation durchführen zu lassen, damit die Präsentation auf den Event hin sofort und in konstanter Zeit erfolgen kann. Bei dem Kleinkram hier fallen solche Unterschiede natürlich nicht auf, da sie absolut sehr gering sind. Da fallen schon eher die groben Timer-Interrupt-Intervalle (von typ. 1...15,625 ms, was die tatsächliche Auflösung definiert) auf, in deren "Rauschen" solche kleinen Unterschiede untergehen.