cocos2dx 3.2 学习篇之六(精灵运动,自定义运动轨迹(太极八卦))

        好了,今天想要讲的是如何让精灵按照自己定义的路径去运动,官方给我们了一个action类,里面有很多运动的类型,比如bezier曲线运动,比如jump运动等等,设计好了运动之后,我们只要让精灵调运runAction()即可。 本人呢是十足的秦时明月粉丝,特别喜欢里面 的 少司命!!!简直是我的女神呀,所以自然想和少司命搭上一点关系那,就记得当初少司命 搭救 盗跖 那次 耍了一招 用树叶画八卦阵放大招技能来着。 然后就让我各种各种激动(原谅我爱少司命爱的那么深沉!)

      好的,转入正题,首先我们可以看看利用 粒子系统运动轨迹做出来效果如何。。。

这个是我静态的粒子系统,是树叶绕着中心转,有一点点散开的效果:



这个是粒子系统在在八卦路线的时候样子,如果有少司命的纤细小手的话技能就好看了:


由于本人用了粒子系统有散开效果,所有早先的路径下叶子就有点散开了,也可以通过叶子浓度看出叶子经过的路径方向。


       首先我们来分析原理,最一开始,我们画了一个 半径为R,中心点为(a,b)的圆,等圆画完以后紧接着画一个半斤为 R/2 ,中心点为(a-R/2 , b)的半个圆(上半个圆弧),再接着,我们就画半径为 R/2 ,中心点为 (a+R/2 , b )的半圆弧(在图中由于截图过早的问题还没有画完整)。这样,我们要的八卦效果就出来了。。。

       由上面分析可知,我们必须要解决画圆算法:由初中还是高中知识可知,x^2 + y^2 = R^2。然后再做适当平移(a,b)就可以得到我们指定中心点为(a,b),半径为R的圆了。 当然 x^2 + y^2 = R^2 求解由于正负的关系考虑比较复杂 ,所以我把它转化成为 : (R*cos(α))^2 + (R*sin(α))^2  = R^2 所以我们的圆上点坐标为 (a+R*cos(α) ,a+R*sin(α) ), 其中 α > 0 && α <2 * Pi , 这样就是我们要画的正圆了。通过 对 α 范围控制,我们也可以画我们指定想要的半圆。

       

//定义一个结构体,包含里中心点坐标以及要画圆的半径长度
typedef struct _WuzhuangConfig
{
    cocos2d::Point centerPosition;//中心点坐标
    float rudius;//半径
}WuzhuangConfig;

//根据画圆进度t以及圆的配置信息计算出圆上点坐标
static inline Vec2 PointAt(float t /*这里的t代表画圆进度,若单纯顺时针画一个圆时,与动作进度相同
                                    ,若逆时针或者画半圆等需要一定映射关系*/
                           , const WuzhuangConfig c )
{
    float x = - c.rudius * cos(3.1415926 * t * 2  ) + c.centerPosition.x ;
    //上面加负号时因为从左手边开始画起
    float y = c.rudius * sin(3.1415926 * t * 2  ) + c.centerPosition.y;
    return Vec2(x,y);
}


       好,上面解决了画圆问题,下面我们来剖析我们画圆的顺序与 动作进度 t (0代表动作起点,1代表动作结束,0.5代表动作执行到了刚刚好一半) 之间关系 。 

       上面大圆的周长是全路径的 2/3 (初中知识不解释),小半圆分别占了全路径的 1/6 。

       故 t < 2.0/3 && t>0 时 , 我们执行画大圆操作。因为我们要画的整个大圆 ,而不是2/3个圆,故我们需要把动作进度映射到画圆进度上 即画大圆的进度 p = t * 3/2 。这样就可以画出整个大圆了。

       同理 t < 5/6 && t >2/3 时,p = (t- 2.0/3) * 3  ; 当 t >5/6 && t < 1 时,p = 7.0/2 - t * 3 ;

    知道了这个映射关系以后,我们就可以写出整个画八卦的根据 动作进度 t 的函数

    

void Wuzhuang::update(float t)
{
    if(_target)
    {
       if(t < 2.0/3)
       {
           _target->setPosition(PointAt( 3.0 / 2 * t, m_config ));
       }
       else
        {
            if(t < 5.0/6)
            {
                _target->setPosition(PointAt((t- 2.0/3) * 3 , m_config1/*小圆1配置信息*/ ));
            }
            else
            {
                _target->setPosition(PointAt( 7.0/2 - t * 3, m_config2/*小圆2配置信息*/ ));
            }
        }
    }
}

介绍完了画圆核心的,剩下的就是简单设置配置属性和定义一个调用接口了。

//小圆的配置信息
WuzhuangConfig m_config1,m_config2;
//初始化
bool Wuzhuang::initWithDuration(float t, const WuzhuangConfig& c)
{
    if (ActionInterval::initWithDuration(t))
    {
        m_config = c;
        
        m_config1.rudius = c.rudius/2;
        m_config2.rudius = c.rudius/2;
        
        m_config1.centerPosition = c.centerPosition - Vec2(c.rudius/2,0);
        m_config2.centerPosition = c.centerPosition + Vec2(c.rudius/2,0);
        return true;
    }
    return false;
}

//外部调用的静态接口
Wuzhuang* Wuzhuang::actionWithDuration(float t,const WuzhuangConfig& c)
{
    Wuzhuang* pWuzhuang = new Wuzhuang();
    pWuzhuang ->initWithDuration(t, c);
    pWuzhuang ->autorelease();
    return pWuzhuang;
}

基本整个代码就是这样了。。这样外部就可以调用了。调用的话就像调用bezierby一样调用就好了。

    WuzhuangConfig m_config;
    m_config.centerPosition = Vec2(370, 500);
    m_config.rudius = 200;
    
    Wuzhuang* pAction = Wuzhuang::actionWithDuration(4, m_config);
    p->runAction(pAction);


     所有想要自定义的动作都可以通过这样实现。如果不懂可以去看看BezierBy这样的类他们时怎么实现的,仿照他们这样写就可以了。。。


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值