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