Cocos2d-x 3.0菜单教程:第二部分
来源:互联网 发布:php可以做直播吗 编辑:程序博客网 时间:2024/05/20 12:48
如果你还没有阅读过第一篇教程的话,那么我建议你在继续之前,回过头去完成第一部分教程再回来。
今天,我们将在上一篇教程之上添加一些东西,同时,我们会用到动画和layer之间的切换效果(transition)。
这里有本教程的完整源代码。
好了,正式出发吧!第一步,就是整理一下我们将要实现些什么东西。如果在编码之前,你不做任何的计划的话,那么你什么也做不成!下面是我们这篇教程将要实现的功能特性列表:
- 为credit场景和play场景添加一个新的层
- 当从一个场景切换到另一个场景的时候,做一些transition。
- 用文本构建菜单系统。
我保证接下来的内容很直白,而且很容易。
让我们先创建两个新类“PlayLayer”和“CreditLayer”--为什么要有Credit Layer?好吧,其实就是让别人知道这个游戏是你做的。我真的希望“PlayLayer”很清晰明了,其实就是我们游戏的GameScene或者MainScene,就是你实际玩游戏的场景。
因此,像之前添加“SceneManger”类一样,右键点击“Classes”分组,再选择“New Files”,选择IOS -> C and C++ -> C++ Class,如下所示:
同样的方法创建CreditLayer:
现在,我们有四个文件,但是里面啥也没有。。。别担心,我们马上会讲到如何添加里面的内容--首先是PlayLayer.h文件:
#include "cocos2d.h"#include "SceneManager.h"class PlayLayer : public cocos2d::Layer{public: PlayLayer(); ~PlayLayer(); bool init(); void back(Object* pSender); CREATE_FUNC(PlayLayer);};
现在是PlayerLayer.cpp文件:
#include "PlayLayer.h"USING_NS_CC;PlayLayer::PlayLayer(){}PlayLayer::~PlayLayer(){}bool PlayLayer::init(){ if(!Layer::init()) { return false; } Size visibleSize = Director::getInstance()->getVisibleSize(); MenuItemFont *back = MenuItemFont::create("back", CC_CALLBACK_1(PlayLayer::back, this)); Menu *menu = Menu::create(back, NULL); menu->setPosition(visibleSize.width/2, visibleSize.height/2); this->addChild(menu); return true;}void PlayLayer::back(Object* pSender){ SceneManager::goMenu();}
现在,CreditLayer和PlayLayer几乎差不多,除了名字不同以外。但是,为了教学的需要,我还是要展示出来--首先是CreditLayer.h文件:
#include "cocos2d.h"#include "SceneManager.h"class CreditLayer : public cocos2d::Layer{public: CreditLayer(); ~CreditLayer(); bool init(); void back(Object* pSender); CREATE_FUNC(CreditLayer);};
然后是CreditLayer.cpp文件:
#include "CreditLayer.h"USING_NS_CC;CreditLayer::CreditLayer(){}CreditLayer::~CreditLayer(){}bool CreditLayer::init(){ if(!Layer::init()) { return false; } Size visibleSize = Director::getInstance()->getVisibleSize(); MenuItemFont *back = MenuItemFont::create("back", CC_CALLBACK_1(CreditLayer::back, this)); Menu *menu = Menu::create(back, NULL); menu->setPosition(visibleSize.width/2, visibleSize.height/2); this->addChild(menu); return true;}void CreditLayer::back(Object* pSender){ SceneManager::goMenu();}
这些文件现在都只干一件事情----有一个“back”菜单按钮,当用户点击的时候,就通过SceneManager调转到MenuLayer。然后,如果你现在编译运行的话,也不会有任何问题,但是,你点back的时候,并不会跳转到任何场景去。。。我们马上就会来解决这个问题!
现在,我们回到SceneManager并作一些修改----添加两个方法“goPlay”和“goCredits”:
static void goPlay();static void goCredit();
同时,我们要向SceneManager.cpp里面添加两个方法的实现,它让我们能够跳转到PlayerLayer和CreditsLayer中去。
//添加头文件#include "PlayLayer.h"#include "CreditLayer.h"void SceneManager::goPlay(){ Layer *layer = PlayLayer::create(); SceneManager::go(layer);}void SceneManager::goCredit(){ Layer *layer = CreditLayer::create(); SceneManager::go(layer);}
因此,现在完整的SceneManager.cpp文件,看起来如下所示:
#include "SceneManager.h"#include "PlayLayer.h"#include "CreditLayer.h"USING_NS_CC;void SceneManager::goMenu(){ Layer *layer = MenuLayer::create(); SceneManager::go(layer);}void SceneManager::goPlay(){ Layer *layer = PlayLayer::create(); SceneManager::go(layer);}void SceneManager::goCredit(){ Layer *layer = CreditLayer::create(); SceneManager::go(layer);}void SceneManager::go(Layer* layer){ Director *director = Director::getInstance(); Scene *newScene = SceneManager::wrap(layer); if ( director->getRunningScene() ) { director->replaceScene(newScene); } else { director->runWithScene(newScene); }}Scene* SceneManager::wrap(Layer *layer){ Scene *newScene = Scene::create(); newScene->addChild(layer); return newScene;}
现在,我们只需要在MenuLayer中添加一些调用就可以了!
因为,我们创建了“onNewGame”和“onCredits”两个函数,在第一部分里,我们并没有在MenuLayer.h里添加任何方法声明。当然,不要忘了#include PlayLayer.h和CreditLayer.h两个头文件。
最后,我们需要在MenuLayer.cpp文件里使用SceneManager来实现“onNewGame”和“onCredits”两个方法:
void MenuLayer::onNewGame(Object* pSender){ SceneManager::goPlay();}void MenuLayer::onCredits(Object* pSender){ SceneManager::goCredit();}
哇!就这么多代码!现在编译并运行,你现在有一个菜单,可以从“Play”到“Menu”,以及“Credits”之间相互切换了。
但是,看起来有点生硬,不够生动---接下来,让我们做一些更有趣的事情吧---来玩一玩transitons怎么样?:)
那么,我们怎么做呢?我们可以让SceneManager来完成所有的工作。好,我们先在“go”方法里面使用CCFadeTransition来replaceScene,如下所示:
director->replaceScene(TransitionFade::create(1.2f, newScene, Color3B::WHITE));
从下载下来的cocos2d-x工程里的TestCpp测试代码中,找到TransitionsTest.h/.cpp,那里面有所有的transition的用法,后面我们用到的是从TransitionsTest切出来的一小部分。
为了从场景的字符串名字返回场景类,我们所要下面的宏定义和结构体:
#define STRINGIFY(x) #x#define TRANS(__className__) { \ [](float t, Scene* s){ return __className__::create(t,s);}, \ STRINGIFY(__className__), \}struct _transitions { std::function<TransitionScene*(float t, Scene* s)> function; const char * name;} transitions[] = { TRANS(PageTransitionForward), TRANS(PageTransitionBackward), TRANS(FadeWhiteTransition), TRANS(ZoomFlipXLeftOver), TRANS(FlipXRightOver), TRANS(FlipYUpOver)};
这个结构体保存从场景的字符串名字返回的场景类和该字符串。顺便定义了一个保存该结构体的数组transitions,存储了6个我们要用到的场景跳转效果。
整个SceneManager类看起来如下所示:
#define TRANSITION_DURATION (1.2f)class FadeWhiteTransition : public TransitionFade{public: static TransitionScene* create(float t, Scene* s) { return TransitionFade::create(t, s, Color3B::WHITE); }};class FlipXRightOver : public TransitionFlipX{public: static TransitionScene* create(float t, Scene* s) { return TransitionFlipX::create(t, s, TransitionScene::Orientation::RIGHT_OVER); }};class FlipYUpOver : public TransitionFlipY{public: static TransitionScene* create(float t, Scene* s) { return TransitionFlipY::create(t, s, TransitionScene::Orientation::UP_OVER); }};class ZoomFlipXLeftOver : public TransitionZoomFlipX{public: static TransitionScene* create(float t, Scene* s) { return TransitionZoomFlipX::create(t, s, TransitionScene::Orientation::LEFT_OVER); }};class PageTransitionForward : public TransitionPageTurn{public: static TransitionScene* create(float t, Scene* s) { Director::getInstance()->setDepthTest(true); return TransitionPageTurn::create(t, s, false); }};class PageTransitionBackward : public TransitionPageTurn{public: static TransitionScene* create(float t, Scene* s) { Director::getInstance()->setDepthTest(true); return TransitionPageTurn::create(t, s, true); }};#define STRINGIFY(x) #x#define TRANS(__className__) { \ [](float t, Scene* s){ return __className__::create(t,s);}, \ STRINGIFY(__className__), \}struct _transitions { std::function<TransitionScene*(float t, Scene* s)> function; const char * name;} transitions[] = { TRANS(PageTransitionForward), TRANS(PageTransitionBackward), TRANS(FadeWhiteTransition), TRANS(ZoomFlipXLeftOver), TRANS(FlipXRightOver), TRANS(FlipYUpOver)};#define MAX_LAYER (sizeof(transitions) / sizeof(transitions[0]))static int s_nSceneIdx = 0;TransitionScene* createTransition(int index, float t, Scene* s){ Director::getInstance()->setDepthTest(false); return transitions[index].function(t,s);}
因此,最后修改一下“go”函数,首先,我们下面的语句:
director->replaceScene(TransitionFade::create(1.2f, newScene, Color3B::WHITE));
替换成:
//director->replaceScene(TransitionFade::create(1.2f, newScene, Color3B::WHITE));s_nSceneIdx++;s_nSceneIdx = s_nSceneIdx % MAX_LAYER;Director::getInstance()->replaceScene( createTransition(s_nSceneIdx, TRANSITION_DURATION, newScene));
最终SceneManger的go函数看起来如下所示:
void SceneManager::go(Layer* layer){ Director *director = Director::getInstance(); Scene *newScene = SceneManager::wrap(layer); if ( director->getRunningScene() ) { //director->replaceScene(TransitionFade::create(1.2f, newScene, Color3B::WHITE)); s_nSceneIdx++; s_nSceneIdx = s_nSceneIdx % MAX_LAYER; Director::getInstance()->replaceScene( createTransition(s_nSceneIdx, TRANSITION_DURATION, newScene)); } else { director->runWithScene(newScene); }}
很酷,对吧?
好像这个教程还不够,我们还可以调加更多的效果。。。最后,我还想在菜单文本上面添加一些效果。为了实现这个,我们需要修改MenuLayer.cpp文件。
首先,我们先把titleLeft和titleRight Label从下面的代码:
titleLeft->setPosition( Point( (visibleSize.width - tileWidth)/2, titleCenterTop->getPosition().y - titleLeft->getContentSize().height - 40) );this->addChild(titleLeft);titleRight->setPosition( Point( (visibleSize.width - tileWidth)/2 + titleLeft->getContentSize().width + 50, titleCenterTop->getPosition().y - titleRight->getContentSize().height - 40) );this->addChild(titleRight);
改成下面的代码:
auto titleLeftPosBegin = Point((visibleSize.width - tileWidth)/2, titleCenterTop->getPosition().y - titleLeft->getContentSize().height - 40 - 400);auto titleLeftPosEnd = Point((visibleSize.width - tileWidth)/2, titleCenterTop->getPosition().y - titleLeft->getContentSize().height - 40 );auto titleRightPosBegin = Point( (visibleSize.width - tileWidth)/2 + titleLeft->getContentSize().width + 50, titleCenterTop->getPosition().y - titleRight->getContentSize().height - 40 + 400);auto titleRightPosEnd = Point( (visibleSize.width - tileWidth)/2+titleLeft->getContentSize().width + 50, titleCenterTop->getPosition().y - titleRight->getContentSize().height - 40);titleLeft->setPosition(titleLeftPos);this->addChild(titleLeft);titleRight->setPosition(titleRightPos);this->addChild(titleRight);
注意:原教程直接写的坐标数字,但是由于我改编时使用的分辨率跟原教程不同,所以之前的坐标没法用。于是我自己使用的相对坐标定位,这样造成代码有点长,于是在这里把需要的坐标特地用titleRightPosEnd,titleRightPosBegin等提取出来。这里由于title初始坐标改变了,依赖title初始坐标的菜单错位,如titleCenterBottom就应该变成依赖title的目的地坐标。titleCenterBottom的设置Position代码变为:
titleCenterBottom->setPosition( Point( (visibleSize.width - titleCenterBottom->getContentSize().width)/2, titleRightPosEnd.y - titleCenterBottom->getContentSize().height - 40) );
接着,在init函数开始时声明float delayTime = 0.3f,然后在菜单项设定Position之后的位置为菜单项添加一个动画:
Action *titleLeftAction = Sequence::create( DelayTime::create(delayTime), EaseBackOut::create(MoveTo::create(1.0, titleLeftPosEnd)), NULL);
oh!我的天,这在干嘛啊!
创建一个Action对象,它由于系列的事件组成。
这个事件序列首先等待0.3秒,然后移动到 titleLeftPosEnd 的位置,时间间隔为1秒,同时用EaseBackOut修饰了,所以是先快后慢。
一旦我们创建了这个动作序列之后,我们运行这个action。
titleLeft->runAction(titleLeftAction);
我们同时要为titleRight添加类似的行为。
最后的动画就是Menu本身:
for (Node *each : menu->getChildren()){ each->setScale(0.0f, 0.0f); Action *action = Sequence::create(DelayTime::create(delayTime), ScaleTo::create(0.5f, 1.0f), NULL); delayTime += 0.2f; each->runAction(action);}
你可以讲讲上面的代码是干嘛用的吗?我们又创建了一个“Action”变量,先停0.3秒,然后0.5秒缩放到1.0。因为我们开始之前把scale设置为0,这样就可以在0.5秒的时间内,慢慢放大到100%的尺寸。让我们运行一下代码,体验一下吧!
- Cocos2d-x 3.0菜单教程:第二部分
- Cocos2d-X菜单教程:第二部分
- Cocos2d-x 3.0菜单教程:第一部分
- (译)cocos2d菜单教程:第二部分
- Cocos2d-x 3.0菜单教程:第三部分·完
- Cocos2d-X菜单教程:第一部分
- Cocos2d-X菜单教程:第三部分
- Cocos2d-x 精灵教程:第二部分
- cocos2d-x 纹理深入研究 第二部分
- cocos2d-x 纹理深入研究 第二部分
- cocos2d-x 纹理深入研究 第二部分
- (译)cocos2d菜单教程:第一部分
- (译)cocos2d精灵教程:第二部分
- Cocos2d-X精灵教程:第一部分
- Cocos2d-x 精灵教程:第一部分
- Cocos2d-x 精灵教程:第三部分
- Cocos2d-x 2048游戏教程 第一部分
- Cocos2d-x开发教程 第二节 基本概念
- 网络分类
- Python基础编程(七)更加抽象
- [易飞]权限
- View Controller 生命周期总结
- linux进程函数大全
- Cocos2d-x 3.0菜单教程:第二部分
- android proguard
- EXCEL宏使用上的一点经验总结
- 黑马程序员------毕老师视频笔记第六天------面向对象(main函数)
- 数据结构之链表单向操作总结
- Cocos2d-x 3.0菜单教程:第三部分·完
- 安卓上传图片,playframework服务器接收保存
- HDU 2710 Max Factor
- Qt中设置快捷键