1 Reply Latest reply: Oct 9, 2012 4:23 PM by morgalr RSS

    AffineTransform: Rotating too fast.

    959990
      I'm making a simple Asteroids clone, and I'm having some trouble with the AffineTransform in my Ship class. I had it working before, but when I corrected the problem I was having with my translate (instead of creating a new AffineTransform every time the canvas is painted, I created it in the constructor, since the transformations only needed to be applied once), it started giving me trouble. So now, instead of gradually rotating while I hold the arrow keys, and stopping when I let go, it quickly accelerates to the point where you barely notice the rotation anymore, and it doesn't stop when I release the arrow key.

      Here is the JPanel where everything is drawn and updated.
      package jasteroids;
      
      import jasteroids.classes.objects.Bullet;
      import jasteroids.classes.objects.Ship;
      import jasteroids.classes.structures.Vector2D;
      import java.awt.*;
      import java.awt.event.KeyAdapter;
      import java.awt.event.KeyEvent;
      import java.awt.event.MouseAdapter;
      import java.awt.event.MouseEvent;
      import java.awt.geom.AffineTransform;
      import java.awt.geom.Rectangle2D;
      import java.util.ArrayList;
      
      /**
       * Panel used for drawing game objects and animation.
       * @author Darin Beaudreau
       */
      public class AsteroidsPanel extends javax.swing.JPanel implements Runnable {
          // Static variables.
          private static final Dimension P_SIZE = new Dimension(640, 480);
          private static final int THREAD_SLEEP_TIME = 20;
          // Member variables.
          private Thread animate;
          private volatile boolean running = false;
          
          private Point mouse;
          private boolean[] buttons;
          private boolean[] keys;
          
          private Ship ship;
          private AffineTransform shipTransform;
          private ArrayList<Bullet> bullets;
      
          /**
           * Creates new form AsteroidsPanel
           */
          public AsteroidsPanel() {
              mouse = new Point();
              
              buttons = new boolean[2];
              buttons[0] = false;
              buttons[1] = false;
              
              keys = new boolean[3];
              keys[0] = false;
              keys[1] = false;
              keys[2] = false;
              
              int[] x_points = new int[] {  0, -1, 0, 1 };
              int[] y_points = new int[] { -2,  2, 0, 2 };
              int n = 4;
              ship = new Ship(x_points, y_points, n);
              
              shipTransform = new AffineTransform();
              shipTransform.translate((P_SIZE.width / 2), (P_SIZE.height / 2));
              shipTransform.scale(10, 8);
              
              bullets = new ArrayList<>();
              
              setBackground(Color.BLACK);
              setPreferredSize(P_SIZE);
              setFocusable(true);
              requestFocus();
              
              addMouseMotionListener(new MouseAdapter() {
                  @Override
                  public void mouseMoved(MouseEvent m) {
                      mouse.x = m.getX();
                      mouse.y = m.getY();
                  }
                  @Override
                  public void mouseDragged(MouseEvent m) {
                      mouse.x = m.getX();
                      mouse.y = m.getY();
                  }
              });
              
              addMouseListener(new MouseAdapter() {
                  @Override
                  public void mousePressed(MouseEvent m) {
                      int button = m.getButton();
                      if(button == MouseEvent.BUTTON1) buttons[0] = true;
                      if(button == MouseEvent.BUTTON2) buttons[1] = true;
                  }
                  @Override
                  public void mouseReleased(MouseEvent m) {
                      int button = m.getButton();
                      if(button == MouseEvent.BUTTON1) buttons[0] = false;
                      if(button == MouseEvent.BUTTON2) buttons[1] = false;
                  }
                  @Override
                  public void mouseClicked(MouseEvent m) {
                      int button = m.getButton();
                      if(button == MouseEvent.BUTTON1) addBullet();
                  }
              });
              
              addKeyListener(new KeyAdapter() {
                  @Override
                  public void keyPressed(KeyEvent k) {
                      int key = k.getKeyCode();
                      if(key == KeyEvent.VK_LEFT) keys[0] = true;
                      if(key == KeyEvent.VK_RIGHT) keys[1] = true;
                      if(key == KeyEvent.VK_SPACE) keys[2] = true;
                  }
                  @Override
                  public void keyReleased(KeyEvent k) {
                      int key = k.getKeyCode();
                      if(key == KeyEvent.VK_LEFT) keys[0] = false;
                      if(key == KeyEvent.VK_RIGHT) keys[1] = false;
                      if(key == KeyEvent.VK_SPACE) keys[2] = false;
                  }
                  @Override
                  public void keyTyped(KeyEvent k) {
                      int key = k.getKeyCode();
                      if(key == KeyEvent.VK_SPACE) addBullet();
                  }
              });
              
              initComponents();
          }
          
          @Override
          public void paintComponent(Graphics g) {
              super.paintComponent(g);
              Graphics2D g2d = (Graphics2D)g;
      
              AffineTransform save = g2d.getTransform();
      
              Dimension d = getSize();
              int w = d.width;
              int h = d.height;
      
              AffineTransform center = shipTransform;
              center.concatenate(ship.getTransform());
      
              //g2d.setPaint(Color.WHITE);
              //g2d.drawString(("Ship Coords: (" + ship.getBounds2D().getX() + "," + ship.getBounds2D().getY() + ")"), 0, 10);
      
              //g2d.setPaint(Color.WHITE);
              //g2d.drawLine((w / 2), 0, (w / 2), h);
              //g2d.drawLine(0, (h / 2), w, (h / 2));
              
              // Draw the bullets.
              g2d.setPaint(Color.RED);
              for(Bullet b : bullets) {
                  g2d.fill(b);
              }
      
              g2d.setPaint(Color.WHITE);
              g2d.draw(center.createTransformedShape(ship));
      
              g2d.setTransform(save);
          }
      
          public void update() {
              // Update the ship's transformation.
              if(keys[0]) ship.rotate(-ship.ROTATE_SPEED);
              if(keys[1]) ship.rotate(ship.ROTATE_SPEED);
              
              // Update the bullet positions.
              if(!bullets.isEmpty()) {
                  for(int i = 0;i < bullets.size();i++) {
                      Bullet b = bullets.get(i);
                      if((b.getCenterX() == b.getTarget().x)&&(b.getCenterY() == b.getTarget().y)) {
                          bullets.remove(i);
                      } else if((b.getCenterX() < 0)||
                                (b.getCenterX() > P_SIZE.width)||
                                (b.getCenterY() < 0)||
                                (b.getCenterY() > P_SIZE.height)) {
                          bullets.remove(i);
                      } else {
                          Vector2D v_ = new Vector2D((b.getTarget().x - b.x), (b.getTarget().y - b.y));
                          Vector2D n_ = v_.normalize();
                          if(!(n_ == null)) {
                              b.x += n_.x;
                              b.y += n_.y;
                          } else {
                              bullets.remove(i);
                          }
                      }
                  }
              }
          }
          
          public void addBullet() {
              //double x = ship.getBounds2D().getCenterX();
              //double y = ship.getBounds2D().getCenterY();
              double x = shipTransform.getTranslateX();
              double y = shipTransform.getTranslateY();
              
              Bullet b = new Bullet((x - 2), (y - 2), 4, 4, (new Point(mouse.x, mouse.y)));
              
              bullets.add(b);
          }
      
          /**
           * This method is called from within the constructor to initialize the form.
           * WARNING: Do NOT modify this code. The content of this method is always
           * regenerated by the Form Editor.
           */
          @SuppressWarnings("unchecked")
          // <editor-fold defaultstate="collapsed" desc="Generated Code">                          
          private void initComponents() {
      
              javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this);
              this.setLayout(layout);
              layout.setHorizontalGroup(
                  layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                  .addGap(0, 400, Short.MAX_VALUE)
              );
              layout.setVerticalGroup(
                  layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                  .addGap(0, 300, Short.MAX_VALUE)
              );
          }// </editor-fold>                        
          // Variables declaration - do not modify                     
          // End of variables declaration                   
      
          @Override
          public void addNotify() {
              super.addNotify();
              start();
          }
          
          private void start() {
              if((animate == null)||(!running)) {
                  animate = new Thread(this);
                  animate.start();
              }
          }
          
          @Override
          public void run() {
              running = true;
              while(running) {
                  update();
                  repaint();
                  
                  try {
                      Thread.sleep(THREAD_SLEEP_TIME);
                  } catch(InterruptedException e) {}
              }
              System.exit(0);
          }
          
          public void stop() {
              running = false;
          }
      }
      And here is the Ship class.
      package jasteroids.classes.objects;
      
      import java.awt.Polygon;
      import java.awt.Shape;
      import java.awt.geom.AffineTransform;
      
      /**
       * A representation of the player's ship.
       * @author Darin Beaudreau
       */
      public class Ship extends Polygon {
          // Static variables.
          public final double ROTATE_SPEED = (Math.PI / 180) * 1;
          // Member variables.
          private AffineTransform at;
          
          public Ship() { 
              super();
              at = new AffineTransform(); 
          }
          public Ship(int[] x_, int[] y_, int n_) {
              super(x_, y_, n_);
              at = new AffineTransform();
          }
          
          public AffineTransform getTransform() { return at; }
          public Shape createTransformedShape() { return at.createTransformedShape(this); }
          
          public void rotate(double theta_) { at.rotate(theta_); }
          public void scale(double scale_) { at.scale(scale_, scale_); }
          public void scale(double sx_, double sy_) { at.scale(sx_, sy_); }
          public void translate(double tx_, double ty_) { at.translate(tx_, ty_); }
      }
      Does anyone see the problem?
        • 1. Re: AffineTransform: Rotating too fast.
          morgalr
          Sorry for taking so long, but this is the first I've had time to look at your code. You need to slow down your refresh cycle and the number of pixels you offset each cycle.
                  private static final Dimension P_SIZE = new Dimension(640, 480);
                  private static final int THREAD_SLEEP_TIME = 20;
          
                  
                  shipTransform = new AffineTransform();
                  shipTransform.translate((P_SIZE.width / 2), (P_SIZE.height / 2));
                  shipTransform.scale(10, 8);
          640/20=32 pixels along the X axis every paint
          480/16=30 pixels along the Y axis every paint

          1000/20 = 50 paints every second

          So your moving 1600 pixels per second in the X axis and 1500 pixels per second in the Y axis

          You're stuff is probably shooting across the screen so fast you can't see it.