Sean Halnon
Sean Halnon

Reputation: 21

How come this AffineTransform rotation method works?

Ive been programming a game just to become better at java. I had been having alot of trouble with getting the player rotation to work correctly. My first method used this

g2.setTransform(AffineTransform.getRotateInstance(radAngle,x_pos + (img.getWidth() / 2),y_pos+(img.getHeight() / 2)));

However this caused all images to rotate with the player thus making shooting and aiming completely disfunctional. i was researching and saw someone use this code to make they're player rotate.

    Graphics2D g2 = (Graphics2D)g;
           AffineTransform oldTransform = g2.getTransform();
    AffineTransform newOne = (AffineTransform)(oldTransform.clone());
    newOne.rotate(radAngle,x_pos + (img.getWidth() / 2),y_pos+ (img.getHeight()  / 2));
    g2.setTransform(newOne);
    g2.drawImage(img, x_pos,y_pos,this);
    repaint();
    g2.setTransform(oldTransform);

This works great and i dont have the same problems i had before. However i dont know why.

Heres my full code. The code above is for the body of the paint method.

import java.applet.*;
import java.awt.*;
import java.awt.event.*;
import java.awt.image.BufferedImage;
import java.lang.Math.*;
import java.awt.Graphics2D;
import java.awt.geom.AffineTransform;
import javax.imageio.ImageIO;
import java.io.*;
import java.net.URL;
import java.util.ArrayList;

public class Game extends Applet implements Runnable, KeyListener, MouseMotionListener, MouseListener
{
//pos variables keep track of the current position of the player
int x_pos = 250;
int y_pos = 250;
//speed variables keep track of the speed/how many pixels will be added to position during this iteration of the thread
float x_speed = 0;
float y_speed = 0;
int radius = 25;
//denotes the boundries of the applet
int appletsize_x = 800;
int appletsize_y = 600;
//the x and y variables mark whether a movement key is being pressed thats telling the object to move on
//on of those axes's
int x = 0;
int y = 0;
//variables that will indicate whether one of those keys are being depressed
int up = 0;
int down= 0;
int left = 0;
int right= 0;

int mouse_x;
int mouse_y;
int tracking_angle;
//getting some images.
private BufferedImage dbImage;
private BufferedImage test;
private Graphics dbg;
private  Image curser;
BufferedImage img = null;
BufferedImage round = null;
   double x_dist;
    double y_dist;



//i dont use this AffineTransform, although ill leave it here just incase i decide to use it if i continue working
//on this independently.
AffineTransform at = new AffineTransform();
//the angle of the mouse to the player object.
double radAngle;
public void init()
{


        try {
           URL url = new URL(getCodeBase(), "UFO.png");
           img = ImageIO.read(url);
        } catch (IOException e) {System.out.println("Cant find player image");
    }
                    try {
                       URL url = new URL(getCodeBase(), "round.png");
                       round = ImageIO.read(url);}
         catch (IOException e) {System.out.println("round not loading");}

    setBackground (Color.black);
    setFocusable(true);
    addKeyListener( this );
    curser = getImage(getDocumentBase(), "mouse.png");
    addMouseMotionListener(this);
    addMouseListener(this);
    try
    //changing the curser to the  crosshair image
            {
                Toolkit tk = Toolkit.getDefaultToolkit();
                Cursor c = tk.createCustomCursor( curser,new Point( 5, 5 ), "Cross_Hair" );
                setCursor( c );
            }
            catch( IndexOutOfBoundsException x )
            {System.out.println("Cross_hair");}
}

public class Shot {
    final double angle = radAngle;
    double x_loc;
    double  y_loc;
    double X;
    double Y;

    public Shot(){
        x_loc += x_pos;
        y_loc += y_pos;
        X=Math.cos(radAngle)*5;
        Y=Math.sin(radAngle)*5;
    }

    public void move(){

    x_loc += X;
    y_loc += Y;}
            }
//start the thread
public void start ()
{

    Thread th = new Thread (this);

    th.start ();

}

public void stop()
{

}

public void destroy()
{

}
//cathces the mouseEvent when the mosue is moved.
public void mouseClicked(MouseEvent e){}
public void mousePressed(MouseEvent e){
Shot shoot = new Shot();
shots.add(shoot);}
public void mouseEntered(MouseEvent e){}
public void mouseExited(MouseEvent e){}
public void mouseReleased(MouseEvent e){}
public void mouseMoved(MouseEvent e){
    //get position of mouse
    mouse_x = e.getX();
    mouse_y = e.getY();
    //get the distence from the player to the

    //i calculate the actual angle of the mosue from the player object in radians




    //this exists more just for debugging purposes since radians make no sense to me
    tracking_angle = 90;

    }
public void mouseDragged(MouseEvent e){
    mouse_x = e.getX();
    mouse_y = e.getY();
    Shot shoot = new Shot();
    shots.add(shoot);}

//this method sets the key variables to zero when the keys are released
public void keyReleased(KeyEvent r)
{
    //Right
    if (r.getKeyCode()  == 68 ){
        x = 0;
        left = 0;

        }
    //Left
    if (r.getKeyCode() == 65){
        x = 0;
        right = 0;
        }
    //Up
    if (r.getKeyCode() == 87 ) {
        //y_speed = 0;
        down = 0;}
    //Down
    if (r.getKeyCode() == 83 ) {
        //y_speed = 0;
        up = 0;}
        //move();
}
public void keyTyped(KeyEvent t){}
//changes the variables when a key is pressed so that the player object will move
public void keyPressed(KeyEvent r){


    //right
    if (r.getKeyCode()  == 68 ){
        left = 1;
        }
    //left
    if (r.getKeyCode() == 65){
        right = 1;}
    //Down
    if (r.getKeyCode() == 87 ) {
        down = 1;}
    //Up
    if (r.getKeyCode() == 83) {
        up = 1;}
        //move();
}

//sorta like the body of the thread i think
public void run ()
{


    Thread.currentThread().setPriority(Thread.MIN_PRIORITY);


    while (true)
    {
        System.out.println(Math.tan(radAngle)/1);
        x_dist = mouse_x - x_pos;
        y_dist = mouse_y - y_pos;

        radAngle = Math.atan2(y_dist , x_dist);
        //if(tracking_angle < 0){
            //tracking_angle = absT
        if (left  == 1 && x_speed < 11){
            x = 0;
            x_speed += 1;
            }
        //Right
        if (right == 1 && x_speed > -11){
            x = 0;
             x_speed -= 1;
            }
        //Down
        if (down == 1  && y_speed > -11) {
            y_speed -= 1;}
        //Up
        if (up == 1  && y_speed < 11) {
        y_speed += 1;}
    if( x == 0 && x_speed > 0){
        x_speed -=.2;}
    if( x == 0 && x_speed < 0){
        x_speed +=.2;}
    if( y == 0 && y_speed > 0){
        y_speed -=.2;}
    if( y == 0 && y_speed < 0){
        y_speed +=.2;}



        if (x_pos > appletsize_x - radius && x_speed > 0)
        {

            x_pos = radius;
        }

        else if (x_pos < radius && x_speed < 0)
        {

            x_pos = appletsize_x + radius ;
        }

        if (y_pos > appletsize_y - radius && y_speed > 0){
            y_speed = 0;}
        else if ( y_pos < radius && y_speed < 0  ){
                y_speed = 0;}

        x_pos += (int)x_speed;
        y_pos += (int)y_speed;


        repaint();

        try
        {

            //tells the thread to wait 15 milliseconds util it executes again.
            Thread.sleep (15);


        }
        catch (InterruptedException ex)
        {

        }


        Thread.currentThread().setPriority(Thread.MAX_PRIORITY);
    }
}


public void update (Graphics g)
{

    if (dbImage == null)
    {
        dbImage = new BufferedImage(this.getSize().width, this.getSize().height, BufferedImage.TYPE_INT_RGB);
        dbg = dbImage.getGraphics ();
    }


    dbg.setColor (getBackground ());
    dbg.fillRect (0, 0, this.getSize().width, this.getSize().height);


    dbg.setColor (getForeground());
    paint (dbg);
    shot_draw(dbg);


    g.drawImage (dbImage, 0, 0, this);



}

ArrayList<Shot> shots = new ArrayList<Shot>();
double last_angle = 1000;

public void paint (Graphics g){

    Graphics2D g2 = (Graphics2D)g;
    AffineTransform oldTransform = g2.getTransform();
    AffineTransform newOne = (AffineTransform)(oldTransform.clone());
    newOne.rotate(radAngle,x_pos + (img.getWidth() / 2),y_pos+(img.getHeight() / 2));
    g2.setTransform(newOne);
    g2.drawImage(img, x_pos,y_pos,this);
    repaint();
    g2.setTransform(oldTransform);
   // g2.setTransform(AffineTransform.getRotateInstance(radAngle,x_pos +   (img.getWidth() / 2),y_pos+(img.getHeight() / 2)));
    //g2.getTransform().setToIdentity();


}
public void shot_draw(Graphics g){

    Graphics2D g2 = (Graphics2D)g;
//        Shot shoot = new Shot();
//        shots.add(shoot);
    for(Shot i: shots){
        g2.drawImage(round,(int)i.x_loc+40,(int)i.y_loc+40,this);
        i.move();}


        }}

Here are the images I'm using:

Upvotes: 2

Views: 2847

Answers (2)

Gravity
Gravity

Reputation: 2744

The AffineTransform object is connected to the Graphics2D object via the call to setTransform. Once connected, the transform causes every object drawn using the Graphics2D object to be drawn with that same transform (in this case, rotation) applied to it until a new AffineTransform is assigned to the Graphics2D object via another call to setTransform. The sample code you found saved the old transform (which presumably encodes a normal, non-rotated state) via

AffineTransform oldTransform = g2.getTransform();

The code then created the rotation transform and connected it to the Graphics2D (now all objects drawn would be rotated until a new transform be assigned), then drew the one object that needed to be drawn rotated (which therefore had the newly-created rotation transform applied to it), and then restored the original, non-rotating transform to the Graphics2D object via:

g2.setTransform(oldTransform);

That way, the transform that would be applied to subsequent objects would be the original, non-rotating transform.

Upvotes: 1

Hovercraft Full Of Eels
Hovercraft Full Of Eels

Reputation: 285415

This makes sense since if you don't reset the Graphics object's AffineTransform back to its baseline, it will use the new transform to draw everything including all images. I don't understand however why you have a call to repaint() from within your paint method. You shouldn't do this.

Upvotes: 1

Related Questions