Cocos2d-x 动作的管理与动作的进度

前面简单的讲过Node的动作(Action),实际上在cocos2d-x中,还提供了一些关于动作的操控类函数;比如使用ActionManger,用于管理Action的一些动作如停止,暂停等,也可能使用ProgressTimer对动作进行进度展示;

一、动作的控制

>>1.停止所有动作
实际上,Node节点已经有了一些简单的动作的管理,比如停止Node实例上的所有动作;

    node->stopAllActions(); //
    node->runAction(ScaleTo::create(2, 2))

调用node->stopAllActions(); 之前的所有动作都将停止,但是,它并影响后续的动作,后续的ScaleTo动作将正常执行;

>>2.延时执行动作

cocos2d-x中,并没有简单的使用一个接口直接指定某一个动作延时一段时间后执行,但是,这都不是问题,下面是一个延时3s执行动作的例子;

    auto grossini = Sprite::create(s_pathGrossini);
    addChild(grossini, 0, 98); // 为sprite指定一个tag
    grossini->setPosition(VisibleRect::center() );
    
    auto action = MoveBy::create(1, Vec2(150,0));

    auto director = Director::getInstance();
    director->getActionManager()->addAction(action, grossini, true);

    schedule( schedule_selector(PauseTest::unpause), 3);  // 每3秒执行一次unpause方法;

unpause方法实现

    unschedule( schedule_selector(PauseTest::unpause) ); // 停止循环执行unpause方法
    auto node = getChildByTag( 98); // 获取sprite实例
    auto director = Director::getInstance();
    director->getActionManager()->resumeTarget(node); // 开始执行动作

上面的例子通过schedule循环更新的方法,每3s执行一次,当执行的时候,就取消循环来实现动作延时执行的效果;

>>3.停止动作

void StopActionTest::onEnter()
{
    auto pMove = MoveBy::create(2, Vec2(200, 0));
    auto pCallback = CallFunc::create(CC_CALLBACK_0(StopActionTest::stopAction,this));
    auto pSequence = Sequence::create(pMove, pCallback, NULL);
    pSequence->setTag(kTagSequence); // 为动作指定tag

    auto pChild = Sprite::create(s_pathGrossini);
    pChild->setPosition( VisibleRect::center() );

    addChild(pChild, 1, kTagGrossini);
    pChild->runAction(Sequence::create(ScaleTo::create(3.0f,2.0f), NULL));
    pChild->runAction(pSequence);
    
}

void StopActionTest::stopAction() // 停止动作
{
    auto sprite = getChildByTag(kTagGrossini); // 通过tag获取sprite
    sprite->stopActionByTag(kTagSequence); // 停止sprite上的指定的tag的动作
}

停止Node的某一个动作简单来说,就是预先给动作指定一个tag,在要停止它的时候,通过stopActionByTag(tag)来停止它;
>>4.Resume动作

void ResumeTest::onEnter()
{
   
    auto pGrossini = Sprite::create(s_pathGrossini);
    addChild(pGrossini, 0, kTagGrossini);
    pGrossini->setPosition(VisibleRect::center());

    pGrossini->runAction(ScaleBy::create(2, 2));

    auto director = Director::getInstance();

    director->getActionManager()->pauseTarget(pGrossini);// @1
    pGrossini->runAction(RotateBy::create(2, 360));  
    this->schedule(schedule_selector(ResumeTest::resumeGrossini), 3.0f);
}

void ResumeTest::resumeGrossini(float time)
{
    this->unschedule(schedule_selector(ResumeTest::resumeGrossini));

    auto pGrossini = getChildByTag(kTagGrossini);
    auto director = Director::getInstance();
    director->getActionManager()->resumeTarget(pGrossini);
}

@1:在上面的代码中,pauseTarget方法调用之后,又再次调用了runAction,那它会不会先执行这个动作呢?实际上,是不会的(亲测),所以,我大胆的解释为pauseTarget之后,需要调用resumeTarget之后,才会执行Node实例自身的未完成的动作;

二、动作进度

实际上对动作的控制除了delay,stop,resume之外,还可以让它有一个动作的进度的展示;
动作简单来讲分为两种:圆形 + 条形;

所谓圆进度动作其实类似于android的圆形进度环,而条形进度动作类似于android的条形进度条,对于后者,在cocso2d-x中拥有更多的进度展示方案,比如从左到右,从中间到两端等效果;

>>1.圆形进度条

void SpriteProgressToRadial::onEnter()
{
    auto s = Director::getInstance()->getWinSize();

    auto to1 = Sequence::createWithTwoActions(ProgressTo::create(2, 100), ProgressTo::create(0, 0));
    auto to2 = Sequence::createWithTwoActions(ProgressTo::create(2, 100), ProgressTo::create(0, 0));

    auto left = ProgressTimer::create(Sprite::create(s_pathSister1));
    left->setType( ProgressTimer::Type::RADIAL ); // 设置进度样式为RADIAL,实际上呈现出的效果就是一个圆形的动作加载过程;
    addChild(left);
    left->setPosition(Vec2(100, s.height/2));
    left->runAction( RepeatForever::create(to1));
    
    auto right = ProgressTimer::create(Sprite::create(s_pathBlock));
    right->setType(ProgressTimer::Type::RADIAL);
    // Makes the ridial CCW
    right->setReverseProgress(true); // 反转动作进度->和上一个动作的加载方向正好相反;
    addChild(right);
    right->setPosition(Vec2(s.width-100, s.height/2)); 
    right->runAction( RepeatForever::create(to2));
}

上面简单的列举了一个圆形进度动作,所呈现出的效果其实就是两个圆形进度的动作,并且一个顺时针一个逆时针执行(暂未截图,比较麻烦;);

2.条形进度动作

void SpriteProgressToHorizontal::onEnter()
{
    auto to1 = Sequence::createWithTwoActions(ProgressTo::create(2, 100), ProgressTo::create(0, 0));
    auto to2 = Sequence::createWithTwoActions(ProgressTo::create(2, 100), ProgressTo::create(0, 0));
    
    auto left = ProgressTimer::create(Sprite::create(s_pathSister1));
    left->setType(ProgressTimer::Type::BAR); // 设置进度为条形进度条
    // 设置进度的起点位置:在这里(0,0)表示进度的起始位置是(0,0)
    left->setMidpoint(Vec2(0,0)); //
    // 设置进度改变速率:同设置MidPoint一样,也是用一个Vec2表示;
    left->setBarChangeRate(Vec2(1, 0)); //
    addChild(left);
    left->setPosition(Vec2(100, s.height/2));
    left->runAction( RepeatForever::create(to1));
    
    auto right = ProgressTimer::create(Sprite::create(s_pathSister2));
    right->setType(ProgressTimer::Type::BAR);
    right->setMidpoint(Vec2(1, 0));
    right->setBarChangeRate(Vec2(1, 0));
    addChild(right);
    right->setPosition(Vec2(s.width-100, s.height/2));
    right->runAction( RepeatForever::create(to2));
}

这里重点说一下setMidPoint()方法和setBarChangeRate()方法;两个方法都需要传入一个Vec2参数;分别用于设置动作进度的起始位置和动作改变的速率;

  • setMidPoint:设置动作进度的起始位置,(0,0)和(1,1)涵盖了整个Node的区域,分别对应左下和右上;
  • setBarChangeRate:设置动作进度的速度改变速率(加速度?对于这个概念暂时不是很清楚),它也是一个(0,0)到(1,1)的Vec2值,其中0表示在这个方向上,Node一直保持为100%,不参与动作的进度过渡过程;

通常setMidPoint是和setBarChangeRate方法配合使用的,比如想要设置一个由中心向四周扩散的动作进度就可以这样来写:

node.setMidPoint(Vec2(0.5f,0.5f));
node.setBarChangeRate(Vec2(1,1));

 

完!

 

你可能感兴趣的:(cocos2d-x)