1
\$\begingroup\$

In my top down shooter game, the player can face in any of the 8 compass directions using the keyboard.

Depending on the direction, the player will have a 90 degree field of view to turn based on the angle selected by the mouse position. Obviously the mouse can go anywhere so it has to be restricted within -45 and 45 of the angle faced.

The eight direction angles:

    135 90 45
180            0
   225 270 305

So if the player is facing to the left at 180, their range of view will be -45 and 45 of that ie 135 to 225. So it's simply mouseAngle - facingAngle, which works fine, except if the player is facing around 0, 45 or 305 degrees where the mouse angle passes zero causing issues in calculation.

As it is I'm using this formula.

private void setAngleFOV() {
    if (facing == 0 || facing == 360)
        facing = mouseAngle < 360 && mouseAngle >= 180 ? 360 : 0;
    angleFOV = mouseAngle - facing;
    angleFOV = Math.max(Math.min(angleFOV, 45), -45);
}

It can either be 0 or 360 for either facing or mouseAngle, whichever works best but I haven't found an ideal solution. The above formula works for facing right at angle 0, but not with diagonal angles 45 and 305.

It could maybe work with lots of if statements and such, but I feel there must be a better way?

\$\endgroup\$

1 Answer 1

2
\$\begingroup\$

Looks like you need to compare angles and work out their difference.

Here's one way to do it:

// Returns the difference between two angles, from -180 to +180 degrees.
float deltaAngle(float aDegrees, float bDegrees) {
    float difference = aDegrees - bDegrees + 180.0f;
    return (float)(difference - Math.floor(difference/360.0f) * 360.0f - 180.0f);
}

// Clamps the angle difference between -rangeDegrees and +rangeDegrees.
float clampRelativeAngle(float angleDegrees, float centreDegrees, float rangeDegrees) {
    float difference = deltaAngle(angleDegrees, centreDegrees);
    return (float)Math.min(Math.max(difference, -rangeDegrees), rangeDegrees);
}

// Clamps one angle within a range of a centre angle, and returns the result from 0 to 360 degrees.
float clampAbsoluteAngle(float angleDegrees, float centreDegrees, float rangeDegrees) {
    float absolute = centreDegrees + clampRelativeAngle(angleDegrees, centreDegrees, rangeDegrees);
    return (float)(absolute - Math.floor(absolute/360.0f) * 360.0f);
}
\$\endgroup\$
7
  • \$\begingroup\$ When I use clampAbsoluteAngle(angle, 180, 45) with angle less than 135, I get the value 135 back. When I use an angle between 135 and 225, I get angle back unchanged. And when I use an angle greater than 225, I get 225 as output. Is that not what you want? \$\endgroup\$
    – DMGregory
    Jun 27, 2020 at 15:14
  • \$\begingroup\$ Ahh ok then yes it is working. I'm actually expecting a value of -45 to 45 for angleFOV but that wasn't made clear in my question. The value facing can't be changed, I just add angleFOV to it where it is needed. \$\endgroup\$
    – Hasen
    Jun 27, 2020 at 15:16
  • \$\begingroup\$ I've edited the answer to give you one method that returns a relative angle from -range to +range, separate from the method that gives you the resulting absolute angle from 0 to 360. \$\endgroup\$
    – DMGregory
    Jun 27, 2020 at 15:18
  • \$\begingroup\$ Yes that's beautiful, thanks a lot. \$\endgroup\$
    – Hasen
    Jun 27, 2020 at 15:21
  • \$\begingroup\$ I'd edit your answer but I'm too low reputation so it would be simpler for you to just edit it yourself. you just need (float) casts on the returns for deltaAngle and clampAbsoluteAngle. \$\endgroup\$
    – Hasen
    Jun 27, 2020 at 15:23

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .