本節課的視頻教程地址是:第三課在此
如果本教程有幫助到您,希望您能點擊進去觀看一下,而且現在註冊成爲極客學院的會員,驗證手機號碼和郵箱號碼會贈送三天的會員時間,手機端首次也可以領取五天的會員時間哦(即使是購買年會員目前也僅僅是年費260),成爲極客學院學習會員可以無限制的下載和觀看所有的學院網站的視頻,謝謝您的支持!
經過前面兩節課的學習,我們已經知道我們要做的是一個什麼樣的遊戲項目,並且對遊戲的基本特點和其中的重難點有了一個基本的認識,並且完成了項目環境的基本搭建,以及項目基礎類等工作。
從這節課開始我們就將進入到實際的邏輯功能和場景開發中來,我們將按照第一節課分析的流程和遊戲實際的運行流程,將我們的整個遊戲項目的所有功能和場景各個擊破,並逐步連接成一個完整的遊戲項目。
這節課我們要學習的內容有:
場景的UI圖如下:
主開始菜單場景:
祕籍場景:
一、資源的異步加載和過渡場景的實現
這部分要學習的內容有三個方面:
- •資源打包
- •資源的異步加載
- •過渡場景的分析和實現
首先是資源的打包,這裏我用的打包工具是TexturePacker,關於此工具的具體用法,我這裏不再描述,您可以查看下官方文檔或者本視頻教程(使用方法非常簡單),如何獲取和激活該工具請參考本人之前的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: [email protected]
*
* \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);
// 按鈕初始化以及時間綁定
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;
}
// 按鈕事件實現
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());
}
三、祕籍場景的實現
祕籍場景是一個很簡單的場景,效果圖如上所示,其主要的一個邏輯就是點擊兩邊的切換選項,或切換顯示不同的圖片。非常簡單。
這裏我直接貼出關鍵代碼:
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);
// 關閉按鈕
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);
// 點擊切換按鈕
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);
// 點擊切換按鈕
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),成爲極客學院學習會員可以無限制的下載和觀看所有的學院網站的視頻,謝謝您的支持!