首页 > 代码库 > cocos2d-x实战 C++卷 学习笔记--第7章 动作、特效(一)

cocos2d-x实战 C++卷 学习笔记--第7章 动作、特效(一)

前言:

介绍cocos2d-x中的动作、特效。

动作:

动作(action)包括基本动作和基本动作的组合,这些基本动作有缩放、移动、旋转等,而且这些动作变化的速度也可以设定。

 动作类是 Action。它的类图如下:

技术分享

Action有3个子类,FiniteTimeAction 是一种受时间限制的动作,Follow 是一种允许精灵跟随另一个精灵的动作,Speed是在一个动作运行时改变其运动速率。

瞬时动作:

 瞬时动作就是不等待立即执行的动作,瞬时动作的基类是ActionInstant。瞬时动作 ActionInstant 类图如下:

技术分享

代码示例:

技术分享
 1 #ifndef __HELLOWORLD_SCENE_H__ 2 #define __HELLOWORLD_SCENE_H__ 3  4 #include "cocos2d.h" 5 #include "Action.h" 6  7 typedef enum  8 { 9     PLACE_TAG = 102,10     FLIPX_TAG,11     FLIPY_TAG,12     HIDE_SHOW_TAG,13     TOGGLE_TAG,14     OTHER_ACTION,15     All_TAG_NUM16 }ActionTypes;17 18 class HelloWorld : public cocos2d::Layer19 {20 public:21     // there‘s no ‘id‘ in cpp, so we recommend returning the class instance pointer22     static cocos2d::Scene* createScene();23 24     // Here‘s a difference. Method ‘init‘ in cocos2d-x returns bool, instead of returning ‘id‘ in cocos2d-iphone25     virtual bool init();  26     27     // a selector callback28     void menuCloseCallback(cocos2d::Ref* pSender);29 30     void menuItemCallback_01(cocos2d::Ref* pSender);31     void menuItemCallback_02(cocos2d::Ref* pSender);32     void menuItemCallback_03(cocos2d::Ref* pSender);33     void menuItemCallback_04(cocos2d::Ref* pSender);34     void menuItemCallback_05(cocos2d::Ref* pSender);35     void menuItemCallback_06(cocos2d::Ref* pSender);36 37 38     // implement the "static create()" method manually39     CREATE_FUNC(HelloWorld);40 };41 42 #endif // __HELLOWORLD_SCENE_H__
HelloWorldScene.h
技术分享
  1 #include "HelloWorldScene.h"  2   3 USING_NS_CC;  4   5 Scene* HelloWorld::createScene()  6 {  7     // ‘scene‘ is an autorelease object  8     auto scene = Scene::create();  9      10     // ‘layer‘ is an autorelease object 11     auto layer = HelloWorld::create(); 12  13     // add layer as a child to scene 14     scene->addChild(layer); 15  16     // return the scene 17     return scene; 18 } 19  20 // on "init" you need to initialize your instance 21 bool HelloWorld::init() 22 { 23     ////////////////////////////// 24     // 1. super init first 25     if ( !Layer::init() ) 26     { 27         return false; 28     } 29      30     Size visibleSize = Director::getInstance()->getVisibleSize(); 31     Point origin = Director::getInstance()->getVisibleOrigin(); 32  33     ///////////////////////////// 34     // 2. add a menu item with "X" image, which is clicked to quit the program 35     //    you may modify it. 36  37     // add a "close" icon to exit the progress. it‘s an autorelease object 38     auto closeItem = MenuItemImage::create( 39                                            "CloseNormal.png", 40                                            "CloseSelected.png", 41                                            CC_CALLBACK_1(HelloWorld::menuCloseCallback, this)); 42      43     closeItem->setPosition(Point(origin.x + visibleSize.width - closeItem->getContentSize().width/2 , 44                                 origin.y + closeItem->getContentSize().height/2)); 45  46     // create menu, it‘s an autorelease object 47     auto menu = Menu::create(closeItem, NULL); 48     menu->setPosition(Point::ZERO); 49     this->addChild(menu, 1); 50  51     ///////////////////////////// 52     // 3. add your codes below... 53  54     Sprite* spbkground = Sprite::create("Demo1/Background480x800.png"); 55     // position the sprite on the center of the screen 56     spbkground->setPosition(Point(visibleSize.width / 2 + origin.x, visibleSize.height / 2 + origin.y)); 57     // add the sprite as a child to this layer 58     this->addChild(spbkground, 0); 59  60     /////////////////////// 61     auto label_1 = Label::createWithBMFont("Demo1/fonts/fnt2.fnt", "01 label"); 62     auto label_2 = Label::createWithBMFont("Demo1/fonts/fnt2.fnt", "02 label"); 63     auto label_3 = Label::createWithBMFont("Demo1/fonts/fnt2.fnt", "03 label"); 64     auto label_4 = Label::createWithBMFont("Demo1/fonts/fnt2.fnt", "04 label"); 65     auto label_5 = Label::createWithBMFont("Demo1/fonts/fnt2.fnt", "05 label"); 66     auto label_6 = Label::createWithBMFont("Demo1/fonts/fnt2.fnt", "06 label"); 67  68     MenuItemLabel* muLab1 = MenuItemLabel::create(label_1, CC_CALLBACK_1(HelloWorld::menuItemCallback_01, this)); 69     MenuItemLabel* muLab2 = MenuItemLabel::create(label_2, CC_CALLBACK_1(HelloWorld::menuItemCallback_02, this)); 70     MenuItemLabel* muLab3 = MenuItemLabel::create(label_3, CC_CALLBACK_1(HelloWorld::menuItemCallback_03, this)); 71     MenuItemLabel* muLab4 = MenuItemLabel::create(label_4, CC_CALLBACK_1(HelloWorld::menuItemCallback_04, this)); 72     MenuItemLabel* muLab5 = MenuItemLabel::create(label_5, CC_CALLBACK_1(HelloWorld::menuItemCallback_05, this)); 73     MenuItemLabel* muLab6 = MenuItemLabel::create(label_6, CC_CALLBACK_1(HelloWorld::menuItemCallback_06, this)); 74  75     muLab1->setTag(PLACE_TAG); 76     muLab2->setTag(FLIPX_TAG); 77     muLab3->setTag(FLIPY_TAG); 78     muLab4->setTag(HIDE_SHOW_TAG); 79     muLab5->setTag(TOGGLE_TAG); 80     muLab6->setTag(OTHER_ACTION); 81  82     Menu* mu = Menu::create(muLab1, muLab2, muLab3, muLab4, muLab5, muLab6,NULL); 83     mu->alignItemsVertically(); 84     mu->setPosition(Point(origin.x + visibleSize.width / 2, origin.y + visibleSize.height/2)); 85  86     this->addChild(mu); 87     return true; 88 } 89  90  91 void HelloWorld::menuCloseCallback(Ref* pSender) 92 { 93 #if (CC_TARGET_PLATFORM == CC_PLATFORM_WP8) || (CC_TARGET_PLATFORM == CC_PLATFORM_WINRT) 94     MessageBox("You pressed the close button. Windows Store Apps do not implement a close button.","Alert"); 95     return; 96 #endif 97  98     Director::getInstance()->end(); 99 100 #if (CC_TARGET_PLATFORM == CC_PLATFORM_IOS)101     exit(0);102 #endif103 }104 105 106 107 108 void HelloWorld::menuItemCallback_01(cocos2d::Ref* pSender)109 {110     MenuItem* muItem = (MenuItem*)pSender;111     auto sc = Scene::create();112     auto SecondLayer = CActionTest::create();113     SecondLayer->setTag(muItem->getTag());114     sc->addChild(SecondLayer);115     auto reScene = TransitionSlideInL::create(1.0f, sc);116     Director::getInstance()->replaceScene(reScene);117 118     log("function:%s, line:%d", __FUNCTION__, __LINE__);119 }120 121 void HelloWorld::menuItemCallback_02(cocos2d::Ref* pSender)122 {123     MenuItem* muItem = (MenuItem*)pSender;124     auto sc = Scene::create();125     auto SecondLayer = CActionTest::create();126     SecondLayer->setTag(muItem->getTag());127     sc->addChild(SecondLayer);128     auto reScene = TransitionSlideInR::create(1.0f, sc);129     Director::getInstance()->replaceScene(reScene);130 131     log("function:%s, line:%d", __FUNCTION__, __LINE__);132 }133 134 void HelloWorld::menuItemCallback_03(cocos2d::Ref* pSender)135 {136     MenuItem* muItem = (MenuItem*)pSender;137     auto sc = Scene::create();138     auto SecondLayer = CActionTest::create();139     SecondLayer->setTag(muItem->getTag());140     sc->addChild(SecondLayer);141     auto reScene = TransitionSlideInB::create(1.0f, sc);142     Director::getInstance()->replaceScene(reScene);143 144     log("function:%s, line:%d", __FUNCTION__, __LINE__);145 }146 147 void HelloWorld::menuItemCallback_04(cocos2d::Ref* pSender)148 {149     MenuItem* muItem = (MenuItem*)pSender;150     auto sc = Scene::create();151     auto SecondLayer = CActionTest::create();152     SecondLayer->setTag(muItem->getTag());153     sc->addChild(SecondLayer);154     auto reScene = TransitionSlideInT::create(1.0f, sc);155     Director::getInstance()->replaceScene(reScene);156 157     log("function:%s, line:%d", __FUNCTION__, __LINE__);158 }159 160 void HelloWorld::menuItemCallback_05(cocos2d::Ref* pSender)161 {162     MenuItem* muItem = (MenuItem*)pSender;163     auto sc = Scene::create();164     auto SecondLayer = CActionTest::create();165     SecondLayer->setTag(muItem->getTag());166     sc->addChild(SecondLayer);167     auto reScene = TransitionPageTurn::create(1.0f, sc, true);168     Director::getInstance()->replaceScene(reScene);169 170     log("function:%s, line:%d", __FUNCTION__, __LINE__);171 }172 173 void HelloWorld::menuItemCallback_06(cocos2d::Ref* pSender)174 {175     MenuItem* muItem = (MenuItem*)pSender;176     auto sc = Scene::create();177     auto SecondLayer = CActionTest::create();178     SecondLayer->setTag(muItem->getTag());179     sc->addChild(SecondLayer);180     auto reScene = TransitionPageTurn::create(1.0f, sc, true);181     Director::getInstance()->replaceScene(reScene);182 183     log("function:%s, line:%d", __FUNCTION__, __LINE__);184 }
HelloWorldScene.cpp
技术分享
 1 #ifndef __ACTION_SCENE_H__ 2 #define __ACTION_SCENE_H__ 3 #include "cocos2d.h" 4 #include "HelloWorldScene.h" 5 class CActionTest : public cocos2d::Layer 6 { 7 public: 8     CActionTest(); 9     ~CActionTest();10 11     static cocos2d::Scene* createScene();12     CREATE_FUNC(CActionTest);13 14     /// 初始化层 调用15     virtual bool init();16     /// 进入层时调用17     virtual void onEnter();18     /// 进入层而且过渡动画结束时调用19     virtual void onEnterTransitionDidFinish();20     /// 退出层时 调用21     virtual void onExit();22     /// 退出层 而且开始过渡动画时调用23     virtual void onExitTransitionDidStart();24     /// 层对象被清除时调用25     virtual void cleanup();26 27     void menuItemCallback_back(cocos2d::Ref* pSender);28     void menuItemCallback_Action(cocos2d::Ref* pSender);29 30 protected:31     cocos2d::Sprite*   spPlane;   // 飞机 精灵32     bool               bShow; // 隐藏标识33 };34 35 #endif  // __ACTION_SCENE_H__
Action.h
技术分享
  1 #include "Action.h"  2   3 USING_NS_CC;  4   5 CActionTest::CActionTest()  6 {  7     spPlane = NULL;  8     bShow = TRUE;  9  10     log("function:%s, line:%d", __FUNCTION__, __LINE__); 11 } 12  13 CActionTest::~CActionTest() 14 { 15  16     log("function:%s, line:%d", __FUNCTION__, __LINE__); 17 } 18  19 Scene* CActionTest::createScene() 20 { 21     Scene* sc = Scene::create(); 22     auto myLayer = CActionTest::create(); 23     sc->addChild(myLayer); 24  25     return sc; 26 } 27  28  29 bool CActionTest::init() 30 { 31     if (!Layer::init()) 32     { 33         return false; 34     } 35  36     //// 层的初始化  37     Size sz = Director::getInstance()->getVisibleSize(); 38     Point origion = Director::getInstance()->getVisibleOrigin(); 39  40     Sprite* spBkground = Sprite::create("Demo1/Background480x800.png"); 41     spBkground->setPosition(Point(origion.x + sz.width / 2, origion.y + sz.height / 2)); 42     this->addChild(spBkground); 43  44     MenuItemImage* muBack = MenuItemImage::create("Demo1/Back-up.png", 45         "Demo1/Back-down.png", 46         CC_CALLBACK_1(CActionTest::menuItemCallback_back, this)); 47     muBack->setPosition(Point(origion.x+100, origion.y+sz.height-100)); 48  49     MenuItemImage* muGo = MenuItemImage::create("Demo1/Go-up.png", 50         "Demo1/Go-down.png", 51         CC_CALLBACK_1(CActionTest::menuItemCallback_Action, this)); 52     muGo->setPosition(Point(origion.x + 150, origion.y + 100)); 53  54     Menu* mu = Menu::create(muBack, muGo, NULL); 55     mu->setPosition(Point::ZERO); 56     this->addChild(mu); 57  58     spPlane = Sprite::create("Demo1/Plane.png"); 59     spPlane->setPosition(Point(origion.x + sz.width / 2, origion.y + sz.height / 2)); 60     this->addChild(spPlane, 1); 61  62     log("function:%s, line:%d", __FUNCTION__, __LINE__); 63     return true; 64 } 65  66 /// 进入层时调用 67 void CActionTest::onEnter() 68 { 69     Layer::onEnter(); 70  71     log("function:%s, line:%d", __FUNCTION__, __LINE__); 72 } 73  74 /// 进入层而且过渡动画结束时调用 75 void CActionTest::onEnterTransitionDidFinish() 76 { 77     Layer::onEnterTransitionDidFinish(); 78  79     log("function:%s, line:%d", __FUNCTION__, __LINE__); 80 } 81  82 /// 退出层时 调用 83 void CActionTest::onExit() 84 { 85     Layer::onExit(); 86  87     log("function:%s, line:%d", __FUNCTION__, __LINE__); 88 } 89  90 /// 退出层 而且开始过渡动画时调用 91 void CActionTest::onExitTransitionDidStart() 92 { 93     Layer::onExitTransitionDidStart(); 94  95     log("function:%s, line:%d", __FUNCTION__, __LINE__); 96 } 97  98 /// 层对象被清除时调用 99 void CActionTest::cleanup()100 {101     Layer::cleanup();102 103     log("function:%s, line:%d", __FUNCTION__, __LINE__);104 }105 106 void CActionTest::menuItemCallback_back(cocos2d::Ref* pSender)107 {108     auto sc = HelloWorld::createScene();109     auto reScene = TransitionShrinkGrow::create(1.0f, sc);110     Director::getInstance()->replaceScene(reScene);111 112     log("function:%s, line:%d", __FUNCTION__, __LINE__);113 }114 115 void CActionTest::menuItemCallback_Action(cocos2d::Ref* pSender)116 {117     log("function:%s, line:%d, Tag=%d", __FUNCTION__, __LINE__, this->getTag());118 119     Size sz = Director::getInstance()->getVisibleSize();120     Point pt = Point(CCRANDOM_0_1() * sz.width, CCRANDOM_0_1() * sz.height);121     ccBezierConfig  bezier;122 123     switch (this->getTag())124     {125     case PLACE_TAG:126         spPlane->runAction(Place::create(pt));127         log("PLACE_TAG,Position. x=%f, y=%f", pt.x, pt.y);128         break;129 130     case FLIPX_TAG:131         spPlane->runAction(FlipX::create(true));132         break;133 134     case FLIPY_TAG:135         spPlane->runAction(FlipY::create(true));136         break;137 138     case HIDE_SHOW_TAG:139         if (bShow)140         {141             spPlane->runAction(Hide::create());142             bShow = false;143         }144         else145         {146             spPlane->runAction(Show::create());147             bShow = true;148         }149         break;150 151     case TOGGLE_TAG:152         spPlane->runAction(ToggleVisibility::create());153         break;154 155     case OTHER_ACTION:156 //        spPlane->runAction(MoveTo::create(3.0f, Point(0, 0)));157 //        spPlane->runAction(MoveBy::create(1.0f, Point(200, 200)));158 //        spPlane->runAction(JumpTo::create(3.0f, Point(100, 300),100, 10));159 //        spPlane->runAction(JumpBy::create(3.0f, Point(100, 300), 400, 8));160         //bezier.controlPoint_1 = Point(100, sz.height);161         //bezier.controlPoint_2 = Point(100, -sz.height / 2);162         //bezier.endPosition = Point(300, 600);163         //spPlane->runAction(BezierTo::create(3.0f, bezier));164 165        // spPlane->runAction(ScaleTo::create(2.0f, 1.3));166 //        spPlane->runAction(ScaleBy::create(2.0f, 0.5));167 //         spPlane->runAction(RotateTo::create(3.0f, 181)); ///旋转角度超过180度,旋转方向会变168 //         spPlane->runAction(RotateTo::create(3.0f, 81)); ///旋转角度超过180度,旋转方向会变169         //        spPlane->runAction(RotateBy::create(3.0f, -100));170 //        spPlane->runAction(Blink::create(3.0f, 5));  // 闪烁171 //        spPlane->runAction(TintTo::create(2.0f, 255, 0, 0));172 //        spPlane->runAction(TintBy::create(2.0f, 255, 0, 0));  /// 这个 渲染,好像 颜色不正确173 //        spPlane->runAction(FadeTo::create(2.0f, 90));174         //spPlane->setOpacity(50);175         //spPlane->runAction(FadeIn::create(2.0f));176         spPlane->runAction(FadeOut::create(3.0f));177         break;178 179     default:180         break;181     }182 183     log("function:%s, line:%d", __FUNCTION__, __LINE__);184 }
Action.cpp

关键代码分析1:

1  auto sc = Scene::create();       /// 生成新场景 2  auto SecondLayer = CActionTest::create(); 3  SecondLayer->setTag(muItem->getTag());4  sc->addChild(SecondLayer);   ///将 CActionTest 层添加到 新场景5  auto reScene = TransitionSlideInR::create(1.0f, sc);  /// 生成 过渡场景(过渡动画)6  Director::getInstance()->replaceScene(reScene);  /// 场景替换

此处没有调用CAction::createScene()直接创建场景和层,而是采用上面的方法。主要是为了给场景传递参数。

 (当然,你重写一个 带参数的 createScene(int Tag) ,将参数传入,也是可行的)

 关键代码分析2:

/// 执行一个Place动作,Place动作是将精灵等Node对象移动到pt点。

 spPlane->runAction(Place::create(pt));

 

//// 执行一个 FlipX 动作,FlipX 动作是将精灵等Node对象 水平方向翻转

spPlane->runAction(FlipX::create(true));

 

 关键代码分析3:

Point pt = Point(CCRANDOM_0_1() * sz.width, CCRANDOM_0_1() * sz.height);

 CCRANDOM_0_1() 宏 可以产生 0~1 之间的随机数。

 

 间隔动作:

 间隔动作执行完成需要一定的时间,可以设置 duration 属性来设置动作的执行时间。间隔动作基类是 ActionInterval。间隔动作ActionInterval类图如下:

 技术分享

上面的源码示例中,有用到 间隔动作。

关键代码分析:

 1 //        spPlane->runAction(MoveTo::create(3.0f, Point(0, 0))); 2 //        spPlane->runAction(MoveBy::create(1.0f, Point(200, 200))); 3 //        spPlane->runAction(JumpTo::create(3.0f, Point(100, 300),100, 10)); 4 //        spPlane->runAction(JumpBy::create(3.0f, Point(100, 300), 400, 8)); 5         //bezier.controlPoint_1 = Point(100, sz.height); 6         //bezier.controlPoint_2 = Point(100, -sz.height / 2); 7         //bezier.endPosition = Point(300, 600); 8         //spPlane->runAction(BezierTo::create(3.0f, bezier)); 9 10        // spPlane->runAction(ScaleTo::create(2.0f, 1.3));11 //        spPlane->runAction(ScaleBy::create(2.0f, 0.5));12 //         spPlane->runAction(RotateTo::create(3.0f, 181)); ///旋转角度超过180度,旋转方向会变13 //         spPlane->runAction(RotateTo::create(3.0f, 81)); ///旋转角度超过180度,旋转方向会变14         //        spPlane->runAction(RotateBy::create(3.0f, -100));15 //        spPlane->runAction(Blink::create(3.0f, 5));  // 闪烁16 //        spPlane->runAction(TintTo::create(2.0f, 255, 0, 0));17 //        spPlane->runAction(TintBy::create(2.0f, 255, 0, 0));  /// 这个 渲染,好像 颜色不正确18 //        spPlane->runAction(FadeTo::create(2.0f, 90));19         //spPlane->setOpacity(50);20         //spPlane->runAction(FadeIn::create(2.0f));21         spPlane->runAction(FadeOut::create(3.0f));

间隔动作中很多类是 XxxTo 和 XxxBy 的命名。

XxxTo是指运动到指定的位置,这个位置是 绝对的。

XxxBy是指运动到相对于本身的位置,这个位置是相对的位置。

 

cocos2d-x实战 C++卷 学习笔记--第7章 动作、特效(一)