[cocos2d-x]捕鱼达人炮台射击角度的旋转实现
话不多说,先上图,下面是实现代码(在后面会具体讲解实现过程):
//第一步:将炮台的坐标转换为世界坐标下的坐标点
CCPoint location = this->getParent()->convertToWorldSpace(this->getPosition());
//第二部:计算出两个向量之间的夹角
float angle = ccpAngleSigned(ccpSub(target, location), CCPointMake(0, 1));
//因为求出的角度是以π为单位,所以这里要转换成以度为单位
this->setRotation(CC_RADIANS_TO_DEGREES(angle));
下面是ccpAngleSinged的实现代码:
CC_DEPRECATED_ATTRIBUTE static inline float ccpAngleSigned(const Vec2& a, const Vec2& b)
{
return a.getAngle(b);//可以看到,这里是a向量对b向量获取角度,我们再往里跳一步看具体的实现
}
我们再跳入getAngle看具体实现:
float Vec2::getAngle(const Vec2& other) const
{
//第一步:先将a,b向量进行规范化,也就是获得两个方向上的单位向量
Vec2 a2 = getNormalized();
Vec2 b2 = other.getNormalized();
//这一步很重要!!!留到最后来讲这一步的实现,涉及到了线性代数的一些知识
float angle = atan2f(a2.cross(b2), a2.dot(b2));
//判断角度是否小于浮点数能表示的最小值(float用的是IEEE754标准,23位表示尾数,8位表示数阶,1位表示尾数符号)
if (std::abs(angle) < FLT_EPSILON) return 0.f;
return angle;
}
接下来讲最重要的一步:
float angle = atan2f(a2.cross(b2), a2.dot(b2));
首先要了解一些线性代数的知识,向量积和数量积;atan2f是math库内的函数,而cross求的是向量积的模,dot求的是数量积,下面给出它们两个的代码:
/** Calculates cross product of two points.
@return float
@since v2.1.4
* @js NA
* @lua NA
*/
//这个求的是向量积,二维坐标下也就是一个二阶行列式的计算
inline float cross(const Vec2& other) const {
return x*other.y - y*other.x;
}
//这个求的是数量积
inline float Vec2::dot(const Vec2& v) const
{
return (x * v.x + y * v.y);
}
然后,我们要知道下面两个公式:
而通过上述的公式可知: arctan(tan⊙)=⊙,而向量积的模除以数量积的模等于tan⊙,经过这样一换算,很简单的就能得出这两个向量之间的角度。
最后,只需要调用精灵的setRotation旋转相应的角度即可。
PS:当然,如果不知道上面这两个公式也是能做的(毕竟引擎库都已经封装好了),我们也可以自己来实现这个角度的计算,比如通过射击目标到炮台位置的向量的X,Y方向长度,利用tan(y/x)=角度,直接计算出角度(不过这里可能要进行判断x的正负,需要一些其他的逻辑判断)
https://github.com/li-zheng-hao