Java 玩家对象移动一个方向但转向另一个方向

Java 玩家对象移动一个方向但转向另一个方向,java,swing,graphics,trigonometry,radians,Java,Swing,Graphics,Trigonometry,Radians,当游戏第一次开始时,玩家将从0(右)方向开始。按向右键(vk_right)将播放器精灵向左旋转,但方向设置为将播放器发送到(看起来)正确的方向。左键和右键更改角色的方向变量,而上/下键加速/减速角色 我不太擅长三角学,所以我可能在这里和那里有一些错误(这就是为什么我张贴这篇文章)。我似乎不明白如何让角色朝着他“看”的方向移动(方向变量) 下面是Player.java类: package rpg2d; import java.awt.Image; import java.awt.event.Ke

当游戏第一次开始时,玩家将从0(右)方向开始。按向右键(vk_right)将播放器精灵向左旋转,但方向设置为将播放器发送到(看起来)正确的方向。左键和右键更改角色的方向变量,而上/下键加速/减速角色

我不太擅长三角学,所以我可能在这里和那里有一些错误(这就是为什么我张贴这篇文章)。我似乎不明白如何让角色朝着他“看”的方向移动(方向变量)

下面是Player.java类:

package rpg2d;

import java.awt.Image;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;

import javax.swing.ImageIcon;

public class Player implements KeyListener{

    private double x,y,direction;
    private double speed;
    private final int max_speed;
    private int hp,lives;
    private Image img;
    //other variables

    public Player(int x, int y, int hp, int lives, String imgpath) {
        this.x = x;
        this.y = y;
        this.hp = hp;
        this.lives = lives;
        img = new ImageIcon(this.getClass().getResource(imgpath)).getImage();
        //loads the player image from the string path
        max_speed = 6;
        speed = 0;
        direction = 0;
    }

    //returns the direction the player is 'facing' as an int
    public int getDirection() {
        return (int)direction;
    }

    //updates the player's location
    public void move() {
        x += speed * Math.cos(-1*direction);
        y += speed * Math.sin(-1*direction);
    }

    @Override
    public void keyPressed(KeyEvent e) {
        int key = e.getKeyCode();
        if(key == KeyEvent.VK_LEFT){
            turn(.6);
            //this is meant to turn the player int a clockwise direction by 0.6
        } else if (key == KeyEvent.VK_RIGHT){
            turn(-.6);
            //counterclockwise by 0.6
        }
        if (key == KeyEvent.VK_DOWN){
            speed -= 0.3;
            if(speed < 0) speed = 0;
            //decelerate until stopped
        } else if (key == KeyEvent.VK_UP){
            speed += 0.3;
            if(speed > max_speed) speed = max_speed;
            //accelerates until it hits maximum speed
        }
    }

    private void turn(double degrees) {
        direction += degrees;
        if(direction > 180) direction -= 180;
        else if(direction < -180) direction += 180;
        /* I honestly don't know whether 180 and -180 are the max and min
         * for Polar Coordinates, so this could be a problem.
         */
    }

    @Override
    public void keyReleased(KeyEvent e) {
    }

    @Override
    public void keyTyped(KeyEvent arg0) {
    }

    public int getX() {
        return (int)x;
    }

    public int getY() {
        return (int)y;
    }

    public double getWidth() {
        return img.getWidth(null);
    }

    public double getHeight() {
        return img.getHeight(null);
    }

    public Image getImg() {
        return img;
    }

}

我做了一些改进:

  • 当执行Cos和Sin时,必须将度转换为弧度,因为这些函数采用弧度(弧度是度的不同单位)
  • 我更改了左右键的-和+。按照惯例,逆时针方向是增加的,而不是相反方向;)
  • 我修改了转弯方法,因为它有一些小错误(-180在三角中是0)
  • 如果有更多错误,请发表评论,我再看一眼:) 祝你好运

    public void move() {
        x += speed * Math.cos(Math.toRadians(direction));
        y += speed * Math.sin(Math.toRadians(direction));
    }
    
    @Override
    public void keyPressed(KeyEvent e) {
        int key = e.getKeyCode();
        if(key == KeyEvent.VK_LEFT){
            turn(-.6);
            //this is meant to turn the player int a clockwise direction by 0.6
        } else if (key == KeyEvent.VK_RIGHT){
            turn(.6);
            //counterclockwise by 0.6
        }
       .....//rest of code}
    
    private void turn(double degrees) {
        direction += degrees;
        if(direction > 180) direction = 180;
        else if(direction < 180) direction = 0;
        }
    
    公共作废移动(){
    x+=速度*Math.cos(Math.toRadians(方向));
    y+=速度*Math.sin(Math.toRadians(方向));
    }
    @凌驾
    按下公共无效键(按键事件e){
    int key=e.getKeyCode();
    if(key==KeyEvent.VK_左){
    转(-.6);
    //这意味着将玩家int顺时针旋转0.6圈
    }else if(key==KeyEvent.VK_RIGHT){
    转弯(.6);
    //逆时针方向0.6
    }
    ..…//代码的其余部分}
    私人空位转弯(双度){
    方向+=度;
    如果(方向>180)方向=180;
    否则,如果(方向<180)方向=0;
    }
    
    我做了一些改进:

  • 当执行Cos和Sin时,必须将度转换为弧度,因为这些函数采用弧度(弧度是度的不同单位)
  • 我更改了左右键的-和+。按照惯例,逆时针方向是增加的,而不是相反方向;)
  • 我修改了转弯方法,因为它有一些小错误(-180在三角中是0)
  • 如果有更多错误,请发表评论,我再看一眼:) 祝你好运

    public void move() {
        x += speed * Math.cos(Math.toRadians(direction));
        y += speed * Math.sin(Math.toRadians(direction));
    }
    
    @Override
    public void keyPressed(KeyEvent e) {
        int key = e.getKeyCode();
        if(key == KeyEvent.VK_LEFT){
            turn(-.6);
            //this is meant to turn the player int a clockwise direction by 0.6
        } else if (key == KeyEvent.VK_RIGHT){
            turn(.6);
            //counterclockwise by 0.6
        }
       .....//rest of code}
    
    private void turn(double degrees) {
        direction += degrees;
        if(direction > 180) direction = 180;
        else if(direction < 180) direction = 0;
        }
    
    公共作废移动(){
    x+=速度*Math.cos(Math.toRadians(方向));
    y+=速度*Math.sin(Math.toRadians(方向));
    }
    @凌驾
    按下公共无效键(按键事件e){
    int key=e.getKeyCode();
    if(key==KeyEvent.VK_左){
    转(-.6);
    //这意味着将玩家int顺时针旋转0.6圈
    }else if(key==KeyEvent.VK_RIGHT){
    转弯(.6);
    //逆时针方向0.6
    }
    ..…//代码的其余部分}
    私人空位转弯(双度){
    方向+=度;
    如果(方向>180)方向=180;
    否则,如果(方向<180)方向=0;
    }
    
    增加迪恩的努力

    在没有图像的情况下,我创建了一个简单的箭头形状,它开始指向右边

    public Player(int x, int y, int hp, int lives, String imgpath) {
        this.x = x;
        this.y = y;
        this.hp = hp;
        this.lives = lives;
        //img = new ImageIcon(this.getClass().getResource(imgpath)).getImage();
    
        BufferedImage arrow = new BufferedImage(16, 16, BufferedImage.TYPE_INT_ARGB);
        Graphics2D g2d = arrow.createGraphics();
        g2d.setColor(Color.RED);
        g2d.drawLine(0, 0, 16, 8);
        g2d.drawLine(16, 8, 0, 16);
        g2d.drawLine(0, 16, 0, 0);
        g2d.dispose();
        img = arrow;
    
        max_speed = 6;
        speed = 0;
        direction = 0;
    }
    
    现在,这个渲染开始时很好

    当我开始移动播放器时,我遇到了一些问题,所以我稍微更新了画图代码

    @Override
    public void paintComponent(Graphics g) {
        super.paintComponent(g);
        Graphics2D g2d = (Graphics2D) g.create();
        AffineTransform trans = new AffineTransform();
        trans.setToIdentity();
        trans.translate(player.x, player.y);
        trans.rotate(Math.toRadians(player.getDirection()), player.getWidth() / 2, player.getHeight() / 2);
        g2d.setTransform(trans);
        g2d.drawImage(player.getImg(), 0, 0, (int) player.getWidth(), (int) player.getHeight(), null);
        g2d.dispose();
    
        g2d = (Graphics2D) g.create();
        g2d.drawString("X: " + player.getX() + " Y: " + player.getY(), 5, 10);
        g2d.dispose();
        trans.setToIdentity();
    }
    
    基本上,我复制了
    图形
    上下文

    Graphics2D g2d = (Graphics2D) g.create();
    
    使用
    仿射变换
    ,我将上下文转换为玩家的当前位置,这简化了旋转代码,因为我不需要偏移锚点

    trans.translate(player.x, player.y);
    trans.rotate(Math.toRadians(player.getDirection()), player.getWidth() / 2, player.getHeight() / 2);
    
    这也意味着更容易绘制图像

    g2d.drawImage(player.getImg(), 0, 0, (int) player.getWidth(), (int) player.getHeight(), null);
    
    这一切的美妙之处在于,所有更改都与
    图形
    上下文的副本相关,您不需要“撤消”所有更改…只是不要忘记在完成后处理副本

    我也不鼓励您使用
    keylister
    ,而是更喜欢使用

    我还将
    线程
    java.util.Timer
    替换为
    javax.swing.Timer

    public void gameLoop() {
        Timer timer = new Timer(16, new ActionListener() {
    
            @Override
            public void actionPerformed(ActionEvent e) {
                update();
                screen.repaint();
            }
        });
        timer.start();
    }
    

    另外,请注意,
    scheduleAtFixedRate
    的最后一个参数是调用之间的毫秒数,因此您当前的代码大约生成16fps。60fps大约是16毫秒…

    加上Dean的努力

    在没有图像的情况下,我创建了一个简单的箭头形状,它开始指向右边

    public Player(int x, int y, int hp, int lives, String imgpath) {
        this.x = x;
        this.y = y;
        this.hp = hp;
        this.lives = lives;
        //img = new ImageIcon(this.getClass().getResource(imgpath)).getImage();
    
        BufferedImage arrow = new BufferedImage(16, 16, BufferedImage.TYPE_INT_ARGB);
        Graphics2D g2d = arrow.createGraphics();
        g2d.setColor(Color.RED);
        g2d.drawLine(0, 0, 16, 8);
        g2d.drawLine(16, 8, 0, 16);
        g2d.drawLine(0, 16, 0, 0);
        g2d.dispose();
        img = arrow;
    
        max_speed = 6;
        speed = 0;
        direction = 0;
    }
    
    现在,这个渲染开始时很好

    当我开始移动播放器时,我遇到了一些问题,所以我稍微更新了画图代码

    @Override
    public void paintComponent(Graphics g) {
        super.paintComponent(g);
        Graphics2D g2d = (Graphics2D) g.create();
        AffineTransform trans = new AffineTransform();
        trans.setToIdentity();
        trans.translate(player.x, player.y);
        trans.rotate(Math.toRadians(player.getDirection()), player.getWidth() / 2, player.getHeight() / 2);
        g2d.setTransform(trans);
        g2d.drawImage(player.getImg(), 0, 0, (int) player.getWidth(), (int) player.getHeight(), null);
        g2d.dispose();
    
        g2d = (Graphics2D) g.create();
        g2d.drawString("X: " + player.getX() + " Y: " + player.getY(), 5, 10);
        g2d.dispose();
        trans.setToIdentity();
    }
    
    基本上,我复制了
    图形
    上下文

    Graphics2D g2d = (Graphics2D) g.create();
    
    使用
    仿射变换
    ,我将上下文转换为玩家的当前位置,这简化了旋转代码,因为我不需要偏移锚点

    trans.translate(player.x, player.y);
    trans.rotate(Math.toRadians(player.getDirection()), player.getWidth() / 2, player.getHeight() / 2);
    
    这也意味着更容易绘制图像

    g2d.drawImage(player.getImg(), 0, 0, (int) player.getWidth(), (int) player.getHeight(), null);
    
    这一切的美妙之处在于,所有更改都与
    图形
    上下文的副本相关,您不需要“撤消”所有更改…只是不要忘记在完成后处理副本

    我也不鼓励您使用
    keylister
    ,而是更喜欢使用

    我还将
    线程
    java.util.Timer
    替换为
    javax.swing.Timer

    public void gameLoop() {
        Timer timer = new Timer(16, new ActionListener() {
    
            @Override
            public void actionPerformed(ActionEvent e) {
                update();
                screen.repaint();
            }
        });
        timer.start();
    }
    

    另外,请注意,
    scheduleAtFixedRate
    的最后一个参数是调用之间的毫秒数,因此您当前的代码大约生成16fps。60fps大约是16毫秒…

    如果这是我的问题,我会去掉底部的咆哮,因为它会分散注意力,没有任何作用。如果您花时间更详细地描述您的代码,以便我们能够理解,那么这个问题会更好地解决。如果我能一目了然地理解你的代码,我现在可能已经给了你一个答案。另外,在Swing应用程序中使用java.util.Timer通常是不安全的。最好使用javax.swing.Timer.Sorry来解释这个问题。信息技术