Performance 有没有更快的方法可以把东西绕成一个圈?

Performance 有没有更快的方法可以把东西绕成一个圈?,performance,actionscript-3,math,Performance,Actionscript 3,Math,目前,我正在使用Math.cos和Math.sin在游戏中移动圆圈中的对象,但在阅读了一些相关内容后,我怀疑它的速度很慢(虽然还没有进行适当的测试) 有没有什么方法可以更快地计算出这一点?。我一直在读到另一种选择,可以是有一种存储了预先计算结果的哈希表,就像电脑时代以前的老年人使用它一样 如果我是你,我会坚持使用正弦和余弦。它们是做你想做的事情最有效的方式。如果您真的想要获得最佳性能,那么您应该根据正弦和余弦值生成一个x和y值数组,然后将该数组的值插入圆的位置。这样,您就不会重复运行正弦和余弦,

目前,我正在使用Math.cos和Math.sin在游戏中移动圆圈中的对象,但在阅读了一些相关内容后,我怀疑它的速度很慢(虽然还没有进行适当的测试)

有没有什么方法可以更快地计算出这一点?。我一直在读到另一种选择,可以是有一种存储了预先计算结果的哈希表,就像电脑时代以前的老年人使用它一样


如果我是你,我会坚持使用正弦和余弦。它们是做你想做的事情最有效的方式。如果您真的想要获得最佳性能,那么您应该根据正弦和余弦值生成一个x和y值数组,然后将该数组的值插入圆的位置。这样,您就不会重复运行正弦和余弦,而是只运行一个周期。

如果您没有任何角加速度,请继续我的评论(角速度保持恒定——这是一项要求,要求对象在不改变中心指向力的情况下,保持在半径恒定的圆内移动,例如通过绳子中的张力),然后可以使用以下策略:

1) 计算
B=角速度*时间步长大小
。这是对象在单个时间步中需要经历的角度变化量

2) 计算
sinb=sin(B)
cosb=cos(B)

(三) 请注意,我们希望将角度从A更改为A+B(对象逆时针移动)。在这个推导中,我们所绕的圆的中心由原点给出。 由于圆的半径是恒定的,我们知道
r*sin(A+B)=y_new=r*sin(A)cos(B)+r*cos(A)sin(B)=y_old*cos(B)+x_old*sin(B)
r*cos(A+B)=x_new r*cos(A)*cos(B)-r*sin B=x_old*cos(B)-y*sin B

我们已经去掉了我们不知道的余弦和正弦,所以笛卡尔坐标可以写成

x_new=x_old*cosb-y_old*sinb

y_new=x_old*sinb+y_old*cosb

除了在一次调用的初始化步骤中,不再调用cos或sin。显然,如果
B
由于任何原因不断变化(角速度或时间步长变化),这不会为您节省任何东西

您会注意到这与将位置向量乘以固定旋转矩阵相同。你可以通过圆圈中心来翻译,如果你不想只考虑在原点有中心的圆。 第一次编辑 正如@user5428643提到的,由于半径漂移,该方法在数值上随时间不稳定。您可能可以通过周期性地重新规范化x和y来纠正这一点(
x\u new=x\u old*r\u const/sqrt(x\u old^2+y\u old^2)
和类似地,对于y,每几千步进行一次——如果您实现了这一点,请保存系数
r\u const/sqrt(x\u old^2+y\u old^2)
,因为
x和
y
)。如果我能想出一个更好的解决方案,我会仔细考虑并编辑这个答案

第二次编辑 关于随时间变化的数值漂移的更多评论:

<>我在C++和Python中做了一些测试。在C++中使用单精度浮点,即使在B=0.1时,100万个时间步之后也存在相当大的漂移。我用了一个半径为1的圆。在“双精度”中,我在1亿步之后没有发现任何肉眼可见的漂移,但检查半径显示,它在下面的几个数字中受到了污染。在每一步上进行重整化(如果只是进行可视化,这是不必要的)会导致运行时间比漂移版本慢大约4倍。然而,即使是这个版本,在每次迭代中也比使用sin和cos快2-3倍。我在g++中使用了完全优化(-O3)。在python中(使用数学软件包),我只在漂移版本和规范化版本之间获得了2的速度提升,然而sin和cos版本实际上介于两者之间——就运行时间而言,它几乎正好介于两者之间。在几千步中每一次重整都会使这个速度更快,但它并不像我的C++版本所能说的那么大。


我没有做太多的科学测试来获得计时,只是做了一些测试,以10为增量进行100万到10亿步。

另一种完全避免触发功能的可能性是使用极坐标模型,在其中设置距离和角度。例如,您可以将x坐标设置为距离,将旋转设置为角度,如

    var gameBoardPin:Sprite = new Sprite();
    var gameEntity:Sprite = new YourGameEntityHere();
    gameBoardPin.addChild( gameEntity );
…在你的循环中

    // move gameEntity relative to the center of gameBoardPin
    gameEntity.x = circleRadius;
    // rotate gameBoardPin from its center causes gameEntity to rotate at the circleRadius
    gameBoardPin.rotation = desiredAngleForMovingObject
gameBoardPin的x、y坐标将设置为gameEntity的旋转中心。所以,如果你想让游戏实体以100像素的绳子围绕舞台中心旋转,你可以

    gameBoardPin.x = stage.stageWidth / 2;
    gameBoardPin.y = stage.stageHeight / 2;
    gameEntity.x = 100;
    desiredAngleForMovingObject += 2;
    gameBoardPin.rotation = desiredAngleForMovingObject
…然后在循环中你可能

    gameBoardPin.x = stage.stageWidth / 2;
    gameBoardPin.y = stage.stageHeight / 2;
    gameEntity.x = 100;
    desiredAngleForMovingObject += 2;
    gameBoardPin.rotation = desiredAngleForMovingObject

使用此方法时,您使用的是度而不是弧度。

抱歉,没有足够的代表发表评论

@neocpp和@oliveryas01的答案都是完全正确的,没有舍入错误

@oliveryas01给出的答案,只要直接使用正弦和余弦,并在必要时预先计算和存储许多值,就可以了

然而,@neocpp的答案,使用旋转矩阵以小角度重复旋转,在数值上是不稳定的;随着时间的推移,半径中的舍入误差将呈指数增长,因此,如果长时间运行程序,对象将缓慢移出圆,向内或向外螺旋移动

通过一点数值分析,您可以从数学上看到这一点:在每个阶段,平方半径近似乘以一个数字,该数字近似为常数且近似等于1,但由于浮点表示的不精确性,几乎肯定不完全等于1

当然,如果您使用的是双精度数字,并且只想获得简单的视觉效果,那么