这个 AffineTransform 旋转方法是如何工作的?

发布于 2024-11-27 04:21:32 字数 9033 浏览 0 评论 0原文

我一直在编写游戏只是为了提高 java 水平。我在让球员轮换正常工作方面遇到了很多麻烦。我的第一个方法使用了这个

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

,但是这导致所有图像随着玩家旋转,从而使射击和瞄准完全不起作用。 我正在研究并看到有人使用此代码来使他们成为玩家轮换。

    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);

这非常有效,而且我没有遇到以前遇到的相同问题。但我不知道为什么。

这是我的完整代码。上面的代码是paint方法的主体。

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();}


        }}

以下是我正在使用的图像:

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:

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

东北女汉子 2024-12-04 04:21:32

这是有道理的,因为如果您不将 Graphics 对象的 AffineTransform 重置回其基线,它将使用新的变换来绘制包括所有图像在内的所有内容。但是,我不明白为什么您要在 paint 方法中调用 repaint() 。你不应该这样做。

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.

猥︴琐丶欲为 2024-12-04 04:21:32

AffineTransform 对象通过调用 setTransform 连接到 Graphics2D 对象。连接后,变换会导致使用 Graphics2D 对象绘制的每个对象都应用相同的变换(在本例中为旋转)进行绘制,直到分配新的 AffineTransform 为止通过再次调用 setTransformGraphics2D 对象。您发现的示例代码通过

AffineTransform oldTransform = g2.getTransform();

代码创建了旋转变换并将其连接到 Graphics2D (现在绘制的所有对象都将旋转,直到分配新的变换为止),然后绘制需要旋转绘制的一个对象(因此应用了新创建的旋转变换),然后恢复原始对象,非旋转变换为Graphics2D 对象通过:

g2.setTransform(oldTransform);

这样,应用于后续对象的变换将是原始的非旋转变换。

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.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文