向量

在创造一款复杂的游戏时,你可能需要处理向量。它们被用在物理学、AI、三角函数和许多其他情况中,但什么是向量呢?简单地说,向量是一个有方向的量。让我们从一个一维向量开始,它和一个数字是一样的,画一条从0开始,到5结束的有箭头的线。这是向量a,它等于5。如果,我们再画一个箭头,从5开始,到8结束,我们得到向量b,等于3

1D Vector Example你应该意识到,一个向量从哪里开始并不重要,重要的是它有多长,朝什么方向走。所以向量b从5开始,长3个单位,指向右边,这和从0开始到3的向量是一样的。现在,你也可以把这些向量相加,通过把a和b两个向量首尾相连得到向量c等于8。那么负数呢?好吧,如果在上面的图像中,一个指向“右”的向量对应一个正数,你可以看到一个指向“左”的向量对应一个负数,使得一个一维向量仅仅是一个带符号(+/-)的数。这解释了向量的基本概念:只计算长度方向(在本例中为“左”或“右”),而不计算位置。

那么,二维向量呢?嗯,我们可以认为它们不仅包括“左”和“右”,还包括“上”和“下”:

Various 2D Vectors现在,它们实际上还不是向量,因为我们仍然需要使用它们的开始和结束坐标来减去它们。 查看向量“a”,我们可以看到它的起始坐标为 [2,2],结束坐标为 [4,3],所以为了得到这个向量,我们需要通过从起始坐标减去结束坐标来减少它,就像这样:

a = [(x2-x1), (y2-y1)] = [(4-2), (3-2)] = [2,1]

现在让我们对向量 b 做同样的事情:

b = [(-1.2 -(-3.2)) ,(2.1 - 1.1)] = [2 ,1]

注意些什么吗?这两个向量是一样的!这是向量没有位置,只有方向和长度的另一个证明,我们可以围绕局部[0,0]轴画出这些向量之间的相对关系:

2D Vectors aroun [0, 0]这意味着2D向量由两个值定义,相对于局部[0,0]轴的“x”和“y”位置。那么三维向量呢?嗯,它们有一个额外的“深度”维度,可以用“x”、“y”和“z”位置围绕局部轴进行计算,就像这样:

3D VectorsGameMaker中使用向量的一个很好的例子是room编辑器中的物理 gravity 属性。重力被计算为一个围绕[0,0]位置的向量。所以,如果你定义重力为[x0, y10],重力将是向下,力为10。

通常,向量可以在很多情况下使用,但有时你想约束它们的值(比如处理角度时),这就是为什么我们归一化它们。这本质上是一种数学技巧,用于将长度为n的向量转换为长度为1的向量,这意味着向量分量将归一化在0到1之间。这些向量也被称为单位向量:

Unit Vector example要计算一个归一化的向量,我们必须首先有原始的向量分量,然后用它们来得到向量的长度。然后,我们将每个向量分量除以这个长度,得到归一化的向量分量,它们形成了归一化的向量,其中所有坐标的平方和的之和等于1。方法如下:

首先,我们取向量的坐标并得到分量:

vx = (x2 - x1); // = (7 - 1) = 6
vy = (y2 - y1); // = (4 - 1) = 3

然后我们使用这些值来计算向量的长度:

len = sqrt(sqr(vx) + sqr(vy)); // = sqrt(36 + 9) = sqrt(45) = 6.708203932499369

现在,我们得到了向量“a”的确切长度,所以让我们用它来归一化两个向量分量vxvy:

vx = (vx/len); // = (6 / 6.708203932499369) = 0.8944271909999159
vy = (vy/len); // = (3 / 6.708203932499369) = 0.4472135954999579

太棒了!我们现在已经归一化了向量的分量!但这在GameMaker上下文中有什么实际用途呢?好吧,让我给你一个实际的例子…

假设你在一款游戏中,玩家必须向敌人射击,你需要知道子弹物体在每一步中需要沿x轴和y轴移动多少距离才能击中它:

Vector Game Example为此,你可以使用玩家和敌人坐标来获得向量组件和长度,然后将其归一化,得到0到1之间的值,最后乘以你希望子弹在每一步中移动的速度。最后这两个值将存储并添加到每一步的起始x和y坐标上。听起来很复杂?它不是,看(为了简单起见,值被四舍五入到小数点后一位):

px = 100;
py = 425;
ex = 356;
ey = 83;
bullet_speed = 5;

vx = (ex - px); // = 256
vy = (ey - py); // = -342

len = sqrt(sqr(vx) + sqr(vy)); // = sqrt(65536 + 116964) = 427.2

vx = vx / len; // = 0.6
vy = vy / len; // = 0.8

speed_x = vx * bullet_speed; // = 3
speed_y = vy * bullet_speed; // = 4

所以,为了击中目标,每一步我们需要在子弹的x坐标上增加3,在y坐标上增加4。