Skip to main content

向量和矩形类的集合

项目描述

向量

用于游戏的合理、高性能的 2D 矢量对象

版权所有 2019-2020 拉里·黑斯廷斯

概述

vec是一个模块,目前包含一个类:Vector2,一个为游戏开发而设计的 2D 矢量对象。

特征:

  • Vector2对象是不可变的。
  • Vector2支持所有常用功能,包括运算符重载。
  • Vector2尽可能延迟计算对象的属性。
  • Vector2对象毫不费力地支持笛卡尔坐标和极坐标。

为什么另一个向量类?

我参加了三个 PyWeek 游戏挑战。在这 3 次中的 2 次中,我在周中编写了自己的矢量类,完全出于沮丧。

大多数 Python 矢量对象的最大问题是它们是可变的。坦率地说,这种方式是疯狂的。矢量对象应该是不可变的——从 API 的角度来看它才有意义。如果您将某个游戏引擎 pawn 的位置设置为特定的矢量对象,然后修改该矢量对象会怎样?pawn 是否应该自动更新它的位置——如果是这样,它应该如何知道值改变了?

类似地,一些向量类使用度数而不是弧度表示极坐标。再次以这种方式存在疯狂。Python 模块中的三角函数在 math弧度域中运行,并且必须跟踪某物在哪个域中——并来回转换——是一个不必要的概念复杂化。你有一个游戏要写!

(一些矢量类同时支持坐标的弧度度数。这简直是糟糕的 API 设计——它使 API 的表面积增加了一倍,增加了不必要的复杂性并增加了维护和测试开销。拥抱弧度,伙计们。)

与此相关的是,许多矢量类使极坐标成为二等公民。大多数向量类仅将向量存储在笛卡尔坐标中,因此程序员必须在向量对象外部执行所有极坐标操作,或者它们会产生开销和累积误差,即每次操作都转换为极坐标并再次返回。

vec.Vector2避免了所有这些问题。 vec.Vector2对象是不可变的,它们支持用极坐标或笛卡尔坐标定义的向量,并且它们严格使用弧度进行极坐标运算。

概念模型

vec.Vector2对象在概念上表示一个向量。它们可以使用笛卡尔坐标或极坐标定义,并且vec.Vector2 可以查询其笛卡尔坐标和极坐标。

游戏中的大多数矢量对象都是使用笛卡尔坐标定义的。 vec.Vector2使这很容易,支持任意数量的调用来创建一个。x支持和y属性的离散参数、可迭代对象和对象都可以正常工作:

vec.Vector2(0, 1)
vec.Vector2(x=0, y=1)
vec.Vector2((0, 1))
vec.Vector2([0, 1])
vec.Vector2(types.SimpleNamespace(x=0, y=1))

所有这些都定义了相同的向量。最后一个示例是为了演示vec.Vector2可以基于任何具有xy 属性的对象创建向量。

一旦你有了一个矢量对象,你就可以检查它的属性。每个vec.Vector2对象都可以查询笛卡尔坐标和极坐标:

v = vec.Vector2(0, 1)
print(v.theta, v.r)

打印1.5707963267948966 1.0。第一个数字是 π/2(大约)。

相反,您也可以vec.Vector2使用极坐标定义对象,然后询问其笛卡尔坐标:

v2 = vec.Vector2(r=1, theta=1.5707963267948966)
print(v2.x, v2.y)

这打印6.123233995736766e-17 1.0。从概念上讲,这应该打印0.0, 1.0出来——但math.pi只是一个近似值,这意味着我们的结果与一个无穷小的数量相差甚远。

实施细节

内部vec.Vector2对象是“笛卡尔”或“极坐标”。“笛卡尔”矢量对象根据x和定义yr“极”矢量对象是根据和定义的theta。所有其他属性都根据需要延迟计算。

vec.Vector2对象使用槽,并依赖于__getattr__ 实现这种惰性计算。在创建向量时仅设置向量的已知值。如果用户引用了一个尚未计算的属性,Python 将调用vec.Vector2.__getattr__(),它计算然后设置该值。未来对该属性的引用会跳过此机制并简单地返回缓存值,这仅与常规对象上的属性查找一样昂贵。

对象上的操作vec.Vector2使用最便宜的方法计算其结果。如果您有一个vec.Vector2使用极坐标定义的对象,并且您在其上调用.rotate()or .scale() ,则所有数学运算都在极坐标域中完成。另一方面,添加向量总是在笛卡尔域中完成,所以如果你将一个极向量添加到任何其他向量,它的笛卡尔坐标将被计算——并且结果向量将始终使用笛卡尔坐标定义。

实际上,最后的陈述并不总是正确的。添加两个完全相同的极向量有一个特殊情况theta:只需添加它们的r值。这种方法比转换为笛卡尔坐标便宜得多,而且更精确,返回使用极坐标定义的向量! vec.Vector2利用许多这样的偶然性,尽可能便宜和准确地计算你的向量。

API

vec.Vector2(x=None, y=None, *, r=None, theta=None, r_squared=None)

构造一个vec.Vector2对象。您可以根据需要传入任意数量的这些参数;但是,您必须同时传入and 或同时传入and 。任何在构造时未传入的属性都将在评估时延迟计算。xy rtheta

(vec.Vector2仅对其参数进行一些验证。它确保randtheta被规范化。但是,它不会检查(x, y)(r, theta)描述相同的向量。如果您传入xand y,并且 a thetaandr不匹配,您将返回你要的vec.Vector2那个。祝你好运。)

vec.Vector2对象支持五个属性: xyrthetar_squared。对象是用笛卡尔坐标还是极坐标定义的都没有关系。这些都有效。 r_squared相当于,r*r但基于笛卡尔坐标计算要便宜得多。

vec.Vector2对象支持迭代器协议。 您可以调用 len()对象vec.Vector2——它总是返回 2。您也可以遍历它们,这将按该顺序产生xandy属性。

vec.Vector2对象支持序列协议。 您可以对它们下标,其行为就好像vec.Vector2对象是一个长度为 2 的包含xandy属性的元组。

vec.Vector2对象也支持布尔协议;您可以将它们与布尔运算符一起使用,并且可以调用bool()它们。在布尔上下文中使用时,零向量的计算结果为False,所有其他向量的计算结果为True

vec.Vector2对象是可散列的。

vec.Vector2对象支持以下运算符:

  • v1 + v2将两个向量相加。
  • v1 - v2从左向量中减去右向量。
  • v1 * scalar将向量乘以一个标量,相当于v1.scale(scalar).
  • v1 / scalar将向量除以一个标量。
  • +v1与 完全相同v1
  • -v1返回 的相反值v1,因此它v1 + (-v1)应该是零向量。(由于复杂的浮点错误,情况可能并非总是如此。)
  • v1 == v2True如果两个向量完全相同False否则。
  • v1 != v2False如果两个向量完全相同True否则。

vec.Vector2对象支持以下方法:

vec.Vector2.scaled(scalar)

返回一个新vec.Vector2对象,相当于原始向量乘以该标量。

vec.Vector2.scaled_to_length(r)

返回一个新vec.Vector2对象,相当于长度设置为 的原始向量r

vec.Vector2.normalized()

返回一个新vec.Vector2对象,相当于缩放到长度为 1 的原始向量。

vec.Vector2.rotated(theta)

返回一个新vec.Vector2对象,等于原始向量旋转theta弧度。

vec.Vector2.dot(other)

返回“点积” selfother。这个结果是一个标量值,而不是一个向量。

vec.Vector2.cross(other)

返回“叉积” selfother。这个结果是一个标量值,而不是一个向量。

注意:从技术上讲,没有为二维向量定义“叉积”。实际上,这会返回两个向量的“垂直点积”或“perp 点积”,因为这是人们在要求两个 2D 向量的“叉积”时真正想要的。

vec.Vector2.polar()

返回 的 2 元组(self.r, self.theta)

vec.Vector2.lerp(other, ratio)

根据标量比,返回表示self和之间的线性插值的向量。 应该是(并包括)和之间的值。如果是,则返回。如果是,则返回。如果是,则返回。otherratioratio01ratio0selfratio1otherratio0.4(self * 0.6) + (other * 0.4)

vec.vector2_zero

不可变的、永恒的“零”vec.Vector2向量对象。 vec保证每个零向量都是对该对象的引用:

>>> v = vec.Vector2(0, 0)
>>> v is vec.vector2_zero
True

从数学上讲,以极坐标表示的零向量没有定义的角度。因此vec将其零向量定义为角度为None

项目详情


下载文件

下载适用于您平台的文件。如果您不确定要选择哪个,请了解有关安装包的更多信息。

源分布

vec-0.5.tar.gz (10.6 kB 查看哈希

已上传 source

内置分布

vec-0.5-py3-none-any.whl (10.4 kB 查看哈希

已上传 py3