玩家对象移动一个方向但转向不同的方向

时间:2014-07-04 01:23:53

标签: java swing graphics trigonometry radians

首次开始游戏时,会生成玩家,向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;
    }

}

这是主要的游戏类:

package rpg2d;

import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.geom.AffineTransform;
import java.util.Timer;
import java.util.TimerTask;

import javax.swing.JFrame;
import javax.swing.JPanel;

public class Main {

    boolean gameRunning = true;
    Graphics2D g;
    JFrame frame;
    JPanel screen;
    Player player;

    public static void main(String[] args) {
        new Main();
    }

    @SuppressWarnings("serial")
    public Main() {
        frame = new JFrame("2D RPG Test");
        frame.setSize(800,600);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        player = new Player(10,10,100,3,"/img/player.png");
        screen = new JPanel() {
            @Override
            public void paintComponent(Graphics g) {
                super.paintComponent(g);
                Graphics2D g2d = (Graphics2D)g;
                AffineTransform trans = new AffineTransform();
                AffineTransform old = new AffineTransform();
                trans.setToIdentity();
                trans.rotate(Math.toRadians(player.getDirection()),player.getWidth()/2,player.getHeight()/2);
                g2d.setTransform(trans);
                g2d.drawImage(player.getImg(), player.getX(), player.getY(), (int)player.getWidth(), (int)player.getHeight(), null);
                g2d.setTransform(old);
                g2d.drawString("X: " + player.getX() + " Y: " + player.getY(), 5,10);
                trans.setToIdentity();
            }
        };

        frame.add(screen);
        frame.setVisible(true);
        screen.addKeyListener(player);
        screen.requestFocus();
        Thread t = new Thread(new Runnable() {
            public void run() {
                gameLoop();
            }
        });
        t.setDaemon(false);
        t.start();
    }

    public void update() {
        player.move();
    }

    public void gameLoop() {
        final int FPS = 60;
        Timer timer = new Timer();
        timer.scheduleAtFixedRate(new TimerTask() {
            public void run() {
                update();
                screen.repaint();
            }
        }, 0, FPS);
    }
}

2 个答案:

答案 0 :(得分:3)

我做了几处改进:

  1. 当你做Cos和Sin时,你必须将度数转换为Radians,因为这些函数需要Radians(弧度是度数的不同单位)。
  2. 我更改了左右键的 - 和+。传统上逆时针方向增加而不是相反;)
  3. 我修改了转弯方法,因为它有一些轻微的错误(-180在触发时为0)
  4. 评论是否有更多错误,我会再看看:) 祝你好运!

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

答案 1 :(得分:2)

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

基本上,我制作了Graphics上下文的副本......

Graphics2D g2d = (Graphics2D) g.create();

使用AffineTransform,我将上下文翻译为玩家的当前位置,这简化了旋转代码,因为我没有需要偏移锚点......

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

所有这一切的美妙之处在于,所有更改都与Graphics上下文的副本相关联,您不需要“撤消”它们......只是不要忘记{完成后复制的{1}}。

我也不鼓励您使用dispose并改为使用Key bindings API

我还用[{1}}替换了您的KeyListenerThread而不是......

java.util.Timer

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