|
|
import pygame
|
|
|
import math
|
|
|
|
|
|
class Vector2D:
|
|
|
def __init__(self, x: float = 0, y: float = 0):
|
|
|
self._vector = pygame.Vector2(x, y)
|
|
|
|
|
|
@property
|
|
|
def x(self) -> float:
|
|
|
return self._vector.x
|
|
|
|
|
|
@x.setter
|
|
|
def x(self, value: float):
|
|
|
self._vector.x = value
|
|
|
|
|
|
@property
|
|
|
def y(self) -> float:
|
|
|
return self._vector.y
|
|
|
|
|
|
@y.setter
|
|
|
def y(self, value: float):
|
|
|
self._vector.y = value
|
|
|
|
|
|
def __add__(self, other):
|
|
|
if isinstance(other, Vector2D):
|
|
|
return Vector2D(self.x + other.x, self.y + other.y)
|
|
|
else:
|
|
|
result = self._vector + other._vector
|
|
|
return Vector2D(result.x, result.y)
|
|
|
|
|
|
def __sub__(self, other):
|
|
|
if isinstance(other, Vector2D):
|
|
|
return Vector2D(self.x - other.x, self.y - other.y)
|
|
|
else:
|
|
|
result = self._vector - other._vector
|
|
|
return Vector2D(result.x, result.y)
|
|
|
|
|
|
def __mul__(self, scalar):
|
|
|
if isinstance(scalar, Vector2D):
|
|
|
return Vector2D(self.x * scalar.x, self.y * scalar.y)
|
|
|
else:
|
|
|
result = self._vector * scalar
|
|
|
return Vector2D(result.x, result.y)
|
|
|
|
|
|
def __truediv__(self, other):
|
|
|
if isinstance(other, Vector2D):
|
|
|
return Vector2D(self.x / other.x, self.y / other.y)
|
|
|
else:
|
|
|
result = self._vector / other
|
|
|
return Vector2D(result.x, result.y)
|
|
|
|
|
|
def length(self):
|
|
|
return self._vector.length()
|
|
|
|
|
|
def normalize(self):
|
|
|
result = self._vector.normalize()
|
|
|
return Vector2D(result.x, result.y)
|
|
|
|
|
|
def dot(self, other):
|
|
|
if isinstance(other, Vector2D):
|
|
|
return self._vector.dot(other._vector)
|
|
|
else:
|
|
|
return self._vector.dot(other)
|
|
|
|
|
|
class Transform2D:
|
|
|
IDENTITY = None
|
|
|
FLIP_X = None
|
|
|
FLIP_Y = None
|
|
|
|
|
|
def __init__(self, position: Vector2D = None, rotation: float = 0.0,
|
|
|
scale: Vector2D = None):
|
|
|
"""
|
|
|
åˆ<C3A5>始化å<E28093>˜æ<CB9C>¢çŸ©é˜µ
|
|
|
|
|
|
Args:
|
|
|
position: ä½<C3A4>ç½®å<C2AE>‘é‡<C3A9>
|
|
|
rotation: 旋转角度(弧度)
|
|
|
scale: 缩放å<C2BE>‘é‡<C3A9>
|
|
|
"""
|
|
|
if position is None:
|
|
|
position = Vector2D(0, 0)
|
|
|
if scale is None:
|
|
|
scale = Vector2D(1.0, 1.0)
|
|
|
|
|
|
self._set_transform(position, rotation, scale)
|
|
|
|
|
|
def _set_transform(self, position: Vector2D, rotation: float, scale: Vector2D):
|
|
|
"""
|
|
|
æ ¹æ<C2B9>®ä½<C3A4>ç½®ã€<C3A3>旋转和缩放设置å<C2AE>˜æ<CB9C>¢çŸ©é˜µ
|
|
|
"""
|
|
|
cos = math.cos(rotation)
|
|
|
sin = math.sin(rotation)
|
|
|
|
|
|
# 设置基å<C2BA>‘é‡<C3A9>(旋转和缩放的组å<E2809E>ˆï¼‰
|
|
|
self.x = Vector2D(cos * scale.x, sin * scale.x)
|
|
|
self.y = Vector2D(-sin * scale.y, cos * scale.y)
|
|
|
|
|
|
# 设置原点(平移)
|
|
|
self.origin = position
|
|
|
|
|
|
@property
|
|
|
def position(self) -> Vector2D:
|
|
|
"""获å<EFBFBD>–ä½<EFBFBD>ç½®"""
|
|
|
return self.origin
|
|
|
|
|
|
@position.setter
|
|
|
def position(self, value: Vector2D):
|
|
|
"""设置ä½<EFBFBD>ç½®"""
|
|
|
self.origin = value
|
|
|
|
|
|
@property
|
|
|
def scale(self) -> Vector2D:
|
|
|
"""获å<EFBFBD>–缩放"""
|
|
|
# 计算基å<C2BA>‘é‡<C3A9>的长度æ<C2A6>¥å¾—åˆ°ç¼©æ”¾å› å<C3A5>
|
|
|
scale_x = math.sqrt(self.x.x * self.x.x + self.x.y * self.x.y)
|
|
|
scale_y = math.sqrt(self.y.x * self.y.x + self.y.y * self.y.y)
|
|
|
return Vector2D(scale_x, scale_y)
|
|
|
|
|
|
@scale.setter
|
|
|
def scale(self, value: Vector2D):
|
|
|
"""设置缩放"""
|
|
|
current_scale = self.scale
|
|
|
if current_scale.x != 0 and current_scale.y != 0:
|
|
|
# 调整基å<C2BA>‘é‡<C3A9>以适应新的缩放
|
|
|
scale_ratio_x = value.x / current_scale.x
|
|
|
scale_ratio_y = value.y / current_scale.y
|
|
|
self.x = Vector2D(self.x.x * scale_ratio_x, self.x.y * scale_ratio_x)
|
|
|
self.y = Vector2D(self.y.x * scale_ratio_y, self.y.y * scale_ratio_y)
|
|
|
|
|
|
@property
|
|
|
def rotation(self) -> float:
|
|
|
"""获å<EFBFBD>–旋转角度"""
|
|
|
return math.atan2(self.x.y, self.x.x)
|
|
|
|
|
|
@rotation.setter
|
|
|
def rotation(self, value: float):
|
|
|
"""设置旋转角度"""
|
|
|
current_scale = self.scale
|
|
|
cos = math.cos(value)
|
|
|
sin = math.sin(value)
|
|
|
|
|
|
self.x = Vector2D(cos * current_scale.x, sin * current_scale.x)
|
|
|
self.y = Vector2D(-sin * current_scale.y, cos * current_scale.y)
|
|
|
|
|
|
def transform_point(self, point: Vector2D) -> Vector2D:
|
|
|
"""
|
|
|
应用å<C2A8>˜æ<CB9C>¢åˆ°ç‚¹
|
|
|
|
|
|
Args:
|
|
|
point: è¦<C3A8>å<EFBFBD>˜æ<CB9C>¢çš„点
|
|
|
|
|
|
Returns:
|
|
|
å<>˜æ<CB9C>¢å<C2A2>Žçš„点
|
|
|
"""
|
|
|
# 应用线性å<C2A7>˜æ<CB9C>¢ç„¶å<C2B6>ŽåŠ ä¸Šå¹³ç§»
|
|
|
x = self.x * point.x
|
|
|
y = self.y * point.y
|
|
|
return self.origin + x + y
|
|
|
|
|
|
def multiply(self, other: 'Transform2D') -> 'Transform2D':
|
|
|
"""
|
|
|
å°†å<E280A0>¦ä¸€ä¸ªå<C2AA>˜æ<CB9C>¢åº”用到当å‰<C3A5>å<EFBFBD>˜æ<CB9C>¢
|
|
|
|
|
|
Args:
|
|
|
other: è¦<C3A8>应用的å<E2809E>˜æ<CB9C>¢
|
|
|
|
|
|
Returns:
|
|
|
æ–°çš„å<E2809E>˜æ<CB9C>¢å¯¹è±¡
|
|
|
"""
|
|
|
# 组å<E2809E>ˆä¸¤ä¸ªå<C2AA>˜æ<CB9C>¢çŸ©é˜µ
|
|
|
new_x = Vector2D(
|
|
|
self.x.x * other.x.x + self.y.x * other.x.y,
|
|
|
self.x.y * other.x.x + self.y.y * other.x.y
|
|
|
)
|
|
|
new_y = Vector2D(
|
|
|
self.x.x * other.y.x + self.y.x * other.y.y,
|
|
|
self.x.y * other.y.x + self.y.y * other.y.y
|
|
|
)
|
|
|
new_origin = self.transform_point(other.origin)
|
|
|
|
|
|
result = Transform2D()
|
|
|
result.x = new_x
|
|
|
result.y = new_y
|
|
|
result.origin = new_origin
|
|
|
return result
|
|
|
|
|
|
def inverse(self) -> 'Transform2D':
|
|
|
"""
|
|
|
计算逆å<E280A0>˜æ<CB9C>¢
|
|
|
|
|
|
Returns:
|
|
|
逆å<E280A0>˜æ<CB9C>¢
|
|
|
"""
|
|
|
# 计算2x2矩阵的行列å¼<C3A5>
|
|
|
det = self.x.x * self.y.y - self.x.y * self.y.x
|
|
|
|
|
|
if abs(det) < 1e-10:
|
|
|
raise ValueError("Transform is not invertible")
|
|
|
|
|
|
inv_det = 1.0 / det
|
|
|
|
|
|
# 计算逆矩阵的基å<C2BA>‘é‡<C3A9>
|
|
|
inv_x = Vector2D(
|
|
|
self.y.y * inv_det,
|
|
|
-self.x.y * inv_det
|
|
|
)
|
|
|
inv_y = Vector2D(
|
|
|
-self.y.x * inv_det,
|
|
|
self.x.x * inv_det
|
|
|
)
|
|
|
|
|
|
# 计算逆矩阵的原点
|
|
|
origin_dot = self.origin.x * inv_x.x + self.origin.y * inv_x.y
|
|
|
origin_dot2 = self.origin.x * inv_y.x + self.origin.y * inv_y.y
|
|
|
inv_origin = Vector2D(-origin_dot, -origin_dot2)
|
|
|
|
|
|
result = Transform2D()
|
|
|
result.x = inv_x
|
|
|
result.y = inv_y
|
|
|
result.origin = inv_origin
|
|
|
return result
|
|
|
|
|
|
|
|
|
# åˆ<C3A5>始化预定义常é‡<C3A9>
|
|
|
Transform2D.IDENTITY = Transform2D()
|
|
|
Transform2D.FLIP_X = Transform2D(scale=Vector2D(-1, 1))
|
|
|
Transform2D.FLIP_Y = Transform2D(scale=Vector2D(1, -1))
|
|
|
|