Scaling Probleme

Eichelhäer

Bekanntes Mitglied
Hallo,

ich bin gerade dabei mein Spiel mit Hilfe der graphics2D API zu skalieren.
Für meine Zwecke reicht erstmal das rudimentäre Scalen ohne AffineTransform. Das klappt auch wunderbar. Die beiden Probleme die ich dabei habe sind:

Die Skalierung rein/raus bezieht sich immer nur auf die linke obere Ecke, die auch gleichzeitig meine Cameraposition ist und verschoben wird. Aber ich möchte die Skalierung bzgl meiner aktuellen Mausposition erreichen.

Und wenn ich skaliere werden ja meine Objekte größer bzw. kleiner und haben nach der skalierung eine andere Position und größe auf dem Screen. Das rendern klappt einfach mit dem Aufruf von graphics2D.scale(zoomX,zoomY), Aber die Größe nach der Skalierung bleibt die gleiche. Ich benötige aber die Größe und Position nach der Skalierung, um die Objekte auch auswählen zu können.

Ich hoffe meine 2 Probleme sind nachvollziehbar.

Wäre für Hilfe dankbar.

Mfg

Eichelhäer
 
Bei so Dingen solltest Du Dir das immer aufmalen - dann kann man das meist einfach herleiten. Dabei evtl. auf diverse Ebenen trennen.

Unter 2.6. Client Implementation | JAdventure - Kurs zur Softwareentwicklung wird das etwas aufgezeigt. Du hast ein Level mit einer bestimmten Größe und ein Ausschnitt wird davon angezeigt. Die Mitte soll dabei immer die Mitte bleiben auch beim Zoomen.

Wenn Du die Position in dem Level hast, dann kannst Du Dir von da ausrechnen, wie groß der Ausschnitt des Bildes ist, das Du anzeigst. Und damit hast Du dann die entsprechenden Werte.

Da ist aber immer die Frage, was für Daten Du genau gespeichert hast - daraus folgt dann immer die Berechnung aller anderen Dinge. Somit fehlen mir schlicht die Grundlagen, Dir hier für Dein genaues Problem konkrete Antworten zu geben.
 
Was für Daten bräuchtest Du denn? Also ich hab das jetzt mit dem Fenster Mittelpunkt das passt jetzt, um ohne meinen FOW zu zoomen. Das Problem ist nun eben mein FOW. Dieser besteht einfach aus einem BufferedImage mit einer transparenten Farbe, das ich über den sichtbaren Bereich lege. Für dieses Bild müsste ich nun die Positionen und die Größe bestimmen. D.h. ich habe ein graphics2D Objekt als Haupt Graphicsobject und für den FOW ein eigenes.
 
Zuletzt bearbeitet:
Ich poste mal den relevanten Code ohne irgendwas:

Java:
BufferedImage fogOfWar = new BufferedImage(game.canvas.getWidth(),game.canvas.getHeight(),BufferedImage.TYPE_INT_ARGB);

        Graphics2D FOVgraphics2D = fogOfWar.createGraphics();
        Rectangle2D greyFog = new Rectangle2D.Double(0,0,game.canvas.getWidth(),game.canvas.getHeight());

        FOVgraphics2D.setColor(new Color(0,0,0,128));
        FOVgraphics2D.fill(greyFog);

        Composite fogOfWarAC = FOVgraphics2D.getComposite();
        FOVgraphics2D.setComposite(AlphaComposite.getInstance(AlphaComposite.CLEAR));

        BufferedImage blackFogOfWar = new BufferedImage(game.canvas.getWidth(),game.canvas.getHeight(),BufferedImage.TYPE_INT_ARGB);

        Graphics2D BlackFOVgraphics2D = blackFogOfWar.createGraphics();
        Rectangle2D blackFog = new Rectangle2D.Double(0,0,game.canvas.getWidth(),game.canvas.getHeight());

        BlackFOVgraphics2D.setColor(Color.BLACK);
        BlackFOVgraphics2D.fill(blackFog);

        Composite blackFogOfWarAC = BlackFOVgraphics2D.getComposite();
        BlackFOVgraphics2D.setComposite(AlphaComposite.getInstance(AlphaComposite.CLEAR));

        Collections.sort(gameObjects, new Comparator<>() {
            @Override
            public int compare(GameObject o1, GameObject o2) {

                Point2D pIso1 = new Point2D.Double(o1.tilePosition.getX()+Math.floor(o1.solidWidth/2.0),o1.tilePosition.getY()+Math.floor(o1.solidHeight/2.0));
                Point2D pIso2 = new Point2D.Double(o2.tilePosition.getX()+Math.floor(o2.solidWidth/2.0),o2.tilePosition.getY()+Math.floor(o2.solidHeight/2.0));

                Point2D pScreen1 = game.gameWorld.isoToScreen(pIso1);
                Point2D pScreen2 = game.gameWorld.isoToScreen(pIso2);

                return Double.compare(pScreen1.getY(),pScreen2.getY());
            }
        });

        for(int i = 0;i<gameObjects.size();i++) {

            GameObject gameObject = gameObjects.get(i);

            // Hier werden die runden Viewfields ausgeschitten
            
            FOVgraphics2D.translate(-game.gameCamera.x, -game.gameCamera.y);
            FOVgraphics2D.fill(gameObject.viewField);
            FOVgraphics2D.translate(game.gameCamera.x, game.gameCamera.y);

            BlackFOVgraphics2D.translate(-game.gameCamera.x, -game.gameCamera.y);
            BlackFOVgraphics2D.fill(gameObject.viewFielArea);
            BlackFOVgraphics2D.translate(game.gameCamera.x, game.gameCamera.y);

            gameObject.render(graphics2D);
        }

        FOVgraphics2D.setComposite(fogOfWarAC);
        BlackFOVgraphics2D.setComposite(blackFogOfWarAC);

        // Hier wird der Fog gezeichnet
        
        graphics2D.drawImage(fogOfWar,null,game.gameCamera.x,game.gameCamera.y);
        //graphics2D.drawImage(blackFogOfWar,null,game.gameCamera.x,game.gameCamera.y);

Außerdem habe ich den relevanten Skalierungsfaktor berechnet. D.h. wenn ich reinzoome wird der Faktor maximal 1.5 groß und -05 wenn ich rauszoome. Das Zoomen funktioniert wunderbar für die Map, jedoch nicht für das BufferedImage.
 
Ich habe gerade nicht die Zeit, mir das im Detail anzusehen. Du kannst aber gerne einmal schauen, wie ich diese Thematik bei JAdventure gelöst habe. Der Part ist ja soweit fertig umgesetzt, auch wenn da die Videos zur Implementation noch immer (seit nun einem 3/4 Jahr) ausstehen.
 
Hallo nochmal,

ich habe nun das rudimentäre Scaling in der Bildschirmmitte mit offsets und scalingfaktoren hinbekommen. Ich verwende die Garphics2D Api und translatiere und skaliere nur über das graphics2D objekt. Das Problem ist nun, dass ich meine GameObjekte nicht mehr wie gewohnt selektieren kann sobald sich der scaling faktor ändert. Außerdem behalten meine boundingBoxes, rein rechnerisch immer die gleiche position, obwohl das scaling die Größe der bounding Box und der Sprites augenscheinlich korrekt ändert.

Daher hier die Frage: Wie erhalte ich die neue Screen Koordinaten sowie die größe der bounding Boxen nach dem skalieren?

Oder wäre es hier besser auf die graphics2D Api komplett zu verzichten und alles von Hand auszurechnen?
 
Also wenn Du skalierst, dann musst Du Koordinaten umrechnen und auch die bounding Boxen anpassen. Dabei ist es egal, an welcher Stelle du die Skalierung durchführst.

Generell gilt hier aus meiner Sicht auch: Separation of Concerns.

Du solltest also auch hier sauber trennen:
  • Model: Du hast also irgend ein Model. Dieses kennt keine Skalierung oder so, da dies eine Frage der Darstellung ist. Die Elemente des Model haben also irgend welche Koordinaten und Größen und damit kannst Du dann z.B. Kollisionen und so bestimmen inkl. dem notwendigen Verhalten.
  • Darstellung - die Darstellung ist davon komplett getrennt. Im Client hast Du dann ggf. eine Skalierung der Anzeige, weil der Anwender rein und raus zoomen kann. Die Kernproblematk bleibt aber natürlich bestehen: Du wirst hier eine Umrechnung brauchen, denn Du hast zwei Koordinatensysteme: Neben den von dem Model hast du eine Darstellung auf dem Bildschirm und da musst Du dann ggf auf ein Mausklick reagieren oder so.

Ich selbst habe die Skalierung in JAdventure, welches ein 2D Level hat, im Client rein über die Darstellung des Bildes gemacht. Ein Level hat ein Bild, Objekte haben Bilder ... diese werden dann in der vorgegebenen Größe gezeichnet. Da gibt es dann keine Skalierung.
Erst wenn dann das Endergebnis angezeigt wird: Da gibt es dann die Skalierung. Und das kann man dann mit einem einfachen Faktor ausrechnen. Die Koordinate xm,ym wird dann in der Darstellung xd,yd mit xd = xm*sf, yd = ym,*sf mit
xm/ym die x/y Koordinate des Model
xd/yd die x/y Koordinate in der Darstellung
sf dem Skalierungsfaktor.

Die Bildschirm-Koordinate xb,yb wird dann natürlich noch durch ein Offset (ox, oy) gekennzeichnet. Es wird ja nur ein Ausschnitt des Levels gezeigt.
xb = xd - ox
yb = yd - oy
ox,oy ist dann der obere linke Punkt der Darstellung vom darzustellenden Level.

Sowas immer aufzeichnen - dann ist es relativ einfache Mathematik und man kann die Formeln schnell und einfach aufstellen. Dazu am besten eigene Klassen schreiben, die dann entsprechend umgerechnet werden können.
(Das fehlt bei mir noch - die Idee hatte ich selbst noch nicht... )
 

Zurück
Oben