【Cocos游戏实战】功夫小子第三课之过渡场景和開始菜单的实现
本节课的视频教程地址是:第三课在此
假设本教程有帮助到您,希望您能点击进去观看一下,并且如今注冊成为极客学院的会员,验证手机号码和邮箱号码会赠送三天的会员时间,手机端首次也能够领取五天的会员时间哦(即使是购买年会员眼下也不过年费260),成为极客学院学习会员能够无限制的下载和观看全部的学院站点的视频,谢谢您的支持!
经过前面两节课的学习。我们已经知道我们要做的是一个什么样的游戏项目。而且对游戏的基本特点和当中的重难点有了一个主要的认识,而且完毕了项目环境的基本搭建。以及项目基础类等工作。
从这节课開始我们就将进入到实际的逻辑功能和场景开发中来,我们将依照第一节课分析的流程和游戏实际的执行流程,将我们的整个游戏项目的全部功能和场景各个击破,并逐步连接成一个完整的游戏项目。
这节课我们要学习的内容有:
场景的UI图例如以下:
主開始菜单场景:
秘籍场景:
一、资源的异步载入和过渡场景的实现
这部分要学习的内容有三个方面:
- •资源打包
- •资源的异步载入
- •过渡场景的分析和实现
首先是资源的打包,这里我用的打包工具是TexturePacker,关于此工具的详细用法,我这里不再描写叙述,您能够查看下官方文档或者本视频教程(用法很easy),怎样获取和激活该工具请參考本人之前的TexturePacker博文。
其次是关于资源的异步载入方法,这里使用的是:
•资源的异步载入方法(TextureCache类)
voidTextureCache::addImageAsync(conststd::string &path, conststd::function<void(Texture2D*)>&callback)
这种方法的參数:
第一个是大图文件路径,第二个是一个回调函数。
以下是过渡场景的头文件代码:
/*! * \file SplashLayer.h * * \author SuooL_振生 * \date 五月 2015 * * 工作室Logo Splash界面 */ #ifndef __SplashScene__H__ #define __SplashScene__H__ #include "cocos2d.h" #include "SimpleAudioEngine.h" USING_NS_CC; class SplashLayer : public Layer { public: virtual bool init(); static Scene* createScene(); CREATE_FUNC(SplashLayer); private: Sprite* logoSprite; // 资源载入 void loadingTextureCallBack(Texture2D * texture); void loadingAudio(); // 场景切换 void nextScene(float dt); void onExit(); // 初始化用户数据 void initUserData(); int m_iNumOfLoad; std::thread* _loadingAudioThread; }; #endif
以下是实现的CPP文件代码:
/*! * \file SplashLayer.cpp * \date 2015/05/17 21:59 * * \author SuooL * Contact: hu1020935219@gmail.com * * \brief 过渡场景 * * TODO: long description * * \note */ #include "SimpleAudioEngine.h" #include "GlobalDefine.h" #include "SplashLayer.h" #include "StartLayer.h" USING_NS_CC; using namespace CocosDenshion; Scene* SplashLayer::createScene() { Scene* splashScene = Scene::create(); SplashLayer* layer = SplashLayer::create(); splashScene->addChild(layer); return splashScene; } bool SplashLayer::init() { if (!Layer::init()) { return false; } // 初始化logo精灵 logoSprite = Sprite::create("logo.png"); logoSprite->setPosition(WINSIZE.width/2, WINSIZE.height/2); this->addChild(logoSprite); // 首次执行初始化用户数据 if (!getBoolFromXML("_IS_EXISTED")) { initUserData(); setBoolToXML("_IS_EXISTED", true); UserDefault::getInstance()->flush(); } setFloatToXML(SOUNDVOL, 0.80f); setFloatToXML(MUSICVOL, 0.35f); UserDefault::getInstance()->flush(); m_iNumOfLoad = 0; // 图片和声音的异步载入 // 主界面 Director::getInstance()->getTextureCache()->addImageAsync("pnglist/startGame.png", CC_CALLBACK_1(SplashLayer::loadingTextureCallBack, this)); // 图籍 Director::getInstance()->getTextureCache()->addImageAsync("pnglist/gameLayer.png", CC_CALLBACK_1(SplashLayer::loadingTextureCallBack, this)); // 设置 Director::getInstance()->getTextureCache()->addImageAsync("pnglist/setLayer.png", CC_CALLBACK_1(SplashLayer::loadingTextureCallBack, this)); // 秘籍 Director::getInstance()->getTextureCache()->addImageAsync("pnglist/cheatsLayer.png", CC_CALLBACK_1(SplashLayer::loadingTextureCallBack, this)); // 选关 Director::getInstance()->getTextureCache()->addImageAsync("pnglist/gateMap.png", CC_CALLBACK_1(SplashLayer::loadingTextureCallBack, this)); // 暂停 Director::getInstance()->getTextureCache()->addImageAsync("pnglist/pauseLayer.png", CC_CALLBACK_1(SplashLayer::loadingTextureCallBack, this)); // 英雄 Director::getInstance()->getTextureCache()->addImageAsync("pnglist/hero.png", CC_CALLBACK_1(SplashLayer::loadingTextureCallBack, this)); Director::getInstance()->getTextureCache()->addImageAsync("pnglist/heroComobo.png", CC_CALLBACK_1(SplashLayer::loadingTextureCallBack, this)); Director::getInstance()->getTextureCache()->addImageAsync("pnglist/heroGun.png", CC_CALLBACK_1(SplashLayer::loadingTextureCallBack, this)); _loadingAudioThread = new std::thread(&SplashLayer::loadingAudio, this); return true; } void SplashLayer::loadingTextureCallBack(Texture2D * texture) { switch (m_iNumOfLoad++) { case 0: SpriteFrameCache::getInstance()->addSpriteFramesWithFile("pnglist/startGame.plist", texture); break; case 1: SpriteFrameCache::getInstance()->addSpriteFramesWithFile("pnglist/gameLayer.plist", texture); break; case 2: SpriteFrameCache::getInstance()->addSpriteFramesWithFile("pnglist/setLayer.plist", texture); break; case 3: SpriteFrameCache::getInstance()->addSpriteFramesWithFile("pnglist/cheatsLayer.plist", texture); break; case 4: SpriteFrameCache::getInstance()->addSpriteFramesWithFile("pnglist/gateMap.plist", texture); break; case 5: SpriteFrameCache::getInstance()->addSpriteFramesWithFile("pnglist/pauseLayer.plist", texture); break; case 6: SpriteFrameCache::getInstance()->addSpriteFramesWithFile("pnglist/hero.plist", texture); break; case 7: SpriteFrameCache::getInstance()->addSpriteFramesWithFile("pnglist/heroComobo.plist", texture); break; case 8: SpriteFrameCache::getInstance()->addSpriteFramesWithFile("pnglist/heroGun.plist", texture); this->schedule(schedule_selector(SplashLayer::nextScene), 1, 1, 1); break; default: break; } } void SplashLayer::loadingAudio() { log("loadAudio"); //初始化 音乐 SimpleAudioEngine::getInstance()->preloadBackgroundMusic("Sound/startBGM.mp3"); //初始化音效 SimpleAudioEngine::getInstance()->preloadEffect("Sound/button.wav"); } void SplashLayer::initUserData() { setIntToXML(GAMELEVEL_KEY, 1); // 初始化关卡 setIntToXML(HEROENERGY_KEY, 10); // 初始化体力 setIntToXML(HEROCOIN_KEY, 1000); // 初始化金币 setBoolToXML(SOUND_KEY, true); setBoolToXML(MUSIC_KEY, true); // 刷新 UserDefault::getInstance()->flush(); } void SplashLayer::nextScene(float dt) { Director::getInstance()->replaceScene(TransitionFade::create(2.0f, StartLayer::createScene())); } void SplashLayer::onExit() { Layer::onExit(); _loadingAudioThread->join(); CC_SAFE_DELETE(_loadingAudioThread); this->unschedule(schedule_selector(SplashLayer::nextScene)); }
从上面的代码中能够看出在图片资源的预载入中。显示载入纹理大图,然后调用回调函数载入相应的plist配置文件。而在最后一个纹理完毕载入之后。便会进行一个场景的切换的回调。
而声音资源的预载入则是通过多线程实现的。新开一个线程,并使用Cocos的
//初始化 音乐 SimpleAudioEngine::getInstance()->preloadBackgroundMusic("Sound/startBGM.mp3"); //初始化音效 SimpleAudioEngine::getInstance()->preloadEffect("Sound/button.wav");方法完毕声音资源的预载入,在场景退出的时候注意回收线程资源。
二、Menu家族的学习和菜单场景的实现
这一部分的主要内容也是三点:
•Menu家族及其成员构成
•Menu及各个成员的特点
•主開始菜单场景的分析和实现
以下是菜单Menu和菜单项MenuItem类图:
他们的关系就如名字一样,一个是容器Menu,一个是内容Item。
以下引用一段话:
Scene* StartLayer::createScene() { Scene* startScene = Scene::create(); StartLayer* layer = StartLayer::create(); startScene->addChild(layer); return startScene; } bool StartLayer::init() { if (!Layer::init()) { return false; } // 载入游戏图片资源缓存 SpriteFrameCache::getInstance()->addSpriteFramesWithFile("pnglist/galleryLayer.plist"); SpriteFrameCache::getInstance()->addSpriteFramesWithFile("pnglist/monster.plist"); SpriteFrameCache::getInstance()->addSpriteFramesWithFile("pnglist/resultLayer.plist"); SpriteFrameCache::getInstance()->addSpriteFramesWithFile("pnglist/mapBg.plist"); SpriteFrameCache::getInstance()->addSpriteFramesWithFile("pnglist/mapMid.plist"); // 依据音乐的开关来播放背景音乐 if (getBoolFromXML(MUSIC_KEY)) { float music = getFloatFromXML(MUSICVOL)*100.0f; aduioEngine->setBackgroundMusicVolume(getFloatFromXML(MUSICVOL)); if (SimpleAudioEngine::getInstance()->isBackgroundMusicPlaying()) { aduioEngine->pauseBackgroundMusic(); aduioEngine->playBackgroundMusic("Sound/startBGM.mp3", true); } else aduioEngine->playBackgroundMusic("Sound/startBGM.mp3", true); } else aduioEngine->pauseBackgroundMusic(); // 精灵初始化及位置设定 title = Sprite::createWithSpriteFrame(SpriteFrameCache::getInstance()->getSpriteFrameByName("Title.png")); title->setPosition(WINSIZE.width / 2 - 222, WINSIZE.height / 2 + 186); bgPic = Sprite::createWithSpriteFrame(SpriteFrameCache::getInstance()->getSpriteFrameByName("MainMenuBackground.png")); bgPic->setPosition(WINSIZE.width / 2, WINSIZE.height / 2); this->addChild(bgPic); this->addChild(title); // button初始化以及时间绑定 auto helpItem = MenuItemSprite::create( Sprite::createWithSpriteFrame(SpriteFrameCache::getInstance()->getSpriteFrameByName("HelpNormal.png")), Sprite::createWithSpriteFrame(SpriteFrameCache::getInstance()->getSpriteFrameByName("HelpSelected.png")), CC_CALLBACK_1(StartLayer::touchHelp, this)); // 帮助 auto tujiItem = MenuItemSprite::create( Sprite::createWithSpriteFrame(SpriteFrameCache::getInstance()->getSpriteFrameByName("PhotoGalleryNormal.png")), Sprite::createWithSpriteFrame(SpriteFrameCache::getInstance()->getSpriteFrameByName("PhotoGallerySelected.png")), CC_CALLBACK_1(StartLayer::touchLib, this)); // 图籍 auto setItem = MenuItemSprite::create( Sprite::createWithSpriteFrame(SpriteFrameCache::getInstance()->getSpriteFrameByName("SetNormal.png")), Sprite::createWithSpriteFrame(SpriteFrameCache::getInstance()->getSpriteFrameByName("SetSelected.png")), CC_CALLBACK_1(StartLayer::touchSet, this)); // 设置 auto mijiItem = MenuItemSprite::create( Sprite::createWithSpriteFrame(SpriteFrameCache::getInstance()->getSpriteFrameByName("CheatsNormal.png")), Sprite::createWithSpriteFrame(SpriteFrameCache::getInstance()->getSpriteFrameByName("CheatsSelected.png")), CC_CALLBACK_1(StartLayer::touchMiJi, this)); // 秘籍 auto chuangguanItem = MenuItemSprite::create( Sprite::createWithSpriteFrame(SpriteFrameCache::getInstance()->getSpriteFrameByName("EmigratedNormal.png")), Sprite::createWithSpriteFrame(SpriteFrameCache::getInstance()->getSpriteFrameByName("EmigratedSelected.png")), CC_CALLBACK_1(StartLayer::touchCG, this)); // 闯关 auto tiaozhanItem = MenuItemSprite::create( Sprite::createWithSpriteFrame(SpriteFrameCache::getInstance()->getSpriteFrameByName("ChallengeNormal.png")), Sprite::createWithSpriteFrame(SpriteFrameCache::getInstance()->getSpriteFrameByName("ChallengeSelected.png")), CC_CALLBACK_1(StartLayer::touchTZ, this)); // 挑战 tujiItem->setPosition(WINSIZE.width - 62, WINSIZE.height - 73); mijiItem->setPosition(WINSIZE.width - 62, WINSIZE.height - 209); setItem->setPosition(WINSIZE.width - 62, WINSIZE.height - 346); helpItem->setPosition(WINSIZE.width - 62, WINSIZE.height - 473); chuangguanItem->setPosition(WINSIZE.width / 2 - 240, WINSIZE.height / 2 - 86); tiaozhanItem->setPosition(WINSIZE.width / 2 - 240, WINSIZE.height / 2 - 250); auto menu = Menu::create(tujiItem,mijiItem, setItem, helpItem, chuangguanItem, tiaozhanItem, NULL); menu->setPosition(Point::ZERO); this->addChild(menu, 2); return true; } // button事件实现 void StartLayer::touchSet(Ref* pSender) { PLAYEFFECT; Director::getInstance()->replaceScene(SetLayer::createScene()); } void StartLayer::touchLib(Ref* pSender) { PLAYEFFECT; Director::getInstance()->replaceScene(TujiLayer::createScene()); } void StartLayer::touchMiJi(Ref* pSender) { PLAYEFFECT; Director::getInstance()->replaceScene(MijiLayer::createScene()); } void StartLayer::touchCG(Ref* pSender) { if (getBoolFromXML(SOUND_KEY)) { aduioEngine->setEffectsVolume(getFloatFromXML(SOUNDVOL)); aduioEngine->playEffect("Sound/button.mp3"); } Director::getInstance()->replaceScene(GateMapLayer::createScene()); } void StartLayer::touchTZ(Ref* pSender) { PLAYEFFECT; // Director::getInstance()->replaceScene(GateMapLayer::createScene()); } void StartLayer::touchHelp(Ref* pSender) { PLAYEFFECT; Director::getInstance()->replaceScene(HelpLayer::createScene()); }
三、秘籍场景的实现
秘籍场景是一个非常easy的场景。效果图如上所看到的。其基本的一个逻辑就是点击两边的切换选项,或切换显示不同的图片。非常easy。
这里我直接贴出关键代码:
Scene* MijiLayer::createScene() { Scene* scene = Scene::create(); MijiLayer* layer = MijiLayer::create(); scene->addChild(layer); return scene; } bool MijiLayer::init() { if (!Layer::init()) { return false; } flag = true; // 背景 spriteBG = Sprite::createWithSpriteFrame(SpriteFrameCache::getInstance()->getSpriteFrameByName("CheatsBackground.png")); spriteBG->setPosition(WINSIZE.width / 2, WINSIZE.height / 2); this->addChild(spriteBG); // 秘籍技能界面 interface_1 = Sprite::createWithSpriteFrame(SpriteFrameCache::getInstance()->getSpriteFrameByName("CheatsInterface1.png")); interface_2 = Sprite::createWithSpriteFrame(SpriteFrameCache::getInstance()->getSpriteFrameByName("CheatsInterface2.png")); interface_1->setPosition(WINSIZE.width / 2, WINSIZE.height / 2 - 10); interface_1->setVisible(true); interface_2->setPosition(WINSIZE.width / 2, WINSIZE.height / 2 - 10); interface_2->setVisible(false); spriteBG->addChild(interface_1); spriteBG->addChild(interface_2); // 关闭button auto closeItem = MenuItemSprite::create( Sprite::createWithSpriteFrame(SpriteFrameCache::getInstance()->getSpriteFrameByName("OffNormal.png")), Sprite::createWithSpriteFrame(SpriteFrameCache::getInstance()->getSpriteFrameByName("offSelected.png")), [](Ref * ref){ // 切换主界面场景 PLAYEFFECT; Director::getInstance()->replaceScene(StartLayer::createScene()); }); closeItem->setPosition(WINSIZE.width-164, WINSIZE.height-132); // 点击切换button auto nextRightItem = MenuItemSprite::create( Sprite::createWithSpriteFrame(SpriteFrameCache::getInstance()->getSpriteFrameByName("PageTurnNormal.png")), Sprite::createWithSpriteFrame(SpriteFrameCache::getInstance()->getSpriteFrameByName("PageTurnSelected.png")), [&](Ref * ref){ PLAYEFFECT; // 切换秘籍 if (flag) { interface_2->setVisible(true); flag = false; } else { interface_2->setVisible(false); flag = true; } }); nextRightItem->setPosition(WINSIZE.width - 55, WINSIZE.height / 2 - 14); // 点击切换button auto nor = Sprite::createWithSpriteFrame(SpriteFrameCache::getInstance()->getSpriteFrameByName("PageTurnNormal.png")); nor->setFlippedX(true); auto sel = Sprite::createWithSpriteFrame(SpriteFrameCache::getInstance()->getSpriteFrameByName("PageTurnSelected.png")); sel->setFlippedX(true); auto nextLeftItem = MenuItemSprite::create(nor, sel, [&](Ref * ref){ PLAYEFFECT; // 切换秘籍 if (flag) { interface_2->setVisible(true); flag = false; } else { interface_2->setVisible(false); flag = true; } }); nextLeftItem->setPosition(55, WINSIZE.height / 2 - 14); auto menu = Menu::create(closeItem, nextRightItem, nextLeftItem, NULL); menu->setPosition(Point::ZERO); spriteBG->addChild(menu); return true; }
这就是本节课的主要内容。主要就是一个资源的预载入学习和Menu家族组件的学习。
转载请注明出处,谢谢合作!
本节课的视频教程地址是:第三课在此
假设本教程有帮助到您,希望您能点击进去观看一下,并且如今注冊成为极客学院的会员。验证手机号码和邮箱号码会赠送三天的会员时间。手机端首次也能够领取五天的会员时间哦(即使是购买年会员眼下也不过年费260),成为极客学院学习会员能够无限制的下载和观看全部的学院站点的视频,谢谢您的支持!