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

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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_NUM
16 }ActionTypes;
17 
18 class HelloWorld : public cocos2d::Layer
19 {
20 public:
21     // there‘s no ‘id‘ in cpp, so we recommend returning the class instance pointer
22     static cocos2d::Scene* createScene();
23 
24     // Here‘s a difference. Method ‘init‘ in cocos2d-x returns bool, instead of returning ‘id‘ in cocos2d-iphone
25     virtual bool init();  
26     
27     // a selector callback
28     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 manually
39     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 #endif
103 }
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         else
145         {
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章 动作特效的主要内容,如果未能解决你的问题,请参考以下文章

cocos2d-x实战 C++卷 学习笔记--第4章 使用菜单

cocos2d-x实战 C++卷 学习笔记--第5章 精灵

cocos2d-x实战 C++卷 学习笔记--第6章 场景与层

《Cocos2d-x实战:C++》学习笔记——基础概念

《Cocos2d-x实战:C++》学习笔记——基础概念

《Cocos2d-x游戏开发实战精解》学习笔记3--在Cocos2d-x中播放声音