Search code examples
javaswingmouseeventtrigonometry

Java Swing - Calculating what angle the mouse position is to the center of the screen


I'm making a 2D topdown view shooter game with Java Swing. I want to calculate what angle the mouse pointer is compared to the center of the screen so some of my Sprites can look toward the pointer and so that I can create projectiles described by an angle and a speed. Additionally If the pointer is straight above the middle of the screen, I want my angle to be 0°, if straight to its right, 90°, if straight below 180°, and straight left 270°.

I have made a function to calculate this:

public static float calculateMouseToPlayerAngle(float x, float y){
        float mouseX = (float) MouseInfo.getPointerInfo().getLocation().getX();
        float mouseY = (float)MouseInfo.getPointerInfo().getLocation().getY();
        float hypotenuse = (float) Point2D.distance(mouseX, mouseY, x, y);
        return (float)(Math.acos(Math.abs(mouseY-y)/hypotenuse)*(180/Math.PI));
    }

The idea behind it is that I calculate the length of the hypotenuse then the length of the side opposite of the angle in question. The fraction of the 2 should be a cos of my angle, so taking that result's arc cos then multiplying that by 180/Pi should give me the angle in degrees. This does work for above and to the right, but straight below returns 0 and straight left returns 90. That means that I currently have 2 problems where the domain of my output is only [0,90] instead of [0,360) and that it's mirrored through the y (height) axis. Where did I screw up?


Solution

  • You can do it like this.

    • For a window size of 500x500, top left being at point 0,0 and bottom right being at 500,500.
    • The tangent is the change in Y over the change in X of two points. Also known as the slope it is the ratio of the sin to cos of a specific angle. To find that angle, the arctan (Math.atan or Math.atan2) can be used. The second method takes two arguments and is used below.
    BiFunction<Point2D, Point2D, Double> angle = (c,
            m) -> (Math.toDegrees(Math.atan2(c.getY() - m.getY(),
                    c.getX() - m.getX())) + 270)%360;
            
    BiFunction<Point2D, Point2D, Double> distance = (c,
                    m) -> Math.hypot(c.getY() - m.getY(),
                            c.getX() - m.getX());
                    
    int screenWidth = 500;
    int screenHeight = 500;
    int ctrY = screenHeight/2;
    int ctrX = screenWidth/2;
    
    Point2D center = new Point2D.Double(ctrX,ctrY );
    
    Point2D mouse = new Point2D.Double(ctrX, ctrY-100);
    double straightAbove = angle.apply(center, mouse);
    System.out.println("StraightAbove: " + straightAbove);
    
    mouse = new Point2D.Double(ctrX+100, ctrY);
    double straightRight = angle.apply(center, mouse);
    System.out.println("StraightRight: " + straightRight);
    
    mouse = new Point2D.Double(ctrX, ctrY+100);
    double straightBelow = angle.apply(center, mouse);
    System.out.println("StraightBelow: " + straightBelow);
    
    mouse = new Point2D.Double(ctrX-100, ctrY);
    double straightLeft = angle.apply(center, mouse);
    System.out.println("Straightleft: " + straightLeft);
          
    

    prints

    StraightAbove: 0.0
    StraightRight: 90.0
    StraightBelow: 180.0
    Straightleft: 270.0
    

    I converted the radian output from Math.atan2 to degrees. For your application it may be more convenient to leave them in radians.

    Here is a similar Function to find the distance using Math.hypot

    BiFunction<Point2D, Point2D, Double> distance = (c,m) ->
                 Math.hypot(c.getY() - m.getY(),
                            c.getX() - m.getX());