图像渲染和动画——动作

  • A+
所属分类:cocos2dx

图像渲染和动画——动作

动作

有时限动作(FiniteTimeAction)

  • 即时动作(ActionInstant)和持续动作(ActionInterval)

即时动作(ActionInstant)

  • 即时动作只能够立刻完成的动作,这类动作是在下一帧立刻完成的动作,如设定位置、设定缩放等。

这里需要注意的是下一帧立刻完成,而不是当前帧。这是由于引擎的动作实现是在一个大的main>这里需要注意的是下一帧立刻完成,而不是当前帧。这是由于引擎的动作实现是在一个大的main loop里面去执行每个动作的update方法。

执行runAction方法只是把动作加入ActionManager而已。

常用即时动作

Place: 该动作用于将节点放置到某个指定位置。

 auto placeAction = Place::create(Vec2::ZERO);
  1. FlipX: 水平翻转
  2. FlipY: 垂直翻转
  3. Show: 显示节点
  4. Hide: 隐藏节点

CallFunc

  • CallFunc系列动作包括CallFunc、CallFuncN两个动作,用来在动作中进行方法调用。

一个简单动作的例子(节点显示,然后移动到(0,0)接着水平翻转,再移动回初始位置并隐藏,之后执行匿名函数输出actionMoveDone)

 void TestScene1::onTouchEnded( Touch* touch, Event* event )
 {
  log("onTouchEnded");
  auto sprite2 = static_cast<Sprite*>(this->getChildByName("sprite2"));
  if (sprite2)
  {
   auto moveBy = MoveBy::create(0.4f, Vec2::ZERO - sprite2->getPosition());
   auto actionMoveDone = CallFunc::create([&](){
    log("actionMoveDone");
   });
   auto actionSeq = Sequence::create(Show::create(), MoveTo::create(0.4f, Vec2::ZERO), FlipX::create(true), moveBy->reverse(), Hide::create(), actionMoveDone, nullptr);
   sprite2->runAction(actionSeq);
  }
 }

moveBy有reverse方法,而moveTo的reverse不可用,因为其_positionDelta值需等到startWithTarget的时候才会进行赋值。想要使用,除非在动作执行完毕后用。

持续动作(ActionInterval)

  • 属性变化动作

    属性变化动作通过属性值的逐渐变化来实现动画效果。

    1. MoveTo, MoveBy: 用于使节点做直线运动,设置了动作时间和终点位置,在规定时间内会移动到终点。
    2. JumpTo, JumpBy: 使节点以一定的轨迹跳跃到指定位置。
    3. BezierTo, BezierBy: 使节点进行曲线运动,运动的轨迹由贝塞尔曲线描述。
    4. ScaleTo, ScaleBy: 产生缩放效果,使节点的缩放系数随时间线性变化。
    5. RotateTo, RotateBy: 产生旋转效果。

贝塞尔曲线: 每条贝塞尔曲线都包含一个起点和一个终点。在一条曲线中,起点和终点各自包含一个控制点,而控制点到端点的连线称作控制线。控制点决定了曲线的形状,包含角度和长度两个参数。

视觉特效动作

该类用来实现特殊视觉效果

  1. FadeIn, FadeOut, FateTo: 产生淡入淡出效果,和透明变化效果。
  2. TintTo, TintBy: 设置色调变化,这个动作较少使用。
  3. Blink: 使节点闪烁。

动画动作(Animate)

以帧动画形式实现动画效果。

  • 两种方式创建动画动作

    1. 手工动画(Manual animation)

     auto animation = Animation::create();
     for( int i = 1; i != 15; ++i)
     {
      char szName[100] = {0};
      sprintf(szName, "grossini_dance_%02d.png", i);
      animation->addSpriteFrameWithFile(szName);
     }
     animation->setDelayPerUnit(2.8f / 14.0f);
     animation->setRestoreOriginalFrame(true);
     auto animate = Animate::create(animation);
    

    2. 文件动画(File animation)

     auto cache = AnimationCache::getInstance();
     cache->addAnimationsWithFile("animations-2.plist");
     auto animation1 = cache->getAnimation("dance_1");
     auto animate1 = Animate::create(animation1);
     arrayOfActions.pushBack(animate1);
    

延时动作(DelayTime)

用来提供一段空白期。

复合动作

  1. Repeat, RepeatForever:反复执行某个动作。
  2. Spawn:使一批动作同时执行。
  3. Sequence: 让各种动作有序执行。

变速动作

  1. Speed:用于线性的改变某个动作的速度。
  2. ActionEase:可以实现动作的速度又快到慢、速度随时间改变的匀速运动。该类包含5类运动,指数缓冲、Sine缓冲、弹性缓冲、跳跃缓冲和回震缓冲。每类运动都包含3个不同时期的变换:In、Out和InOut。
  • 动作使用例子(推荐使用lambda,可以使代码更简洁)
 void TestScene1::onTouchEnded( Touch* touch, Event* event )
 {
  log("onTouchEnded");
  auto visibleSize = Director::getInstance()->getVisibleSize();
  auto sprite2 = static_cast<Sprite*>(this->getChildByName("sprite2"));
  if (sprite2)
  {
   auto moveTo = MoveTo::create(0.5f, Vec2::ZERO);
   auto easeSinIn = EaseSineIn::create(moveTo);
   auto moveBy = MoveBy::create(0.5f, Vec2(visibleSize.width/2, visibleSize.height/2));
   auto jumpTo = JumpTo::create(0.5f, Vec2(visibleSize.width/2, visibleSize.height/2), 5, 1);
   auto jumpBy = JumpBy::create(0.5f, Vec2(visibleSize.width/2, visibleSize.height/2), 5, 1);
   auto rotateTo = RotateTo::create(1.8f, 180);
   auto rotateBy = RotateBy::create(1.8f, 180);
   auto scaleTo = ScaleTo::create(2.0f, 3);
   auto scaleBy = ScaleBy::create(2.0f, 2);
   auto repeat = Repeat::create(rotateBy, 3);

   auto fadeOut = FadeOut::create(0.8f);
   auto fadeIn = FadeIn::create(0.8f);
   auto fadeTo = FadeTo::create(0.8f, 200);
   auto tintTo = TintTo::create(2.4f, 128, 128, 128);
   auto tintBy = TintBy::create(2.4f, 255, 255, 255);
   auto blink = Blink::create(2.4f, 12);

   auto delayTime = DelayTime::create(1.2f);

   // 创建动画的第一种方式:手工动画
   auto animation = Animation::create();
   for( int i = 1; i != 15; ++i)
   {
    char szName[100] = {0};
    sprintf(szName, "grossini_dance_%02d.png", i);
    animation->addSpriteFrameWithFile(szName);
   }
   animation->setDelayPerUnit(2.8f / 14.0f);
   animation->setRestoreOriginalFrame(true);
   auto animate = Animate::create(animation);

   // 创建动画的第二种方式:文件动画
   auto cache = AnimationCache::getInstance();
   cache->addAnimationsWithFile("animations-2.plist");
   auto animation1 = cache->getAnimation("dance_1");
   auto animate1 = Animate::create(animation1);

   // 贝塞尔曲线
   ccBezierConfig bezier;
   bezier.controlPoint_1 = Vec2(0, visibleSize.height);
   bezier.controlPoint_2 = Vec2(visibleSize.width, 0);
   bezier.endPosition = Vec2(visibleSize.width, visibleSize.height);
   auto bezierTo = BezierTo::create(4.8f, bezier);

   // 同时执行MoveTo和ScaleTo
   auto spawn = Spawn::create(
    MoveTo::create(2.0f, Vec2(visibleSize.width/2, visibleSize.height/2)),
    scaleTo, nullptr);

   auto actionDone = CallFuncN::create([animate](Node* sender){
    log("actionDone");  // sender的值会在startWithTarget的时候被设置
    auto repeatForever = RepeatForever::create(animate);
    auto speed = Speed::create(repeatForever, 0.5f);
    sender->runAction(speed);
    // PS: speed不能放入Sequence
   });

   // Sequence的第一种创建方式cocos2d::Vector<cocos2d::FiniteTimeAction*>
   cocos2d::Vector<cocos2d::FiniteTimeAction*> arrayOfActions;
   arrayOfActions.pushBack(Place::create(Vec2::ZERO));
   arrayOfActions.pushBack(bezierTo);
   arrayOfActions.pushBack(spawn);
   arrayOfActions.pushBack(rotateTo);
   arrayOfActions.pushBack(scaleBy);
   arrayOfActions.pushBack(repeat);
   arrayOfActions.pushBack(fadeOut);
   arrayOfActions.pushBack(fadeIn);
   arrayOfActions.pushBack(fadeTo);
   arrayOfActions.pushBack(tintTo);
   arrayOfActions.pushBack(animate);
   arrayOfActions.pushBack(delayTime);
   arrayOfActions.pushBack(blink);
   arrayOfActions.pushBack(tintBy);
   arrayOfActions.pushBack(animate1);
   arrayOfActions.pushBack(actionDone);

   // Sequence的第二种创建方式FiniteTimeAction *action1, ...
   auto actionSeq1 = Sequence::create(Show::create(), easeSinIn, moveBy,
    moveBy->reverse(), jumpTo, jumpBy,
    CallFuncN::create([arrayOfActions](Node* sender){
     auto actionSeq2 = Sequence::create(arrayOfActions);
     sender->runAction(actionSeq2); // sender在startWithTarget里被设置
    }), nullptr);

   sprite2->runAction(actionSeq1);
  }
 }

说明

最后附上lambda表达式的一点说明和控制台输出显示的方法。

  • lambda表达式的一点说明:
  1. [] 不截取任何变量
  2. [&] 截取外部作用域中所有变量,并作为引用在函数体中使用
  3. [=] 截取外部作用域中所有变量,并拷贝一份在函数体中使用
  4. [=, &foo] 截取外部作用域中所有变量,并拷贝一份在函数体中使用,但是对foo变量使用引用。
  5. [bar] 截取bar变量并且拷贝一份在函数体重使用,同时不截取其他变量
  6. [this] 截取当前类中的this指针。如果已经使用了&或者=就默认添加此选项。
  • 控制台输出显示的方法:
    AllocConsole();
    freopen("CONOUT$", "w", stdout);
    
百分购

发表评论

您必须才能发表评论!