pygame-ce
pygame-ce copied to clipboard
Add `Vector2.angle` and `Vector2.angle_rad` properties
Proposal:
Add properties angle and angle_rad to pygame.Vector2 with getter and possibly a setter.
vec.angle_rad == math.atan2(vec.y, vec.x) == vec.as_polar()[1] # note: no vec.angle_rad_to() method
vec.angle == -vec.angle_to([1, 0]) == degrees(vec.angle_rad)
(These angles are normalized: degrees within interval (-180, 180], even if set to an angle outside this range.) The zero vector has an angle of 0.
Reasons:
In math, the angle of a vector is often relative to the positive x-axis (increasing angle from 0 goes towards positive y-axis).
For example, polar coordinates and trigonometry functions are connected to vectors through their angle to positive x-axis.
vec == Vector2(r * cos(theta), r * sin(theta))
The current ways to get these angles are indirect and less readable, for such an (IMO) important aspect of vectors. See above. In as_polar() result, the length is available via vec.length, but the angle is not directly available.
In a codebase, it's convenient to only have to store one float (angle to +x axis) to mark the direction of something, rather than another vector (especially when the distance between two points is unnecessary/inapplicable). Many physics libraries or engines use angles like this heavily, usually using radians. Even if angles are technically only relative, to store them conveniently there has to be 'absolute' angles.
Example uses:
Calculate the angle of one position to another position, in degrees.
# Before
self.angle = (vec2 - vec1).angle_to([1, 0])
# After
self.angle = (vec2 - vec1).angle
Find the angle between two vectors, in radians.
# Before
self.angle_rad = math.radians(vec1.angle_to(vec2))
self.angle_rad = vec2.as_polar()[1] - vec1.as_polar()[1]
# After
self.angle_rad = vec2.angle_rad - vec1.angle_rad
Rotate a vector in-place at the direction of a given angle (from +x axis), in degrees.
# Before
vec.rotate_ip(angle - vec.angle_to([1, 0]))
# After
vec.angle = angle