最近在研究cocos2d-x v3.9的RotateTo时遇到了个问题,不知道是否算是Bug。
首先说一下我理解的RotateTo。RotateTo不关心精灵当前的角度,将精灵旋转至指定的角度。无论指定的角度是多少,最终旋转的角度一定在-360°~360°之间。进一步,我认为如果指定的角度为正角度则应按照顺时针方向将精灵旋转至指定角度;如果指定的角度为负角度,则应按照逆时针方向。
例如精灵的初始角度为0°,指定旋转角度为1090°,则实际应按照顺时针旋转10°(1090 % 360);又或者精灵的初始角度为0°,指定旋转角度为-591°,则实际应按照逆时针旋转231°(591 % 360)。
实际情况:比如精灵的初始角度均为0°。
1、
auto myRotateTo = RotateTo::create(3, 270);
mySprite->runaction(myRotateTo);
效果:以逆时针旋转90°。
2、
auto myRotateTo = RotateTo::create(3, -181);
mySprite->runaction(myRotateTo);
效果:以顺时针旋转179°。
看起来是遵循了就近原则,从当前角度到指定角度走了个最近路程。看一下源码:
void RotateTo::calculateAngles(float &startAngle, float &diffAngle, float dstAngle)
{
// 将startAngle更新为对360.0°求余的角度。
// 比如startAngle传进来是721.7°,更新后为1.7°。
if (startAngle > 0)
{
startAngle = fmodf(startAngle, 360.0f);
}
else
{
startAngle = fmodf(startAngle, -360.0f);
}
diffAngle = dstAngle - startAngle; // 得到目标角度与起始角度之间的差值。
if (diffAngle > 180)
{
diffAngle -= 360;
}
if (diffAngle < -180)
{
diffAngle += 360;
}
}
初步证实了,是就近原则那么个意思。如果顺时针的旋转角度大于180°了,那从逆时针方向转更近,逆时针方向的同理。
可真的是这样吗?继续测试。
3、
auto myRotateTo = RotateTo::create(3, 640);
mySprite->runaction(myRotateTo);
效果:以顺时针旋转280°。如果遵循就近原则,应该按照逆时针旋转80°。
4、
auto myRotateTo = RotateTo::create(3, -541);
mySprite->runaction(myRotateTo);
效果:以逆时针旋转181°。如果遵循就近原则,应该按照顺时针旋转179°。
5、
auto myRotateTo = RotateTo::create(3, 899);
mySprite->runaction(myRotateTo);
效果:以顺时针旋转539°。这更没什么就近原则之说了,起码效果上是多转了一圈。
6、
auto myRotateTo = RotateTo::create(3, -731);
mySprite->runaction(myRotateTo);
效果:以逆时针旋转371°。同上,没有就近原则之说,起码效果上多转了一圈。
**至此做个总结:
精灵的初始角度为0°,
当 -540° <= 指定的角度 <= 540°时,旋转遵循就近原则,旋转的角度在360°之内。
当 541° < 指定的角度 < 720° 或者 -720° < 指定的角度 < -541° 时,旋转不遵循就近原则,旋转的角度在360°之内。
当 指定的角度 >= 720° 或者 指定的角度 <= -720° 时,旋转的角度在360°之外,即起码多旋转了一圈,也就无法谈及是否遵循就近原则了。**
如果按照我理解的RotateTo,RotateTo::calculateAngles()应该是如下形式:
void RotateTo::calculateAngles(float &startAngle, float &diffAngle, float dstAngle)
{
diffAngle = fmodf(dstAngle, 360) - fmodf(startAngle, 360);
diffAngle = fmodf(diffAngle, 360);
if(((diffAngle < 0) && (dstAngle >= 0)) || ((diffAngle > 0) && (dstAngle < 0)))
{
if(diffAngle > 0)
diffAngle -= 360;
else
diffAngle += 360;
}
return ;
}
SkewTo在计算变化角度的时候也有同样的问题。此外,SkewTo在对X轴的变化角度取余的时候为何对180°求余?
if (_startSkewX > 0)
{
_startSkewX = fmodf(_startSkewX, 180.f); // 180°?
}
else
{
_startSkewX = fmodf(_startSkewX, -180.f); // 180°?
}
这样会导致问题。举个简单的例子,比如我让X轴从181°变换到191°,
sprite->setSkewX(181);
auto skewto = SkewTo::create(3, 191, 0);
sprite->runAction(skewto);
本意只是想让X轴沿顺时针方向变化10°,单实际的效果是X轴沿逆时针方向变化了170°。