This discussion is archived
1 Reply Latest reply: Oct 9, 2012 2:23 PM by morgalr RSS

AffineTransform: Rotating too fast.

959990 Newbie
Currently Being Moderated
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 Explorer
    Currently Being Moderated
    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.

Legend

  • Correct Answers - 10 points
  • Helpful Answers - 5 points