Loading

[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的正负,需要一些其他的逻辑判断

posted @ 2017-08-15 21:51  李正浩  阅读(240)  评论(0编辑  收藏  举报