我太过数学了,很难受,但对你们中的某些人来说应该是小菜一碟。我想在一个简单的圆形路径上沿对象的年龄或周长围绕另一个对象移动对象。目前,我的游戏算法知道如何移动精灵并将其放置在障碍物的边缘,现在它会根据各种条件等待下一个点的移动。
因此,这里的数学问题是如何得到(AX,AY)和(BX,BY)位置,当我知道中心(CX,CY),目标位置(OX,OY)和需要移动的距离(d)
我太过数学了,很难受,但对你们中的某些人来说应该是小菜一碟。我想在一个简单的圆形路径上沿对象的年龄或周长围绕另一个对象移动对象。目前,我的游戏算法知道如何移动精灵并将其放置在障碍物的边缘,现在它会根据各种条件等待下一个点的移动。
因此,这里的数学问题是如何得到(AX,AY)和(BX,BY)位置,当我知道中心(CX,CY),目标位置(OX,OY)和需要移动的距离(d)
Answers:
(CAVEAT:我在这里使用两个近似值:第一个近似值d为圆弧长度,第二个近似值为正交长度。这两个近似值对于d的较小值都应该是好的,但它们不能满足注释中阐明的确切问题。)
幸运的是,关于这一点的数学相对简单。首先,我们可以找到从中心位置到当前位置的相对矢量:
deltaX = oX-cX;
deltaY = oY-cY;
一旦有了这个相对矢量,我们就可以通过找到圆的长度来知道我们正在加工的圆的半径:
radius = sqrt(deltaX*deltaX+deltaY*deltaY);
此外,从我们的相对矢量中,我们可以找到从cX到oX的直线的精确角度:
curTheta = atan2(deltaX, deltaY);
现在事情变得有些棘手了。首先,请了解圆的周长(即,角度为2π的圆弧的“弧长”)为2πr。通常,沿半径为r的圆的角度为θ的弧的弧长仅为θr。如果我们将图表中的d用作圆弧长度,并且由于我们知道半径,我们可以通过除以找到theta的变化以将我们带到新位置:
deltaTheta = d/radius; // treats d as a distance along the arc
对于d需要为线性距离的情况,情况会稍微复杂一些,但幸运的是,情况并不多。d是等腰三角形的一侧,另一侧是圆的半径(分别从cX / cY到oX / oY和aX / aY),将等腰三角形二等分可以得到两个直角三角形,每个直角三角形d / 2为一侧,半径为斜边;这意味着我们一半角度的正弦为(d / 2)/半径,因此整个角度仅为此的两倍:
deltaTheta = 2*asin(d/(2*radius)); // treats d as a linear distance
请注意,如果您从该公式中删除了asin并取消了2s,它将与最后一个公式相同;这与说x(x)较小时sin(x)近似为x相同,这是一个有用的近似值。
现在我们可以通过添加或减去找到新角度:
newTheta = curTheta+deltaTheta; // This will take you to aX, aY. For bX/bY, use curTheta-deltaTheta
一旦有了新的角度,就可以使用一些基本的trig来查找更新的相对矢量:
newDeltaX = radius*cos(newTheta);
newDeltaY = radius*sin(newTheta);
从中心位置和相对矢量我们可以(最终)找到目标点:
aX = cX+newDeltaX;
aY = cY+newDeltaY;
现在,所有这些都需要注意一些重大警告。首先,您会注意到该数学运算主要是浮点运算,实际上几乎必须是浮点运算。尝试使用此方法循环更新并在每一步取整为整数值可以完成从使圆不闭合(每次绕圈向内或向外盘旋)到第一次不开始时的所有操作地点!(如果d太小,则可能会发现aX / aY或bX / bY的舍入版本恰好是起始位置oX / oY所在的位置。)另一方面,这非常昂贵,尤其是对于它试图做; 通常,如果您知道角色将沿圆弧运动,则应提前计划整个弧度,而不是像这样逐帧打勾,因为这里许多最昂贵的计算都可以预先加载以降低成本。如果您确实想像这样逐步进行更新,则另一种降低成本的好方法是不要首先使用trig。如果d很小,并且您不需要精确而又非常接近,则可以通过向oX / oY添加长度为d的矢量(正交于朝向您的中心的矢量)来进行“欺骗”与(dX,dY)正交的向量由(-dY,dX)给出,然后将其缩小到正确的长度。我不会一步一步地解释此代码,但是希望您到目前为止已经看到的内容对它有意义。请注意,我们在最后一步中隐式“缩小”了新的增量矢量,
deltaX = oX-cX; deltaY = oY-cY;
radius = sqrt(deltaX*deltaX+deltaY*deltaY);
orthoX = -deltaY*d/radius;
orthoY = deltaX*d/radius;
newDeltaX = deltaX+orthoX; newDeltaY = deltaY+orthoY;
newLength = sqrt(newDeltaX*newDeltaX+newDeltaY*newDeltaY);
aX = cX+newDeltaX*radius/newLength; aY = cY+newDeltaY*radius/newLength;
使用已有的两个边形成一个三角形(一侧从'c'到'o',另一侧从'o'到'a'),第三侧从'a'到'c'。您不知道“ a”在哪里,只需想象现在有一个点。您将需要三角函数来计算与“ d”面相对的角度。您具有边c <-> o和c <-> a的长度,因为它们都是圆的半径。
现在,您已经知道了该三角形的三个边的长度,您可以确定与三角形的“ d”侧相反的角度。如果需要,这是SSS(侧面-侧面)公式: http //www.teacherschoice.com.au/maths_library/trigonometry/solve_trig_sss.htm
使用SSS公式,您可以得到与边“ d”相对的角度(我们将其称为“ j”)。因此,现在我们可以计算(aX,aY)。
// This is the angle from 'c' to 'o'
float angle = Math.atan2(oY - cY, oX - cX)
// Add the angle we calculated earlier.
angle += j;
Vector2 a = new Vector2( radius * Math.cos(angle), radius * Math.sin(angle) );
确保您要计算的角度始终为弧度。
如果需要计算圆的半径,可以使用向量减法,从点“ o”中减去点“ c”,然后获得所得向量的长度。
float lengthSquared = ( inVect.x * inVect.x
+ inVect.y * inVect.y
+ inVect.z * inVect.z );
float radius = Math.sqrt(lengthSquared);
我相信,这样的事情应该可以做。我不懂Java,所以我猜到了确切的语法。
这是用户给出的图像,Byte56
用于说明此三角形的外观:
要使obj2围绕obj1旋转,可以尝试:
float angle = 0; //init angle
//call in an update
obj2.x = (obj1.x -= r*cos(angle));
obj2.y = (obj1.y += r*sin(angle));
angle-=0.5;
d
直线距离还是弧线?