2017-12-04 2 views
0

Ich mache ein 2D-Spiel in Java, wo der Spieler ein Polygon durch Hindernisse führt. Das Polygon bewegt sich nach oben und unten und die Spielwelt scrollt nach links und rechts. Ich brauche das Polygon um seine Mitte zu drehen, aber da es ständig übersetzt wird, bewegt sich der Punkt, um den es gedreht wird. Der Versuch, es zurück in das ursprüngliche Zentrum zu übersetzen, es zu drehen und es zurück zu übersetzen, funktioniert nicht. Wie bekomme ich das Zentrum der Form?Drehen Sie eine bewegliche Form um ihre Mitte

Hier sind meine Bewegungs Berechnungen auf einem 2 ms-Timer:

@Override 
public void actionPerformed(ActionEvent e) { 

    double theta = angleRad+90; 
    if (up == true) { 
     if (accelerating == false) { 
      time2 = 0; 
      moveX0 = moveX; 
      moveY0 = moveY; 
      accelerating = true; 
     } 
     time1++; 
     double t = time1/500; 
     if (accCount % 10 == 0) { 
      DronePilot.velocity++; 
     } 
     moveX = moveX0 + velX*Math.cos(theta)*t; 
     moveY = moveY0 + velY*Math.sin(theta)*t-(1/2d)*g*Math.pow(t, 2); 
     velX = (DronePilot.velocity)*Math.cos(theta); 
     velY = (DronePilot.velocity)*Math.sin(theta)-g*(t); 
     accCount++; 
    } else if (up == false){ 
     if (accelerating == true) { 
      time1 = 0; 
      moveX0 = moveX; 
      moveY0 = moveY; 
      accelerating = false; 
     } 
     time2++; 
     double t = time2/500; 
     moveX = moveX0 + velX*Math.cos(theta)*t; 
     moveY = moveY0 + velY*Math.sin(theta)*t-(1/2d)*g*Math.pow(t, 2); 
     accCount = 0; 
    } if (left == true) { 
     angleCount++; 
     if (angleCount % 2 == 0) { 
      angleDeg++; 
     } 
     angleRad = Math.toRadians(angleDeg); 
    } else if (right == true) { 
     angleCount--; 
     if (angleCount % 2 == 0) { 
      angleDeg--; 
     } 
     angleRad = Math.toRadians(angleDeg); 
    } 
    repaint(); 
} 
} 

Und hier ist meine Methode paintcomponent:

@Override 
public void paintComponent(Graphics g) { 
    super.paintComponent(g); 
    Graphics2D g2D = (Graphics2D)g; 

    Graphics g2 = g.create(); 
    Graphics2D copy = (Graphics2D)g2; 




    copy.rotate(-angleRad, xPos, yPos); 

    copy.translate(0, -moveY); 

    g2D.translate(-moveX, 0); 

    copy.draw(player.shape); 

    for (Rectangle2D.Double r: DronePilot.rocksFloorArray) { 
     g2D.draw(r); 
    } 
    for (Rectangle2D.Double r: DronePilot.rocksCeilArray) { 
     g2D.draw(r); 
    } 
    for (Rectangle2D.Double r: DronePilot.roomsArray) { 
     g2D.draw(r); 
    } 
} 

wo (xPos, yPos) die Mitte des Bildschirms werden.

+0

Nun, anstatt den 'Graphics' Kontext zu übersetzen, einen' AffineTransform' verwenden.Ich würde annehmen, dass Sie die Position zuerst übersetzen möchten, wird es wesentlich einfacher machen, das Objekt um seine Mittelposition zu drehen. – MadProgrammer

+0

Sie scheinen auch zu übersetzen sowohl 'g2D' als auch' copy', was zu allen Arten von interessanten (aber unerwünscht) Probleme – MadProgrammer

Antwort

1

Transformationen sind (in der Regel) Compoundierung

public void paintComponent(Graphics g) { 
    super.paintComponent(g); 
    Graphics2D g2D = (Graphics2D)g; 

    Graphics g2 = g.create(); 
    Graphics2D copy = (Graphics2D)g2; 

    copy.rotate(-angleRad, xPos, yPos); 
    copy.translate(0, -moveY); 

    g2D.translate(-moveX, 0); 

    copy.draw(player.shape); 
    for (Rectangle2D.Double r: DronePilot.rocksFloorArray) { 
     g2D.draw(r); 
    } 
    for (Rectangle2D.Double r: DronePilot.rocksCeilArray) { 
     g2D.draw(r); 
    } 
    for (Rectangle2D.Double r: DronePilot.roomsArray) { 
     g2D.draw(r); 
    } 
} 

In Ihrem obigen Code übersetzen Sie sowohl den ursprünglichen Graphics Kontext und die copy. In diesem Zusammenhang wird copy nicht durch das Original beeinflusst und das Original wird nicht von der copy beeinflusst, aber der ursprüngliche Kontext ist eine freigegebene Ressource und da Sie die Übersetzung nicht zurücksetzen, erhalten Sie weiterhin ein übersetzter Kontext jedes Mal (Compoundierung).

Als allgemeine Faustregel gilt, führen Sie alle Transformationen auf einer Kopie durch und entsorgen Sie sie, wenn Sie fertig sind.

Zum Beispiel ...

Graphics2D g2d = (Graphics2D)g.create(); 
AffineTransform at = AffineTransform.getTranslateInstance(playerPoint.x, playerPoint.y); 
at.rotate(Math.toRadians(angle), player.getBounds2D().getCenterX(), player.getBounds2D().getCenterY()); 
g2d.setTransform(at); 
g2d.setColor(Color.RED); 
g2d.fill(player); 
g2d.setColor(Color.BLACK); 
g2d.draw(player); 
g2d.dispose(); 

Dies bedeutet im Grunde die Position des Objekts der Position des Spielers und dreht dann das Objekt um den Mittelpunkt des Objekts

Sie könnten auch eine Anwendung Transformation, erstellen Sie eine Kopie dieses Kontextes und wenden Sie eine weitere Umwandlung an, die zusammengesetzt würde (so könnten Sie translate einen Kontext kopieren und dann rotate die Kopie und die erste Übersetzung würde immer noch auf die Kopie angewendet)

Dieses unglaubliche einfache Beispiel zeigt zwei grundlegendes Beispiel ...

  1. Mit dem Graphics Kontext und ein AffineTransform zu übersetzen und zu drehen, um das Spielerobjekt
  2. ein Path2D Verwendung (davon Mittelpunkt ist) eine transformierte Form zu erzeugen, (In diesem Beispiel werden zwei Objekte erstellt, aber Sie können eine einzelne AffineTransform übersetzen und rotieren und sie einmal anwenden).

In beiden Fällen sie haben keinen Einfluss auf die ursprüngliche Form

import java.awt.Color; 
import java.awt.Dimension; 
import java.awt.EventQueue; 
import java.awt.Graphics; 
import java.awt.Graphics2D; 
import java.awt.Point; 
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.Rectangle2D; 
import java.util.Random; 
import javax.swing.JFrame; 
import javax.swing.JPanel; 
import javax.swing.Timer; 

public class Test { 

    public static void main(String[] args) { 
     new Test(); 
    } 

    public Test() { 
     EventQueue.invokeLater(new Runnable() { 
      @Override 
      public void run() { 
       JFrame frame = new JFrame(); 
       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 player; 
     private Point playerPoint; 
     private float angle; 
     private float deltaZ = 1.0f; 

     private int deltaX, deltaY; 

     public TestPane() { 
      player = new Rectangle(0, 0, 20, 20); 
      playerPoint = new Point(80, 80); 
      Random rnd = new Random(); 
      deltaX = 1; 
      deltaY = -1; 

      Timer timer = new Timer(5, new ActionListener() { 
       @Override 
       public void actionPerformed(ActionEvent e) { 
        playerPoint.x += deltaX; 
        playerPoint.y += deltaY; 

        Shape rotatedPlayer = rotatedAndTranslatedPlayer(); 
        Rectangle2D bounds = rotatedPlayer.getBounds2D(); 
        if (bounds.getX() < 0.0) { 
         playerPoint.x = (int)(bounds.getX() * -1); 
         deltaX *= -1; 
        } else if (bounds.getX() + bounds.getWidth() >= getWidth()) { 
         playerPoint.x = getWidth() - (int)bounds.getWidth(); 
         deltaX *= -1; 
        } 
        if (bounds.getY() < 0) { 
         playerPoint.y = 0; 
         deltaY *= -1; 
        } else if (bounds.getY() + bounds.getHeight() > getHeight()) { 
         playerPoint.y = getHeight() - (int)bounds.getHeight(); 
         deltaY *= -1; 
        } 
        angle += deltaZ; 
        repaint(); 
       } 
      }); 
      timer.start(); 
     } 

     @Override 
     public Dimension getPreferredSize() { 
      return new Dimension(200, 200); 
     } 

     protected Shape rotatedAndTranslatedPlayer() { 
      Path2D.Double rotated = new Path2D.Double(player, AffineTransform.getRotateInstance(
        Math.toRadians(angle), 
        player.getBounds2D().getCenterX(), 
        player.getBounds2D().getCenterY())); 
      return new Path2D.Double(rotated, AffineTransform.getTranslateInstance(playerPoint.x, playerPoint.y));    
     } 

     // Simply paints the "area" that the player takes up when it's rotated and 
     // translated 
     protected void paintAutoTranslatedShape(Graphics2D g2d) { 
      g2d.setColor(Color.DARK_GRAY); 
      g2d.fill(rotatedAndTranslatedPlayer().getBounds2D()); 
     } 

     // Uses a AffineTransform to translate and rotate the player 
     protected void paintPlayer(Graphics2D g2d) { 
      AffineTransform at = AffineTransform.getTranslateInstance(playerPoint.x, playerPoint.y); 
      at.rotate(Math.toRadians(angle), player.getBounds2D().getCenterX(), player.getBounds2D().getCenterY()); 
      g2d.setTransform(at); 
      g2d.setColor(Color.RED); 
      g2d.fill(player); 
      g2d.setColor(Color.BLACK); 
      g2d.draw(player); 
     } 

     @Override 
     protected void paintComponent(Graphics g) { 
      super.paintComponent(g); 
      Graphics2D g2d = (Graphics2D) g.create(); 
      paintAutoTranslatedShape(g2d); 
      g2d.dispose(); 
      g2d = (Graphics2D) g.create(); 
      paintPlayer(g2d); 
      g2d.dispose(); 
     } 

    } 
} 
+0

Folgefrage: Was ist der Unterschied zwischen dem Erzeugen und Zeichnen eines Path2D, dem Erzeugen und Zeichnen einer createTransformedShape und dem Anwenden der AffineTransform auf den Grafikkontext und dessen Zeichnen? Alle diese haben mir verschiedene Ergebnisse in Tests gegeben. – Denis

+0

Das Transformieren der Form ermöglicht es Ihnen, 1: Eine Kopie der Form zu generieren, die basierend auf der'AffineTransform' transformiert wurde. Sie wirkt sich nicht auf andere Formen aus, hat aber auch keinen Einfluss auf die ursprüngliche Form. 2: Es hat keinen Einfluss auf den 'Graphics'-Kontext, der, wie Sie herausgefunden haben, Probleme verursachen kann, wenn Sie nicht vorsichtig sind; 3: Sie können Entscheidungen über die transformierte Form treffen, ohne einen 'Graphics'-Kontext zu benötigen, da ich die Grenzen überprüft habe; Der Nachteil ist, dass Sie ein anderes Objekt erstellen. Wenn Sie viele schnelle Änderungen vornehmen, kann dies die Leistung beeinträchtigen, da der GC mehr zu tun hat – MadProgrammer

0

In openGL speichern wir den Umwandlungsstatus mit pushMatrix() und popMatrix(). Hier ihre Äquivalente sind Graphics.create() und Graphics.dispose()

Graphics g1 = g.create(); 
//do transformations 
g1.dispose(); 

Graphics g2 = g.create(); 
//do other stuff 
g2.dispose();