Isometrische Tileposition auslesen

Federhalter

Mitglied
Hallo,

ich habe ein isometrisches Spielfeld bestehend aus Kacheln und möchte bei beliebigem Klick auf dasselbige die Kachel x bzw. y Position auslesen.

Orthogonal ist das klar, aber isometrisch ists finde ich schwieriger. Das Feld ist NICHT gestaffelt sondern liegt in der Diamantform vor und ich bräuchte die reine mathematische Formel dafür OHNE AffineTransform, denn das führt später zu größeren Komplikationen bei der Kollisionsberechnung.(Habe das Probiert).

Und noch etwas, die Kacheln sind im Grunde genommen 2x2 groß, aber das dürfte für die benötigte Formel glaube ich egal sein.

Im Prinzip habe ich folgende Größen gegeben:

Feldbreite : 800.
Feldhöhe : 800.
Kachelbreite : 2.
Kachelhöhe : 2.
sowie die Mausposition.

Ach ja und wenn man sich die Raute im Fenster vorstellt ist der 0-Punkt in der oberen linken Ecke des Fenster, das ganze Feld wird aber noch um 400 Pixel nach rechts verschoben, also oden in der Mitte.


Wäre für konkrete Hilfe dankbar, denn ich kann diese Formel mit meinem Wissen nicht herleiten.

Danke im Voraus.

Gruß Federhalter
 
Weiß hier denn keiner Rat?

Mein Feld besteht aus 25x25 isometrischen Kacheln mit der Größe von 64x32 pro Kachel.

Orthogonal teilt man einfach die Mausposition durch Kachelhöhe bzw. Kachelbreite.

Ich möchte bei Klick auf eine Kachel wissen, welche Kachelposition diese besitzt, z.B. Kachel(3,2).
 
Hallo Federhalter,
Orthogonal teilt man einfach die Mausposition durch Kachelhöhe bzw. Kachelbreite.
Das ist richtig. Damit hast du im Prinzip schon fast deine Lösung. Du hast also das Kachelfeld um einen bestimmten Winkel gedreht, und vielleicht noch mehr. Insgesamt gibt es da Rotation, Skalierung, und Translation. Die drei gehören auch zu den affinen Transformationen. Um zurück zu deinem einfachen orthogonalen Fall zu kommen, musst du die Transformationen rückgängig machen. Aber nicht mit deinem Spielfeld, sondern mit den Mauskoordinaten. Sagen wir mal du hast das Spielfeld um 45° um sein Zentrum gedreht (dann ergibt das die Diamantform). Wenn du jetzt die Maus auf einem der Felder positionierst, möchtest du dieses Feld markieren. Stell dir nun vor du würdest das gesamte Spielfeld + Maus um -45° um das Zentrum rotieren, was hättest du dann? Den einfachen orthogonalen Fall. Du musst also nur die Mauskoordinaten korrekt zurückrotieren, und schon kannst du orthogonal rechnen. Anders ausgedrückt: Du transformierst das Koordinatensystem der Maus in das Koordinatensystem deiner orthogonalen Kacheln.
In Wirklichkeit ist die Rücktransformation wahrscheinlich etwas komplizierter, da du mehrere Transformationen hintereinander ausführst. Ich gehe hier von dem Code aus, den du in einem anderen Thread (https://www.tutorials.de/threads/graphics2d-isometrie.406389/#post-2103293) gepostet hast:
Java:
public void paintComponent(Graphics g) {
        super.paintComponents(g);
     
        Graphics2D g2 = (Graphics2D) g;
     
        AffineTransform at = new AffineTransform();
        at.setToTranslation(600,0);
        g2.transform(at);
        at.setToScale(2, 1);
        g2.transform(at);
        at.setToRotation(Math.toRadians(45));
        g2.transform(at);
     
        for(int x = 0;x<width;x++) {
            for(int y = 0;y<height;y++) {
                g2.setColor(new Color(random.nextInt(255),random.nextInt(255),random.nextInt(255)));
                g2.fill(new Rectangle2D.Double(x*32,y*32,32,32));
            }
        }
    }
Zunächst verschiebst du um 600 Einheiten in x-Richtung (https://docs.oracle.com/javase/7/do...ansform.html#setToTranslation(double, double)). Dann skalierst du in x-Richtung doppelt so breit und in y-Richtung einfach (https://docs.oracle.com/javase/7/do...fineTransform.html#setToScale(double, double)). Zum Schluss rotierst du das ganze um 45° (https://docs.oracle.com/javase/7/docs/api/java/awt/geom/AffineTransform.html#setToRotation(double)).
Du kannst mir glauben, dass solche Transformationen von der Mathematik her schnell fordernd werden können (siehe z.B. https://de.wikipedia.org/wiki/Affine_Abbildung). Was wir jetzt brauchen ist eine Transformationsmatrix, die deine Transformationen rückgängig macht. Glücklicherweise bietet die Java-Klasse uns da einige Hilfen an, damit wir nicht alles händisch machen müssen. Händisch müssten wir 1) Die Transformationen rückgängig machen 2) Die Transformationsmatrix ausrechnen 3) Die T-Matrix mit den Mauskoordinaten multiplizieren.

Dir ist sicherlich schon in den Sinn gekommen, dass so etwas wie dein Problem häufig vorkommen muss. Aus diesem Grund besitzt AffineTransform eine Methode .inverseTransform() (guckst du hier https://docs.oracle.com/javase/7/do...java.awt.geom.Point2D, java.awt.geom.Point2D)). Diese Methode macht alles was wir besprochen haben automatisch für uns. Hier ist ein Minimalbeispiel (ungetestet):
Java:
// Du brauchst natürlich dein Graphics2D Objekt
Graphics2D g2 = (Graphics2D) g;
.
.
.

Point2D mouseCoords = new Point2D.Float(10.0, 10.0); // Die Werte sind beispielhaft, du nimmst natürlich einen Point2D mit den echten Mauskoordinaten
AffineTransform at = g2.getTransform(); // Hol dir die aktuelle Transformation deines Graphics2D-Objektes
Point2D mouseCoordsOrtho = at.inverseTransform(mouseCoords, null); // Führe Rücktransformation der Mauskoordinaten durch

// mouseCoordsOrtho entspricht den Mauskoordinaten im ursprünglichen System

Wenn du die Koordinaten rücktransformiert hast, kannst du wie du schon angemerkt hast schlicht durch die Kachelgröße teilen. Falls es noch Fragen gibt gerne posten.

Gruß Technipion
 
OK. Vielen Dank für deine Antwort, ABER heute früh habe ich die Lösung gefunden und zwar durch Berechnung. Ich hatte ein Grundlagenproblem beim Initialisieren und berechnen meiner Variablen, hierbei ging es um Datentypen und exakte Werte, also essentielle Grundlagen. Ich hatte bereits die korrekte Formel zur Umrechnung von kartesischen Koordinaten in Isometrische Koordinaten, habe aber alles mit Integer berechnet. Der Trick dabei war, dass man alles in Gleitkommazahlen berechnet inklusive der Mausposition und ERST beim Übergeben der berechneten Variablen in Integer castet. Ich bekomme nun den exakten Wert für die jeweilige Kachel in meinem Grid und kann jetzt meine Spielfiguren per Mausklick auf dem Spielfeld mittels A* beliebig herumspazieren lassen und es werden sogar nicht begehbare Kacheln berücksichtigt.

Trotzdem vielen Dank für deine Antwort. Ich denke ich habe die Isometrie nun besser im Griff auch dank deiner Antwort. Letztendlich versuche ich ja irgendwann in die dreidimensionale Programmierung zu gelangen und deshalb habe ich mich eben zuerst mit orthogonal und jetzt isometrisch beschäftigt, denn ich denke wie soll ich die dreidimensionale Perspektive vor allem mathematisch verstehen, wenn ich schon Probleme im zweidimensionalen Raum habe.

Im Übrigen bin ich Fan von alten 2D-Klassikern wie Starcraft und AoE und das Nachvollziehen, wie solche Spiele gemacht sind macht mir immensen Spaß.

Das Thema wäre damit dann eigentlich erledigt. Ich denke ich kann jetzt weitermachen an meinem Projekt und Kampfsystem und Ressourcenverwaltung sowie ein einfaches Menü für mein Spiel erstellen.

Bis zu meiner nächsten Frage.
 
Das freut mich wenn du es selbst gelöst hast. So viel Ärger wie man (gerade in der Einstiegszeit in neue Themen) beim Programmieren auch hat, diese vielen kleinen Erfolge lohnen sich doch immer wieder. Als Übung war es mit Sicherheit auch hilfreich. Da du ja anscheinend an einem Spiel arbeitest, könntest du dich früher oder später mal noch in Engine-Design einlesen. Gerade wenn es später in Richtung 3D gehen soll, wirst du das definitiv brauchen.
Und auch die Elemente der linearen Algebra von denen ich oben gesprochen habe werden da zu wichtigen Begriffen (Transformationsmatrix, Weltmatrix, Projektionsmatrix, etc.). Aber auch dafür gibt es gute Bücher die dich sicher in die Thematik einführen.

Gruß Technipion
 
Zurück