Rendering order auf einem ismetrischen Grid

Eichelhäer

Bekanntes Mitglied
Hi,

ich bin gerade dabei eine Art rendering order für mein isometrisches Spielfeld zu erstellen. Dazu habe ich mir die ArrayList mit allen GameObjekten genommen und diese dann mit Collections.sort versucht zu sortieren. Allerdings klappt das nicht so ganz, denn mein Comparator liefert die falschen Werte. Ich versuche Punkte zu vergleichen bzw. bounding Boxen. Hier mal der Code:

Java:
Collections.sort(gameObjects, new Comparator<>() {
            @Override
            public int compare(GameObject o1, GameObject o2) {
                
                // Wenn y gleich ist dann vergleiche die x position
                
                if(o1.boundingBox.getBounds().y == o2.boundingBox.getBounds().getY()) {
                    return Double.compare(o1.boundingBox.getBounds().getX(),o2.boundingBox.getBounds().getX());
                }
                
                // sonst vergleiche mimmer die y position
                
                return Double.compare(o1.boundingBox.getBounds().getY(),o2.boundingBox.getBounds().getY());
            }
        });

Die GameObjekte haben unterschiedliche Größen so ist ein Gebäude z.B. 120x60 groß während ein Baum 40X40 groß ist.

Ich hoffe jemand kann mir da helfen.

MfG


Eichelhäer
 
Erst einmal wäre es super, wenn Du mehr Informationen geben könntest. Wann liefert Dein Comparator welche falschen Werte?

Was auffällt: Double mit == zu vergleichen ist in der Regel nicht, was man machen will. In der Regel werden minimale Abweichungen erlaubt. Das kann man z.B. prüfen über die Prüfung ob der absolute Wertes (Math.abs) der Differenz kleiner als die Schwelle Epsilon ist.

Hintergrund ist, dass Gleitkommazahlen eine begrenzte Genauigkeit haben und daher bei Berechnungen Ungenauigkeiten einfließen.

Dann noch zwei Hinweise zu Deinem Code:
a) Funktionale Interfaces bitte nie als innere Klasse implementieren. Das ist extrem unleserlich - auch daran zu erkennen, dass Du da Kommentare in den Code eingefügt hast. Mit Java 8 wurden dazu Lambda Expressions und Methodenreferenzen eingeführt. Damit hättest Du eine Methode schreiben können, die im Namen genau aussagt, was diese macht was dann den Nebeneffekt hat, dass da weitere Kommentare unnötig werden. Und wenn das nicht ausreicht, dann ist das eine Sache für ein JavaDoc Kommentar vor der Methode.

b) Comparatoren einfach über Comparator.comparing(..).thenComparing(...) aufbauen. Das ist sehr kurz und zugleich gut lesbar. (Aufpassen: statt comparing muss teilweise der Typ angegeben werden ... bei double wäre es comparingDouble(...) )
 
Danke für die Antwort. Ich glaube ich lese mich erstmal noch etwas mehr in Comparatoren ein. Im Grunde genommen liefert der Comparator keine falschen Werte die Darstellung ist nur eine falschen, d.h. ,dass die render order die ich damit erzielen wollte eine andere ist. so werden an verschiedenen stellen größerer y werte hinter kleineren gezeichnet und an wieder anderen nicht. Ich glaube es liegt nicht unbeding an dem ==, denn ich verwende ganzzahlen zum vergleich und die sind eindeutig ( war blos ein tippfehler mit dem getX() bzw. getY(), das sollte x bzw y heißen).

Könntest du bitte ein konkretes Beispiel zu deinem Comparatoraufbau zeigen bitte? Ich kenne diese Konstruktion nicht.
 
Wenn dein Koordinatenursprung für y nicht "unten" sondern "oben" ist, wie es bei den meisten Window-Koordinatensystemen wie etwa für AWT oder Swing oder JavaFX der Fall ist, dann musst du nicht nur die y-Koordinate der Rechtecke berücksichtigen, sondern eben auch die Höhe (also bounds.getHeight()). Die Linie der höchsten Y Koordinate (y + height) definiert dann also die Zeichenreihenfolge und nicht die Linie der niedrigen Y-Koordinate (y) - weil höhe Y-Werte ja "weiter unten" im Window-Koordinatensystem sind.
 
Könntest du bitte ein konkretes Beispiel zu deinem Comparatoraufbau zeigen bitte? Ich kenne diese Konstruktion nicht.
Dein Sort Aufruf wäre etwas wie:

Java:
Collections.sort(
    gameObjects,
    Comparator.comparingDouble( o -> o.boundingBox.getBounds().getX() )
              .thenComparingDouble( o -> o.boundingBox.getBounds().getY() )
);

Wenn Du Dir die Dokumentation anschaust (https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/util/Comparator.html), dann siehst Du, dass da bei comparingDouble eine ToDoubleFunction<T> als Parameter benötigt wird. Also eine Methode, die in Deinem Fall ein GameObject als Parameter bekommt und ein double zurück gibt. Und das ist dann hier der Lambda Ausdruck.
 
Ok danke. Und wie sähe dann die konkrete Implementierung für ein isometrisches Grid aus? Sorry, dass ich so direkt frage, aber ich sitze schon sehr lange daran.
 
Ok, ich habe es. Ich habe einfach den Mittelpunkt der BoundingBox des jeweils mittleren Tiles eines GameObjects genommen. Und anschließend dessen screeny werte verglichen. Das funktioniert wunderbar.
 

Zurück
Oben