游戏开发中的三角形数学学习

4

我正在尝试制作一个等腰三角形,让它在屏幕上移动,并在用户按下方向键(如右或左)时稍微旋转。

我希望三角形的顶点永远领先于其他部分。就像那个古老的“陨石游戏”一样。

我的问题在于数学计算。在每个X时间间隔内,我希望三角形朝“某个方向”移动,我需要帮助找到这个方向(x和y增量/减量)。

我可以找到三角形的中心点(重心),并且我有最顶端的x和y点,因此我有一个线向量可供使用,但不知道如何使用它。

我认为这与旧的正弦和余弦方法以及三角形旋转的数量(角度)有关,但我对这些东西有点生疏。

非常感谢任何帮助。


不是的,这是为了我自己的项目,出于个人兴趣。为什么?听起来像作业吗? - Mark
1
有关系吗?他在寻求帮助,而不是代码。=) - Erik Forbes
9个回答

5

vy/vx的反正切(反正切)是您的(重心->尖端)向量的分量,给出向量面对的角度。

标准反正切会给你一个角度,归一化为-90°< r < +90°度,因此根据结果和vx的符号添加或减去90度。

幸运的是,您的标准库应该提供一个atan2()函数,将vx和vy分别作为参数,返回0°到360°或-180°到+180°之间的角度。它也将处理vx = 0的特殊情况,否则如果您不小心会导致除以零。

请参见http://www.arctangent.net/atan.html或搜索“arctangent”。

编辑:我在帖子中使用了度数,但Java和许多其他语言/库使用弧度,其中180°=π。

您还可以将vx和vy添加到三角形的点中,使其向“前”移动,但请确保向量已归一化(vx²+vy²=1),否则速度将取决于三角形的大小。


那么,一旦我有了这个角度,我该如何应用它,以便我知道如何增加/减少三角形每个点的x和y值? - Mark
此外,该网站似乎表明反正切仅适用于直角三角形,而我的是等腰三角形。 - Mark
你可以进行归一化并使用vx和vy(只需将它们添加到点的x/y坐标即可)。请注意,vx = sin(r)和vy = cos(r),这仅仅是反正切运算的相反。 - aib
在你的情况下,这并不重要。你可以交换正弦和余弦。它们基本上给出相同的曲线,只是相位差为PI/2。它只会影响到当你的角度从0开始时,你的三角形最初朝向的方向。 - Ates Goral
但是是的,我在评论中的意思是把sin()和cos()搞反了。关键是,在向量分量、向量角度和你的x/y位移之间来回转换非常容易。 - aib
显示剩余2条评论

4

我认为您需要存储三角形的旋转角度以及可能的当前速度。

x' = x + speed * cos(angle)
y' = y + speed * sin(angle)

注意,这里的角度是弧度制而不是角度制!

弧度 = 角度 * 2π / 360

一个圆中的弧度 = 2 * π

一个圆中的角度 = 360

对于顶点的位置,每个顶点都位于中心点的一定距离和角度处。在进行此计算之前,请添加当前旋转角度。这与计算移动的数学相同。


如果我要使用角度,公式将是:x' = x + speed * cos( myAngleInDegrees * ((2 * PI) / 360) ) y' = y + speed * sin( myAngleInDegrees * ((2 * PI) / 360) ) ?? - Mark
是的,而且更简洁的形式是:myAngleInDegrees * PI / 180。 - Ates Goral
是的,2 Pi / 360 简化为 Pi / 180。我试图展示其中的原因。 - Loren Pechtel

4

@Mark:

我曾尝试在此回答框中写一个向量、坐标、点和角度的初学者指南,但两次都改变了主意,因为这需要太长时间,而且我相信有很多教程可以更好地解释这些内容。

你的重心和“顶点”坐标不是向量;也就是说,认为它们是向量并没有什么好处。

你想要的向量vForward = pTip - pCentroid,可以通过从重心点中减去“顶点”角的坐标来计算。该向量的atan2(),即atan2(tipY-centY, tipX-centX),可以给出三角形“朝向”的角度。

至于它相对于什么,这并不重要。你的库可能使用约定,即增加的X轴(--->你看到的所有2D图表上的右/东方向)为0°或0π。增加的Y(顶部,北方)方向将对应90°或(1/2)π。


谢谢aib,非常清楚。我非常感激您的帮助! - Mark

4

这里还有一些内容:

向量代表位移。位移、平移、运动或者你想怎么称呼它都无法脱离一个起点的概念,这也是为什么我以上提到的“向前”向量被称为“从中心点开始”的原因,也是为什么“重心向量”,即具有重心点x/y分量的向量没有意义的原因。这些分量给出了重心点相对于原点的位移。换句话说,pOrigin + vCentroid = pCentroid。如果你从0点开始,加上一个代表重心点位移的向量,就可以得到重心点。

请注意:

vector + vector = vector
(两个位移的加法会得到第三个不同的位移)

point + vector = point
(对一个点进行移动/位移会得到另一个点)

point + point = ???
(两个点的加法没有意义;但是:)

point - point = vector
(两点之间的差值是它们之间的位移)

现在,这些位移可以用(至少)两种不同的方式来考虑。你已经熟悉其中一种——矩形坐标系(x,y),其中向量的两个分量分别表示在x和y方向的位移。然而,你也可以使用极坐标(r,Θ)。在这里,Θ表示位移的方向(相对于一个任意零角度的角度)和r表示距离。

举个例子,向量(1,1)代表在我们习惯看到的坐标系中向右移动一单位并向上移动一单位。它的极坐标等价于(1.414,45°),即同样的位移,但表示为“1.414单位在45°方向上的位移”。(再次使用方便的极坐标系,其中东方是0°,角度逆时针增加。)

极坐标和矩形坐标之间的关系为:

Θ = atan2(y, x)
r = sqrt(x²+y²) (现在你看到这个直角三角形从哪里来了吧?)

反之,

x = r * cos(Θ)
y = r * sin(Θ)

现在,由于从你的三角形重心到“顶端”角落绘制的线段会代表你的三角形所“面向”的方向,如果我们获得一条与该线平行的向量(例如 vForward = pTip - pCentroid),那么该向量的Θ坐标将对应着你的三角形所面对的角度。

再次考虑(1,1)向量。如果这是vForward,则意味着您的“顶部”点的x和y坐标都比重心大1。假设重心在(10,10)上。这将把“顶部”角落移到(11,11)。(记住,通过在先前方程式的两侧添加“+ pCentroid”,pTip = pCentroid + vForward。)现在这个三角形朝向哪个方向?45度,对吧?这是我们(1,1)向量的Θ坐标!


2

0
double v; // velocity
double theta; // direction of travel (angle)
double dt; // time elapsed

// To compute increments
double dx = v*dt*cos(theta);
double dy = v*dt*sin(theta);

// To compute position of the top of the triangle
double size; // distance between centroid and top
double top_x = x + size*cos(theta);
double top_y = y + size*sin(theta);

计算新的 top_x 和 top_y 的逻辑是否也完全适用于另外两个点? - Mark

0
首先,我会从重心开始而不是计算它。您知道三角形的重心位置和旋转角度,我会利用这些信息来计算顶点的位置。(提前为任何语法错误道歉,我刚开始涉足Java。)
//起始点
double tip_x = 10;
double tip_y = 10;

should be

double center_x = 10;
double center_y = 10;

//三角形详情

int width = 6; //base
int height = 9;

应该是一个由3个角度和距离对组成的数组。

angle = rotation_angle + vertex[1].angle;
dist = vertex[1].distance;    
p1_x = center_x + math.cos(angle) * dist;
p1_y = center_y - math.sin(angle) * dist;
// and the same for the other two points

请注意,我正在减去Y距离。你被屏幕空间倒置的事实绊住了。在我们的脑海中,随着向上移动,Y坐标增加--但屏幕坐标不是这样工作的。
如果您跟踪位置和旋转角度而不是导出旋转角度,则数学会简单得多。
此外,在您的最终代码中,您正在通过旋转角度修改位置。结果将是您的飞船每个更新周期都会按旋转角度转向。我认为目标类似于Asteroids,而不是猫追逐自己的尾巴!

很抱歉,我不理解这两行代码:angle = rotation_angle + vertex[1].angle; dist = vertex[1].distance;可能只是语法问题,但我不明白你在做什么... vertex[1]是什么?如果这很简单,那我很抱歉,我遇到的问题比我想象中的更多... - Mark
vertex[1]是不是代表三角形的顶点,而“角度”是它相对于中心的旋转?那么“距离”部分是什么意思? - Mark
我的意思是你的三角形信息是三个点,而不仅仅是顶点。我正在指定3个点中的第1个——一个数组。(注意:这也允许其他形状,不仅仅是三角形。) - Loren Pechtel
我建议将点存储为极坐标——即从中心点的角度和距离,而不是从中心点的x、y坐标。极坐标使旋转变得更加容易。 - Loren Pechtel
我知道了,谢谢提供信息,感谢帮助。尽管似乎我无意中把这个问题从位移变成了旋转,这并不是我真正想要做的! - Mark
我认为是我把它变成了旋转,但那是因为我认为你提出的方法存在弱点。 - Loren Pechtel

0

我可以看到,我需要将常见的2D旋转公式应用于我的三角形中才能得到结果,但是我在这里不同组件之间的关系上遇到了一些麻烦。

aib表示:

反正切函数(arctangent)vy/vx 的值,其中vx和vy是你的(质心-顶点)向量的两个分量,将给出向量的朝向角度。

这里的vx和vy是质心还是顶点的x和y坐标?我认为我对“向量”的术语有点困惑。我原本以为矢量只是表示方向的二维(在这种情况下)空间中的一个点。

那么,在这种情况下,如何计算质心到顶点的向量?只是质心吗?

meyahoocomlorenpechtel表示:

我认为你需要存储三角形的旋转角度,可能还需要存储其当前速度。

旋转角度是相对于什么的?三角形的原点还是游戏窗口本身?另外,对于未来的旋转,角度是上一次旋转的角度还是三角形的初始位置的角度?

感谢大家迄今为止的帮助,我非常感激!


0

为了达到所需的效果,您将希望将最顶部的顶点设置为重心。


你确定吗?像《小行星》这样的游戏将旋转中心放在飞船的中心,而不是在机头上。但无论你把它放在哪里,公式都是相同的。 - Loren Pechtel

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接