Search code examples
javaswinggraphicstrigonometryradians

Player object moving one direction but turned a different direction


When the game is first started, the player is spawned, looking in direction 0 (right). Pressing the right key (vk_right) turns the player sprite left, but the direction is being set to send the player in the (what seems like) correct direction. The left and right keys change the character's direction variable, while the up/down keys accelerate/decelerate the character.

I'm not very good at trigonometry, so I probably have a few things wrong here and there (which is why I'm posting this). I can't seem to understand how to get the character to move in the same direction he is 'looking' (direction variable).

Here is the Player.java class:

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

}

Here is the main game class:

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

Solution

  • I made several improvements:

    1. When you do Cos and Sin, you must convert the degrees to Radians, as those functions take Radians (radians are a different unit for degrees).
    2. I changed the - and + of the right and left key. It's conventional that counter clockwise is increasing not the other way around ;)
    3. I modified the turn method as it had some slight mistakes (-180 is 0 in trig)

    Comment if there are more errors and I'll take another look :) Good luck!

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