Hey purplechalk,
I had some time to look into this. Funny thing, I thought this was in the API too. Here's what I came up with:
private static Position[] getSweepCorners(Position from, Entity o) {
int offsetX = o.getSizeX() - 1;
int offsetY = o.getSizeY() - 1;
Position objPos = o.getPosition();
if (offsetX == 0 && offsetY == 0) {
return new Position[] {
objPos, objPos
};
}
int relativeX = from.getX() - o.getX();
int relativeY = from.getY() - o.getY();
boolean isOutOfBoundsX = relativeX < 0 || relativeX > offsetX - 1;
boolean isOutOfBoundsY = relativeY < 0 || relativeY > offsetY - 1;
int signX = Integer.signum(relativeX);
int signY = Integer.signum(relativeY);
if (isOutOfBoundsX && isOutOfBoundsY) {
boolean sameSign = signX == signY;
return new Position[] {
objPos.translate(sameSign ? offsetX : 0, 0),
objPos.translate(sameSign ? 0 : offsetX, offsetY)
};
}
if (isOutOfBoundsX) {
int staticX = signX < 0 ? 0 : offsetX;
return new Position[] {
objPos.translate(staticX, 0),
objPos.translate(staticX, offsetY)
};
}
int staticY = signY < 0 ? 0 : offsetY;
return new Position[] {
objPos.translate(0, staticY),
objPos.translate(offsetX, staticY)
};
}
private static double getAngleToPosition(Position from, Position to) {
double distX = from.getX() - to.getX();
double distY = from.getY() - to.getY();
// -pi, pi
double angleRadians = Math.atan2(distX, distY);
// 0, 2pi
final double TWO_PI = 2 * Math.PI;
angleRadians = (angleRadians + TWO_PI) % TWO_PI;
// 0, 2048
final int HALF_ROTATION_GAME_ANGLE = 1024;
final double RADIANS_TO_GAME_ANGLE = HALF_ROTATION_GAME_ANGLE / Math.PI;
return angleRadians * RADIANS_TO_GAME_ANGLE;
}
public boolean isFacingObject(Entity o) {
Position ourPosition = myPosition();
Position[] sweepCorners = getSweepCorners(ourPosition, o);
double sweepAngle1 = getAngleToPosition(ourPosition, sweepCorners[0]);
double sweepAngle2 = getAngleToPosition(ourPosition, sweepCorners[1]);
final int FULL_ROTATION = 2048;
long minTemp = (Math.round(Math.min(sweepAngle1, sweepAngle2)) - 1) % FULL_ROTATION;
long maxTemp = (Math.round(Math.max(sweepAngle1, sweepAngle2)) + 1) % FULL_ROTATION;
long minAngle = Math.min(minTemp, maxTemp);
long maxAngle = Math.max(minTemp, maxTemp);
int ourAngle = myPlayer().getRotation();
if (maxAngle - minAngle <= FULL_ROTATION / 2) {
return ourAngle >= minAngle && ourAngle <= maxAngle;
}
return (ourAngle >= 0 && ourAngle <= minAngle) ||
(ourAngle >= maxAngle && ourAngle <= FULL_ROTATION);
}
You would then use "isFacingObject(Entity)" which returns true if your character is rotated towards the given Entity object. It should also work for Entity objects that span more than one tile, e.g., trees.
The code is chunky, but the calculations are not complex. I'm sure someone else can trim this down a bit (or contribute a cleaner alternative!). I don't think comments would help visualize the calculations, so if you'd like, I could make some sketches to show how it works.
Best,
randomjoe