1. 当前所在位置:
  2. 首页
  3. 游戏打鱼

[cocos2d-x]捕鱼达人炮台射击角度的旋转实现

2018-12-18 admin
 
话不多说,先上图,下面是实现代码(在后面会具体讲解实现过程):
 
 //第一步:将炮台的坐标转换为世界坐标下的坐标点
 CCPoint location = this->getParent()->convertToWorldSpace(this->getPosition());
 //第二部:计算出两个向量之间的夹角
    float angle = ccpAngleSigned(ccpSub(target, location), CCPointMake(0, 1));
    //因为求出的角度是以π为单位,所以这里要转换成以度为单位
    this->setRotation(CC_RADIANS_TO_DEGREES(angle));
1
2
3
4
5
6
下面是ccpAngleSinged的实现代码:
 
CC_DEPRECATED_ATTRIBUTE static inline float ccpAngleSigned(const Vec2& a, const Vec2& b)
{
    return a.getAngle(b);//可以看到,这里是a向量对b向量获取角度,我们再往里跳一步看具体的实现
}
1
2
3
4
我们再跳入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;
}
1
2
3
4
5
6
7
8
9
10
11
12
接下来讲最重要的一步:
 
float angle = atan2f(a2.cross(b2), a2.dot(b2));
1
首先要了解一些线性代数的知识,向量积和数量积;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);
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
然后,我们要知道下面两个公式: 
 
 
而通过上述的公式可知: arctan(tan⊙)=⊙,而向量积的模除以数量积的模等于tan⊙,经过这样一换算,很简单的就能得出这两个向量之间的角度。 
 
 
最后,只需要调用精灵的setRotation旋转相应的角度即可。
 
PS:当然,如果不知道上面这两个公式也是能做的(毕竟引擎库都已经封装好了),我们也可以自己来实现这个角度的计算,比如通过射击目标到炮台位置的向量的X,Y方向长度,利用tan(y/x)=角度,直接计算出角度(不过这里可能要进行判断x的正负,需要一些其他的逻辑判断)
 
捕鱼驾到