天天看点

cocos2d-x3.0中bezier曲线的分析

在action中,bezier曲线算是理解比较麻烦的,其中包含一定的数学几何原理在背后,在实际的开发中可以在一些简单的曲线运动模拟场合中使用,避免了对box2d等物理引擎的调用,cocos2d中封装的bezier曲线为两个控制点加终点,其实还应该包含与sprite的起始点,总共四个点,来对整个bezier曲线进行控制。

遗憾的是很多cocos2d-x的网上资料,包括一些开发书籍中对bezier的理解是有问题,甚至是错误的,可能只是能够使用,确不明白背后的原理。从而可能导致错误的使用。

我们首先简单的分析下bezier曲线的原理,其原本数学实现原理是更具控制点绘制控制区域,更具所设定的不同的比例截取点等比例的递归绘制控制点。如果对其具体实现感兴趣,可以自行查找,本文主要讲述cocos2d包装后的bezier曲线,包含两个控制点的bezier曲线简单原理,如下所示:

cocos2d-x3.0中bezier曲线的分析

其中a为起始点,b为a对应的控制点,d为终点,c为d对应的控制点。

当我们设定了这样的控制以后,从a到b的控制线决定了切线的方向为向下和曲线距离控制线的长度。d到c的控制线同样决定了切线的方向向下和曲线距离控制线的长度较之a到b的更近。

下面的2张图简单的阐述了在控制点的基础上,如何进一步根据方向和控制线的长度绘制出bezier曲线。当然,途中只是简单的找出了其中的bezier曲线上的一个点,不过其他的所有点都是采取这样的方式迭代绘制出来的。

cocos2d-x3.0中bezier曲线的分析
cocos2d-x3.0中bezier曲线的分析

当我们了解了bezier曲线的绘制后,我们便可以来看看cocos2d-x3.0版本中的tests示例中对于bezier曲线的简单例子。

在actiontest的actionbezier中,我们可以看到这样的定义,首先是人物的定义函数:

centerSprites(3);
           

实现如下:

numberOfSprites
           

由于参数为3,我们注意到在numberofsprites等于3的时候设定_grossini的参数为

Point(s.width/2, s.height/2),这个其实就是起始点的位置,而不少人误以为cocos2d-x中的bezier.controlPoint_1为起始点,其实是起始点对应的第一个控制点。

void ActionsDemo::centerSprites(unsigned int numberOfSprites)
{
    auto s = Director::getInstance()->getWinSize();

    if( numberOfSprites == 0 )
    {
        _tamara->setVisible(false);
        _kathia->setVisible(false);
        _grossini->setVisible(false);
    } 
    else if ( numberOfSprites == 1 ) 
    {
        _tamara->setVisible(false);
        _kathia->setVisible(false);
        _grossini->setPosition(Point(s.width/2, s.height/2));
    }
    else if( numberOfSprites == 2 ) 
    {        
        _kathia->setPosition( Point(s.width/3, s.height/2));
        _tamara->setPosition( Point(2*s.width/3, s.height/2));
        _grossini->setVisible(false);
    } 
    else if( numberOfSprites == 3 ) 
    {
        _grossini->setPosition( Point(s.width/2, s.height/2));
        _tamara->setPosition( Point(s.width/4, s.height/2));
        _kathia->setPosition( Point(3 * s.width/4, s.height/2));
    }
}
           

回到函数,继续进行bezier曲线相关的设置,我们只考虑其中grossini的运动轨迹就可以了,一定注意其中用的 by方法,既为相对位置,其他人的不考虑,原理类似:

// sprite 1
    ccBezierConfig bezier;
    bezier.controlPoint_1 = Point(0, s.height/2);
    bezier.controlPoint_2 = Point(300, -s.height/2);
    bezier.endPosition = Point(300,100);

    auto bezierForward = BezierBy::create(3, bezier);
    auto bezierBack = bezierForward->reverse();
    auto rep = RepeatForever::create(Sequence::create( bezierForward, bezierBack, NULL));
           

函数中,我们可以看见分别给bezier结构提进行了声明,然后设定了两个控制点,最后是终止点,在设定好后,利用bezierby进行封装,并调用reverse函数进行相反的路径设置,最后用sequece进行调用顺序的包装,最后放进repeatforever中进行循环调用。

_grossini->runAction( rep);
           

最后精灵进行动作的调用。

完成整个的动作调用。实现效果如下面所示:

cocos2d-x3.0中bezier曲线的分析
cocos2d-x3.0中bezier曲线的分析
cocos2d-x3.0中bezier曲线的分析
cocos2d-x3.0中bezier曲线的分析

从图中,我们可以发现grossini做了类似波浪线的运动,但到底是怎么养的波浪线呢,如我自己绘制的下图所示:

cocos2d-x3.0中bezier曲线的分析

其中a代表其实点,b代表控制点1,d为终点,c为控制点2,a到b的直线为控制线1,决定了曲线的方向和曲率,d到c的直线同样为控制线,决定了曲线或者叫切线的方向或者曲率,观察tests中的运动轨迹,发现和我绘制的bezier曲线基本一致。

成功的对bezier曲线进了基本原理的分析和在cocos2d-x3.0中的实际使用分析。

希望能帮助到同样遇到困后的人。

继续阅读