from math import atan2, hypot, pi class Vec: """Support : `Vec2i | Vec2f | Vec3i | Vec3f`""" def __init__(self, x: int | float | None = None, y: int | float | None = None, z: int | float | None = None) -> None: if x != None: self.new(x, y, z) else: self.x = 0 self.y = 0 self.z = 0 def new(self, x: int | float, y: int | float | None, z: int | float | None) -> None: """Change values of Vector""" if y == None: raise TypeError # Determine type of class self.type = int if type(x) == float: self.type = float # Verify other type if type(y) != self.type: raise TypeError self.x = self.type(x) self.y = self.type(y) if z == None: self.z = None else: self.z = self.type(z) def __str__(self): max_precision = 3 x = round(self.x, max_precision) y = round(self.y, max_precision) z = None if self.z == None else round(self.z, max_precision) return f"{self.__class__.__name__}({x}, {y}{'' if z == None else f', {z}'})" def plus(self, other: 'Vec') -> 'Vec': """Add 2 vectors""" x = self.x + other.x y = self.y + other.y if self.z == None or other.z == None: return Vec(x, y) return Vec(x, y, self.z + other.z) def minus(self, other: 'Vec') -> 'Vec': """Subtracts 2 vectors""" x = self.x - other.x y = self.y - other.y if self.z == None or other.z == None: return Vec(x, y) return Vec(x, y, self.z - other.z) def times(self, factor: float) -> 'Vec': """Multiplies 2 vectors""" x = self.x * factor y = self.y * factor if self.z == None: return Vec(x, y) return Vec(x, y, self.z * factor) def div(self, factor: float) -> 'Vec': """Divides 2 vectors""" x = self.x / factor y = self.y / factor if self.z == None: return Vec(x, y) return Vec(x, y, self.z / factor) def to_angle(self): """Transforms a Vec3 into a Vec2 angle""" if self.z == None: raise TypeError deg_to_rad = (180. / pi) return Vec( atan2(-self.z, hypot(self.x, self.y)) * deg_to_rad, atan2(self.y, self.x) * deg_to_rad ) def is_zero(self): """Check if the vector is zero""" xy = (float(self.x) == 0.) and (float(self.y) == 0.) if self.z == None: return xy return xy and float(self.z) == 0. def angle_normalizer(angle: Vec) -> Vec: """Force the angle to respect game limitation""" # Limit of pitch in game is ]-89; 180[ if angle.x > 89.: angle.x = 89. if angle.x < -89.: angle.x = -89 # Limit of yaw in game is ]-180; 360[ while (angle.y > 180.): angle.y -= 360. while (angle.y < -180.): angle.y += 360. return angle class Color3i: """Color RGB as integer""" def __init__(self, r: int, g: int, b: int) -> None: self.r = r self.g = g self.b = b def __str__(self): return f"{self.__class__.__name__}({self.r}, {self.g}, {self.b})" class Color4f: """Color RGBA as float""" def __init__(self, r: float, g: float, b: float, a: float) -> None: self.r = r self.g = g self.b = b self.a = a def __str__(self): max_precision = 3 r = round(self.r, max_precision) g = round(self.g, max_precision) b = round(self.b, max_precision) a = round(self.a, max_precision) return f"{self.__class__.__name__}({r}, {g}, {b}, {a})"