0

游戏刚开始时,玩家会生成,朝 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);
    }
}
4

2 回答 2

3

我做了几个改进:

  1. 当您执行 Cos 和 Sin 时,您必须将度数转换为弧度,因为这些函数采用弧度(弧度是度数的不同单位)。
  2. 我改变了左右键的-和+。按照惯例,逆时针方向增加而不是相反;)
  3. 我修改了转弯方法,因为它有一些小错误(-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;
    }
于 2014-07-04T02:41:43.553 回答
2

再加上迪恩的努力……

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

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相关,您不需要全部“撤消”它......完成后不要忘记dispose副本。

我也劝阻您不要使用KeyListener和支持Key bindings API

我还用一个代替了你的Threadand ......java.util.Timerjavax.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 毫秒...

于 2014-07-04T04:42:55.610 回答