From 86b1109ba859d0a5fc9f86c00d0e7cf39e699d34 Mon Sep 17 00:00:00 2001 From: Max Nusspickel Date: Sat, 25 Apr 2026 09:31:44 +0100 Subject: [PATCH 1/2] Fixes Unit.is_facing --- sc2/unit.py | 30 ++++++++++++++++++++---------- 1 file changed, 20 insertions(+), 10 deletions(-) diff --git a/sc2/unit.py b/sc2/unit.py index 73c519b0..1f76c203 100644 --- a/sc2/unit.py +++ b/sc2/unit.py @@ -833,20 +833,30 @@ def facing(self) -> float: """Returns direction the unit is facing as a float in range [0,2π). 0 is in direction of x axis.""" return self._proto.facing - def is_facing(self, other_unit: Unit, angle_error: float = 0.05) -> bool: - """Check if this unit is facing the target unit. If you make angle_error too small, there might be rounding errors. If you make angle_error too big, this function might return false positives. + def facing_difference(self, target: Point2 | Unit) -> float: + """The angle difference (in radians) between the facing direction and the target point or unit. + + The returned angle is positive if the unit is facing left of the target, and negative otherwise. + """ + target_point = target.position if isinstance(target, Unit) else target + dx = target_point.x - self.position.x + dy = target_point.y - self.position.y + angle = math.atan2(dy, dx) + # Plain subtraction (angle - facing) can land outside [-π, π), so we add π, normalize, and remove π again + difference = (angle - self.facing + math.pi) % (2 * math.pi) - math.pi + + return difference + + def is_facing(self, other_unit: Point2 | Unit, angle_error: float = 0.05) -> bool: + """Check if this unit is facing the target point or unit within a tolerance (in units of radians). + + If you make angle_error too small, there might be rounding errors. + If you make angle_error too big, this function might return false positives. :param other_unit: :param angle_error: """ - # TODO perhaps return default True for units that cannot 'face' another unit? e.g. structures (planetary fortress, bunker, missile turret, photon cannon, spine, spore) or sieged tanks - angle = math.atan2( - other_unit.position_tuple[1] - self.position_tuple[1], other_unit.position_tuple[0] - self.position_tuple[0] - ) - if angle < 0: - angle += math.pi * 2 - angle_difference = math.fabs(angle - self.facing) - return angle_difference < angle_error + return abs(self.facing_difference(other_unit)) < angle_error @property def footprint_radius(self) -> float | None: From 1674603383c3515faaf658fa58007827c20b841f Mon Sep 17 00:00:00 2001 From: Max Nusspickel Date: Sat, 25 Apr 2026 09:42:18 +0100 Subject: [PATCH 2/2] Renames facing_difference to relative_facing --- sc2/unit.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sc2/unit.py b/sc2/unit.py index 1f76c203..f1bd9824 100644 --- a/sc2/unit.py +++ b/sc2/unit.py @@ -833,7 +833,7 @@ def facing(self) -> float: """Returns direction the unit is facing as a float in range [0,2π). 0 is in direction of x axis.""" return self._proto.facing - def facing_difference(self, target: Point2 | Unit) -> float: + def relative_facing(self, target: Point2 | Unit) -> float: """The angle difference (in radians) between the facing direction and the target point or unit. The returned angle is positive if the unit is facing left of the target, and negative otherwise. @@ -856,7 +856,7 @@ def is_facing(self, other_unit: Point2 | Unit, angle_error: float = 0.05) -> boo :param other_unit: :param angle_error: """ - return abs(self.facing_difference(other_unit)) < angle_error + return abs(self.relative_facing(other_unit)) < angle_error @property def footprint_radius(self) -> float | None: