距离上次写这个demo已经快俩个礼拜了,其实这段时间我也一直在做这个例子,为这个小例子加入UI,声音,对中文的支持用户数据的保存做移植做适配直到今天才把所有的东西都解决了,并且已经在我手机上跑了起来,自己也看到了效果。今天写完这篇博客,我的基础就差不多了,可以进一步学习了,真是高兴啊,没想到自己解决了这么多的问题!现在就把这几天的成果都展现出来吧。 1、我们首先引入对中文的支持,在我的前几篇博客中我有记录了整个过程,不明白的可以先点击上一段的链接,我们先来把我们将要用到的筛选器都建立好,如下图所示,大家对照着上一篇文章新增一些筛选器就可以了。

Cocos2d-x游戏实例之忍者飞镖

建立字符转化的头文件和cpp文件,然后写入以下的代码,代码的含义注释写的很清楚了,这里就不罗嗦了。

#ifndef _GBKTOUTF8_H_
#define _GBKTOUTF8_H_
#include "cocos2d.h"
//包含这个头文件,iconv库是一个字符集转换的开源的库,cocos2dx支持的编码是UTF-8,
//在win32下使用的编码是GB2312,所以要转化一下,才能显示中文
#if(CC_TARGET_PLATFORM == CC_PLATFORM_WIN32)
#include "iconv\iconv.h"
#else
#include "../../../../libiconv/include/iconv.h"
#endif
//#include "../../../../libiconv/include/iconv.h"

//记住附加依赖项libiconv.lib或者使用以下的代码
//#pragma comment(lib, "libiconv.lib")

//就是一个函数没有分装成类
int GBKToUTF8(std::string & gbkStr, const char* toCode, const char* fromCode);

#endif
#include "GBKToUTF8.h"

//以下函数是从网上copy的,试了一下可以解决问题
int GBKToUTF8(std::string & gbkStr, const char* fromCode, const char* toCode)
{
	iconv_t iconvH;
	//这个函数调用的作用是将formCode的编码转换成toCode的编码,我们一般调用的时候是GB2312 UTF-8
	//因为系统又的编码支持有的不支持所以就有可能返回0
	iconvH = iconv_open(toCode,fromCode);

	//如果返回值为0代表不可以转化
	if (iconvH == 0)
	{
		return -1;
	}

	//将string类型转化为char *类型
	const char* strChar = gbkStr.c_str();
	//以下是基础不说了
	const char** pin = &strChar;
	size_t strLength = gbkStr.length();
	char* outbuf = (char*) malloc(strLength*4);
	char* pBuff = outbuf;

	//这里GB2312和UTF-8的位数是1:4不明白,知道的人说一下
	memset(outbuf, 0, strLength*4);
	size_t outLength = strLength*4;

	//第二个参数表示转化前字符的地址,以后的参数分别是转化前字符的长度,转化后的存储地址,转化后的长度
	if (-1 == iconv(iconvH, pin, &strLength, &outbuf, &outLength))
	{
		free(pBuff);
		iconv_close(iconvH);
		return -1;
	}

	gbkStr = pBuff;
	iconv_close(iconvH);

	return 0;
}

接着我们建立三个游戏场景,分别为游戏的开始界面场景,游戏的设置界面场景,和关于我们的场景。先来完成开始界面的编写。 Cocos2d-x游戏实例之忍者飞镖

#ifndef _START_GAME_SCENE_H_
#define _START_GAME_SCENE_H_
#include "cocos2d.h"

using namespace cocos2d;

//这几个场景类都是继承自CCLayer,和原来的例子HelloWorld的写法差不多,大家仿照原来的搭建基本的代码就行
class StartGameScene : public CCLayer
{
public:
	static CCScene * scene();
	bool init();
	CREATE_FUNC(StartGameScene);
private:
	//考虑到这些方法都是在本类中自己调用,所以写成私有的
	//这是开始游戏菜单触发的事件代码
	void startMenu(CCObject * object);
	//这个是游戏设置菜单触发事件的代码
	void setMenu(CCObject * object);
	//这个是关于我们游戏菜单的触发事件的代码
	void aboutMenu(CCObject * object);
	//这个函数的作用是在开始游戏的这个场景上添加上述的一些菜单
	void addMenu();
};
#endif
#include "StartGameScene.h"
#include "GBKToUTF8.h" //字符的支持
#include "GameMainLayer.h" //游戏主场景
#include "SetMenuScene.h" //设置游戏场景
#include "AboutUs.h" //关于我们场景

CCScene * StartGameScene::scene()
{
	CCScene * scene = NULL;
	do
	{
		scene = CCScene::create();
		CC_BREAK_IF(!scene);

		StartGameScene * layer = StartGameScene::create();
		CC_BREAK_IF(!layer);

		scene->addChild(layer);
	}
	while(0);

	return scene;
}

bool StartGameScene::init()
{
	bool bRet = false;

	do
	{
		CC_BREAK_IF(!CCLayer::init());

		CCSize size = CCDirector::sharedDirector()->getWinSize();

		//添加背景图片
		CCSprite * backgroundSprite = CCSprite::create("StartGame.png");
		backgroundSprite->setPosition(ccp(size.width/2,size.height/2));
		this->addChild(backgroundSprite);

		//添加显示在该场景上的一些菜单项
		this->addMenu();

		bRet = true;
	}
	while(0);

	return bRet;
}

void StartGameScene::startMenu(CCObject * object)
{
	//菜单响应处理事件的实现,改变场景,我们使用的是replaceScene的方法,这个时候会释放掉当前的场景
	//考虑到用户从游戏主界面中返回到这个场景可能需要很长的时间,当然要释放掉这个场景了,免得占用资源
	CCDirector::sharedDirector()->replaceScene(GameMainLayer::scene());
}

void StartGameScene::setMenu(CCObject * object)
{
	//使用push将当前的场景入桟,以便继续运行原来的场景,用户设置完一些选项会回到这里,所以就不要先释放这个资源了
	CCDirector::sharedDirector()->pushScene(SetMenuScene::scene());
}

void StartGameScene::aboutMenu(CCObject * object)
{
	//和上边的setMenu类似,它们都会通过popScene()的方式回到这个游戏开始的场景的
	CCDirector::sharedDirector()->pushScene(AboutUs::scene());
}

//添加显示在该场景上的一些菜单项
void StartGameScene::addMenu()
{
	//设置菜单中显示的字符,并转换编码格式
	std::string  startString = "开始游戏";
	GBKToUTF8(startString,"GB2312","UTF-8");
	std::string  setString = "游戏设置";
	GBKToUTF8(setString,"GB2312","UTF-8");
	std::string aboutString = "关于我们";
	GBKToUTF8(aboutString,"GB2312","UTF-8");

	//设置菜单项
	CCMenuItemFont * item1 = CCMenuItemFont::create(startString.c_str(),this,
		menu_selector(StartGameScene::startMenu));
	CCMenuItemFont * item2 = CCMenuItemFont::create(setString.c_str(),this,
		menu_selector(StartGameScene::setMenu));
	CCMenuItemFont * item3 = CCMenuItemFont::create(aboutString.c_str(),this,
		menu_selector(StartGameScene::aboutMenu));

	CCMenu * mainMenu = CCMenu::create(item1,item2,item3,NULL);
	//设置菜单项的竖直对齐方式,间隔25
	mainMenu->alignItemsVerticallyWithPadding(25);
	//添加到场景中
	this->addChild(mainMenu);
}

Cocos2d-x游戏实例之忍者飞镖接着我们完成游戏设置场景的实现。在设置界面我们这里主要是设置游戏的声音和音效,就是开和关,而音量的话手机上自己有音量键可以调节,所以我们需要先写个声音处理类出来。 Cocos2d-x游戏实例之忍者飞镖

//声音预先处理类的头文件
#ifndef _AUDIO_PRETREAT_H
#define _AUDIO_PRETREAT_H
#include "cocos2d.h"
//使用声音引擎必须包含SimpleAudioEngeim.h头文件
#include "SimpleAudioEngine.h"

using namespace cocos2d;
//声音引擎的命名空间
using namespace CocosDenshion;

//类AudioPretrea采用单例设计模式

//把用到的音乐做为枚举类型,这里用到的比较少,但是当我们用到很多的声音和音效的时候这样做就比较好了
enum MUSIC_TYPE
{
	MUSIC_TYPE_BACKGROUND //背景音乐
};

//把用到的音乐做为枚举类型
enum EFFECT_TYPE
{
	EFFECT_TYPE_EFFECT1
};

class AudioPretreat
{
private:
	static AudioPretreat * m_audioPretreat;
	//将构造函数私有,这样的话就不能new了,才叫单例
	AudioPretreat(){};
	//可以根据不同的平台获取不同的声音文件
	char * getMusic(MUSIC_TYPE type);
	char * getEffect(EFFECT_TYPE type);
public:
	//单例设计的时候需要用到的俩个函数
	static AudioPretreat * sharedAudioPretreat();
	static void freeAudioPretreat();
	//在init中完成声音的预先加载
	bool init();
	//播放声音和背景音乐的方法
	void playEffect();
	void playBackgroundMusic();
};

#endif
//声音预先处理类的实现
#include "AudioPretreat.h"
#include "UserData.h"

//单例设计模式采用的惯用方式
AudioPretreat * AudioPretreat::m_audioPretreat = NULL;

AudioPretreat * AudioPretreat::sharedAudioPretreat()
{
	if(NULL == m_audioPretreat)
	{
		m_audioPretreat = new AudioPretreat();
	}
	return m_audioPretreat;
}

//在AppDelegate析构的时候调用这个函数,初始化的时候是在
//AppDelegate::applicationDidFinishLaunching()这个函数中,引擎跑起来的时候我们就加载我们的声音文件
void AudioPretreat::freeAudioPretreat()
{
	if(m_audioPretreat)
	{
		delete m_audioPretreat;
		m_audioPretreat = NULL;
	}
}

//根据不同的平台获得不同的声音文件
char * AudioPretreat::getMusic(MUSIC_TYPE type)
{
	switch(type)
	{
	case MUSIC_TYPE_BACKGROUND:
		//WIN32,ANDROID,IOS都使用MP3格式的背景音乐
#if(CC_TARGET_PLATFORM == CC_PLATFORM_WIN32)
	return "sound/background-music.mp3";
#else(CC_TARGET_PLATFORM == CC_PLATFORM_ANDROID)
	return "sound/background-music.mp3";
#endif
	break;
	}
	return NULL;
}

//根据不同的平台获得不同的音效文件
char * AudioPretreat::getEffect(EFFECT_TYPE type)
{
	switch(type)
	{
	case EFFECT_TYPE_EFFECT1:
		//win32下使用的是.wav格式的文件,android下是.ogg的文件
#if(CC_TARGET_PLATFORM == CC_PLATFORM_WIN32)
		return "sound/pew-pew-lei.wav";
#else(CC_TARGET_PLATFORM == CC_PLATFORM_ANDROID)
		return "sound/pew-pew-lei.ogg";
#endif
	}
	return NULL;
}

//init函数中完成一些初始化的操作
bool AudioPretreat::init()
{
	bool bRet = false;
	do
	{
		//预先加载声音,参数是声音文件
		SimpleAudioEngine::sharedEngine()->preloadBackgroundMusic(this->getMusic(MUSIC_TYPE_BACKGROUND));
		//加载音效
		SimpleAudioEngine::sharedEngine()->preloadEffect(this->getEffect(EFFECT_TYPE_EFFECT1));
		//设置声音的大小0.0-1.0,已经多次说过,在win32下这个函数没有作用,只能移植到android平台的时候
		//用了,本人移植android平台测试的时候背景音乐很小,因为移植的时候传入的参数是0.1,调大声音效果也不好
		//估计是声音文件的音质不太好吧
		SimpleAudioEngine::sharedEngine()->setBackgroundMusicVolume(0.5f);

		//这个是从XML文件中获得声音是否播放的bool值,以便确定初始化的时候是否要播放声音
		//之所以不判断音效就是因为背景音乐是整个游戏过程都是可以播放的,而音效就不同了
		if(UserData::sharedUserData()->getMusicValue())
		{
			//播放声音,第二个参数为true,代表循环播放
			SimpleAudioEngine::sharedEngine()->playBackgroundMusic(this->getMusic(MUSIC_TYPE_BACKGROUND),true);
		}

		bRet = true;
	}
	while(0);

	return bRet;
}

//播放音效
void AudioPretreat::playEffect()
{
	SimpleAudioEngine::sharedEngine()->playEffect(this->getEffect(EFFECT_TYPE_EFFECT1));
}

//播放背景音乐
void AudioPretreat::playBackgroundMusic()
{
	//判断背景音乐是否在播放
	if(!SimpleAudioEngine::sharedEngine()->isBackgroundMusicPlaying())
	{
		//播放声音,第二个参数为true,代表循环播放
		SimpleAudioEngine::sharedEngine()->playBackgroundMusic(this->getMusic(MUSIC_TYPE_BACKGROUND),true);
	}
	else
	{
		SimpleAudioEngine::sharedEngine()->resumeBackgroundMusic();
	}
}

上边用到一个UserData类,现在我们就来写这个类。这个类是用来保存用户的游戏数据的。比如声音设置的开和关,玩家的最高得分。 Cocos2d-x游戏实例之忍者飞镖

/*
保存用户游戏数据的头文件
*/
#ifndef _USER_DATA_H_
#define _USER_DATA_H_
#include "cocos2d.h"

using namespace cocos2d;

//这个类同样使用单例设计模式

class UserData
{
public:
	//以下的set和get方法都是用来设置和获取游戏数据的
	//获取是否播放背景音乐
	bool getMusicValue();
	void setMusicValue(bool b);
	//是否播放音效
	bool getEffectValue();
	void setEffectValue(bool b);
	//用户游戏的最高得分
	int getHighScore();
	void setHighScore(int score);
	//单例的写法,初始化的时候在bool AppDelegate::applicationDidFinishLaunching()中
	static UserData * sharedUserData();
	//在Appdelegate的析构函数中调用,用来释放m_userData数据成员
	static void freeUserData();
private:
	//保存是否播放背景音乐的成员变量
	bool m_musicValue;
	//是否播放音效的成员变量
	bool m_effectValue;
	//保存玩家的最高分
	int m_highScore;
	static UserData * m_userData;
	//在构造函数中来进行一些初始化的操作
	UserData();
};

#endif
/*
保存用户游戏数据的类的具体实现
*/
#include "UserData.h"

//以下为单例设计模式的惯用写法,所有的单例设计模式都类似,大家照着写就行了
UserData * UserData::m_userData = NULL;

UserData * UserData::sharedUserData()
{
	if(m_userData == NULL)
	{
		m_userData = new UserData();
	}

	return m_userData;
}

void UserData::freeUserData()
{
	if(m_userData)
	{
		delete m_userData;
		m_userData = NULL;
	}
}

//在UserData的构造函数中为游戏数据初始化
UserData::UserData()
{

	//不要调用CCUserDefault::sharedUserDefault()->isXMLFileExist()来判断是否存在XML文件,因为当我们调用sharedUserDefalut()的时候
	//系统就会为我们初始化xml文件的,所以如果这么调用的话文件就永远存在了。而使用CCUserDefault::isXMLFileExit()仍然解决不
   //了问题,这个时候无论什么时候启动程序isXMLFileExist()都返回的是假,也就是文件永远不存在了,经过我的调试认为这俩个函数都不能解决问题
	//如果你有其他的发现请留言。这里我采用以下的方法进行处理,直接调用getBoolForKey函数,第二个参数是说如果isExit不存在,则返回的是false
	//这样的话,用户第一次玩游戏的时候返回的是false,在if中会进行一些数据的初始化,并且保持在XML文件中,第二次调用的时候就会执行else了
	//也就是从XML文件中取用户的游戏数据了
	if(!(m_musicValue = CCUserDefault::sharedUserDefault()->getBoolForKey("isExit",false)))
	{
		CCUserDefault::sharedUserDefault()->setBoolForKey("isExit",true);
		//初始化游戏数据,并且保存在XML文件中
		m_musicValue = true;
		CCUserDefault::sharedUserDefault()->setBoolForKey("m_musicValue",m_musicValue);
		this->m_effectValue = true;
		CCUserDefault::sharedUserDefault()->setBoolForKey("m_effectValue",m_effectValue);
		this->m_highScore = 0;
		CCUserDefault::sharedUserDefault()->setIntegerForKey("m_highScore",m_highScore);
	}
	else
	{
		m_musicValue = CCUserDefault::sharedUserDefault()->getBoolForKey("m_musicValue");
		m_effectValue = CCUserDefault::sharedUserDefault()->getBoolForKey("m_effectValue");
		m_highScore = CCUserDefault::sharedUserDefault()->getIntegerForKey("m_highScore");
	}
}

//返回用户的数据
bool UserData::getMusicValue()
{
	return this->m_musicValue;
}
bool UserData::getEffectValue()
{
	return this->m_effectValue;
}
int UserData::getHighScore()
{
	return this->m_highScore;
}

//设置用户的声音数据,并且保存在文件中,最后使用flush来刷新进XML文件中
void UserData::setMusicValue(bool b)
{
	this->m_musicValue = b;
	CCUserDefault::sharedUserDefault()->setBoolForKey("m_musicValue",this->m_musicValue);
	//在win32上这个函数的实现是空的
	CCUserDefault::sharedUserDefault()->flush();
}
void UserData::setEffectValue(bool b)
{
	this->m_effectValue = b;
	CCUserDefault::sharedUserDefault()->setBoolForKey("m_effectValue",this->m_effectValue);
	CCUserDefault::sharedUserDefault()->flush();
}
void UserData::setHighScore(int score)
{
	this->m_highScore = score;
	CCUserDefault::sharedUserDefault()->setIntegerForKey("m_highScore",this->m_highScore);
	CCUserDefault::sharedUserDefault()->flush();
}

有了上面的内容下面我们就来完成游戏设置场景的编写。

/*游戏设置场景的头文件*/
#ifndef _SET_MENU_SCENE_H_
#define _SET_MENU_SCENE_H_
#include "cocos2d.h"
//导入支持控件的扩展库
#include "cocos-ext.h"

//使用扩展库的命名空间
using namespace cocos2d::extension;
using namespace cocos2d;

class SetMenuScene : public CCLayer
{
public:
	static CCScene * scene();
	bool init();
	CREATE_FUNC(SetMenuScene);
private:
	//返回键的处理函数
	void goBack(CCObject * object);
	//添加背景音乐的控制按钮和事件处理函数
	void setBgMusic(CCObject * object,CCControlEvent controlEvent);
	void addBgButton();
	//添加音效的控制按钮和事件处理函数
	void setEtMusic(CCObject * object,CCControlEvent controlEvent);
	void addEtButton();
};
#endif
/*游戏设置场景的具体实现*/
#include "SetMenuScene.h"
#include "UserData.h" //保存用户数据的头文件
#include "GBKToUTF8.h" //字符编码转换
//支持声音的俩个头文件
#include "SimpleAudioEngine.h"
#include "AudioPretreat.h"

using namespace CocosDenshion;

CCScene * SetMenuScene::scene()
{
	CCScene * scene = NULL;
	do
	{
		scene = CCScene::create();
		SetMenuScene * layer = SetMenuScene::create();
		scene->addChild(layer);
	}
	while(0);

	return scene;
}

bool SetMenuScene::init()
{
	bool bRet = false;
	do
	{
		CC_BREAK_IF(!CCLayer::init());

		CCSize size = CCDirector::sharedDirector()->getVisibleSize();

		//添加背景图片
		CCSprite * background = CCSprite::create("setbackground.png");
		background->setPosition(ccp(size.width/2,size.height/2));
		this->addChild(background);

		//添加返回键
		CCMenuItemImage * goBack = CCMenuItemImage::create("b1.png","b1.png",
			this,menu_selector(SetMenuScene::goBack));
		CCMenu * menu = CCMenu::create(goBack,NULL);
		menu->setPosition(ccp(size.width*4/5,size.height*1/5));
		this->addChild(menu);

		//添加控制背景音乐的按钮
		this->addBgButton();
		//添加控制音效的按钮
		this->addEtButton();

		//添加最高分
		CCString * highscore = CCString::createWithFormat("high score:%d",
			UserData::sharedUserData()->getHighScore());
		//创建文本用来显示最高分
		CCLabelBMFont * scoreLabel = CCLabelBMFont::create(highscore->getCString(),
			"bitmapFontChinese.fnt");
		scoreLabel->setPosition(ccp(size.width/2,size.height*4/7));
		this->addChild(scoreLabel);

		bRet = true;
	}
	while(0);

	return bRet;
}

//返回键的事件响应处理函数
void SetMenuScene::goBack(CCObject * object)
{
	//将游戏开始场景出栈
	CCDirector::sharedDirector()->popScene();
}

//添加背景音乐的控制按钮
void SetMenuScene::addBgButton()
{
	CCSize size = CCDirector::sharedDirector()->getVisibleSize();

	//添加控制背景音乐的按钮
	CCControlSwitch * setBgMusic = CCControlSwitch::create(
		CCSprite::create("switch-mask.png"),
		CCSprite::create("switch-on.png"),
		CCSprite::create("switch-off.png"),
		CCSprite::create("switch-thumb.png"),
		CCLabelTTF::create("on","",24),
		CCLabelTTF::create("off","",24));

	//为按钮添加事件处理函数
	setBgMusic->addTargetWithActionForControlEvents(this,cccontrol_selector(SetMenuScene::setBgMusic),
		CCControlEventValueChanged);

	//设置控制背景音乐的按钮的一些属性
	setBgMusic->setPosition(ccp(size.width*2/3,size.height/3));
	//设置背景音乐是否开启,需要从用户的数据文件中取得
	setBgMusic->setOn(UserData::sharedUserData()->getMusicValue());
	this->addChild(setBgMusic);

	//在背景音乐按钮之上添加文本
	std::string bgMStr = "背景音乐";
	GBKToUTF8(bgMStr,"GB2312","UTF-8");
	CCLabelTTF * bgMusic = CCLabelTTF::create(bgMStr.c_str(),"",20);
	bgMusic->setColor(ccc3(200,200,200));
	bgMusic->setPosition(ccp(size.width*2/3,size.height*3/7));
	this->addChild(bgMusic,1);
}

//背景音乐菜单处理函数,当进去游戏的设置场景时,这个函数就会被调用的,改变按钮的值同样被调用
void SetMenuScene::setBgMusic(CCObject * object,CCControlEvent controlEvent)
{
	CCControlSwitch * setBgMusic = (CCControlSwitch *)object;
	if(setBgMusic->isOn())
	{
		//如果按钮是开启状态则播放声音
		AudioPretreat::sharedAudioPretreat()->playBackgroundMusic();
		//并且保存用户的设置数据
		UserData::sharedUserData()->setMusicValue(true);
	}
	else
	{
		SimpleAudioEngine::sharedEngine()->stopBackgroundMusic();
		UserData::sharedUserData()->setMusicValue(false);
	}
}

//添加音效控制按钮
void SetMenuScene::addEtButton()
{
	CCSize size = CCDirector::sharedDirector()->getVisibleSize();

	//添加控制音效的按钮
	CCControlSwitch * setEtMusic = CCControlSwitch::create(
		CCSprite::create("switch-mask.png"),
		CCSprite::create("switch-on.png"),
		CCSprite::create("switch-off.png"),
		CCSprite::create("switch-thumb2.png"),
		CCLabelTTF::create("on","",24),
		CCLabelTTF::create("off","",24));

	//为按钮添加事件处理函数
	setEtMusic->addTargetWithActionForControlEvents(this,cccontrol_selector(SetMenuScene::setEtMusic),
		CCControlEventValueChanged);

	//设置控制音效的按钮的一些属性
	setEtMusic->setPosition(ccp(size.width*1/3,size.height/3));
	setEtMusic->setOn(UserData::sharedUserData()->getEffectValue());
	this->addChild(setEtMusic);

	//在背景音乐按钮之上添加文本
	std::string etMStr = "音效";
	GBKToUTF8(etMStr,"GB2312","UTF-8");
	CCLabelTTF * etMusic = CCLabelTTF::create(etMStr.c_str(),"",20);
	etMusic->setColor(ccc3(200,200,200));
	etMusic->setPosition(ccp(size.width*1/3,size.height*3/7));
	this->addChild(etMusic,1);
}

//音效控制按钮的事件响应函数
void SetMenuScene::setEtMusic(CCObject * object,CCControlEvent controlEvent)
{
	CCControlSwitch * setEtMusic = (CCControlSwitch *)object;
	if(setEtMusic->isOn())
	{
		UserData::sharedUserData()->setEffectValue(true);
	}
	else
	{
		UserData::sharedUserData()->setEffectValue(false);
	}
}

Cocos2d-x游戏实例之忍者飞镖接着再来看一个简单的场景的编写,就是关于我们的场景。

/*关于我们游戏场景的头文件*/
#ifndef _ABOUT_US_H_
#define _ABOUT_US_H_
#include "cocos2d.h"

using namespace cocos2d;

class AboutUs : public CCLayer
{
public:
	static CCScene * scene();
	bool init();
	CREATE_FUNC(AboutUs);
	//添加返回按钮的事件处理函数
	void back(CCObject * object);
};

#endif
/*关于我们游戏场景的具体实现*/
#include "AboutUs.h"
#include "GBKToUTF8.h"

CCScene * AboutUs::scene()
{
	CCScene * scene = NULL;
	do
	{
		scene = CCScene::create();
		AboutUs * layer = AboutUs::create();
		scene->addChild(layer);
	}
	while(0);

	return scene;
}

bool AboutUs::init()
{
	bool bRet = false;
	do
	{
		CCSize size = CCDirector::sharedDirector()->getWinSize();

		//添加背景
		CCSprite * sprite = CCSprite::create("setbackground.png");
		sprite->setPosition(ccp(size.width/2,size.height/2));
		this->addChild(sprite);

		//添加一些文本信息
		//先转换一下字符的编码
		std::string str = "欢迎大家访问www.zaojiahua.com皂荚花";
		GBKToUTF8(str,"GB2312","UTF-8");
		CCLabelTTF * label = CCLabelTTF::create(str.c_str(),"Paint Boy.ttf",18);
		label->setPosition(ccp(size.width/2,size.height/2));
		this->addChild(label);

		std::string str2 = "代码:小塔";
		GBKToUTF8(str2,"GB2312","UTF-8");
		CCLabelTTF * label2 = CCLabelTTF::create(str2.c_str(),"Paint Boy.ttf",24);
		label2->setPosition(ccp(size.width/2,size.height*2/3));
		this->addChild(label2);

		CCLabelBMFont * label3 = CCLabelBMFont::create("QQ:2933682586","bitmapFontChinese.fnt");
		label3->setPosition(ccp(size.width/2,size.height/3));
		this->addChild(label3);

		//添加一个返回键
		CCMenuItemImage * back = CCMenuItemImage::create("b1.png","b1.png",
			this,menu_selector(AboutUs::back));
		back->setPosition(ccp(size.width*5/6,size.height/6));
		CCMenu * menu = CCMenu::create(back,NULL);
		menu->setPosition(CCPointZero);
		this->addChild(menu);

		bRet = true;
	}
	while(0);

	return bRet;
}

void AboutUs::back(CCObject * object)
{
	//将游戏开始场景出栈
	CCDirector::sharedDirector()->popScene();
}

Cocos2d-x游戏实例之忍者飞镖 在玩家玩游戏的时候一定希望看到自己的分数,每消灭一个怪物就得一分,所以我们需要在游戏的主场景中加入一个显示分数和返回到游戏主菜单的UI,下面我们就来实现这个类。

/*游戏主场景的UI界面*/
#ifndef _UI_LAYER_H_
#define _UI_LAYER_H_
#include "cocos2d.h"

using namespace cocos2d;

//UILayer采用单例设计模式

class UILayer : public CCLayer
{
public:
	//设置和获取玩家的当前分数
	int getScore(){return m_score;};
	void setScore(int score){m_score = score;};
	bool init();
	//scheduleUpdate()
	void update(float tm);
	//UI的初始化放到游戏主场景的init函数中
	static UILayer * sharedUILayer();
	//释放放到主场景的析构函数中
	static void freeUILayer();
	//返回游戏主菜单的事件处理函数
	void backMainMenu(CCObject * object);
private:
	//将玩家的分数作为私有成员变量
	int m_score;
	static UILayer * m_UILayer;
	CCSize m_winSize;
	//主场景的左上边显示的字体,包含了玩家的得分信息
	CCLabelBMFont * m_font;
	UILayer(){};
};

#endif
/*游戏主场景的UI界面*/
#include "UILayer.h"
#include "StartGameScene.h"

UILayer * UILayer::m_UILayer = NULL;

UILayer * UILayer::sharedUILayer()
{
	if(!m_UILayer)
	{
		m_UILayer = new UILayer();
	}
	return m_UILayer;
}

void UILayer::freeUILayer()
{
	if(m_UILayer)
	{
		delete m_UILayer;
		m_UILayer = NULL;
	}
}

//init中完成一些初始化的操作
bool UILayer::init()
{
	bool bRet = false;
	do
	{
		CC_BREAK_IF(!CCLayer::init());
		//玩家的开始分数为0
		m_score = 0;
		m_winSize = CCDirector::sharedDirector()->getWinSize();
		//调用update函数来更新玩家的分数
		this->scheduleUpdate();

		//创建一个显示分数的标签
		CCString * string = CCString::createWithFormat("score:%d",m_score);
		m_font = CCLabelBMFont::create(string->getCString(),"bitmapFontChinese.fnt");
		m_font->setPosition(ccp(m_font->getContentSize().width/2,m_winSize.height-m_font->getContentSize().height/2));
		this->addChild(m_font);

		//添加一个返回游戏主菜单的菜单项
		CCMenuItemImage * backMenu = CCMenuItemImage::create("b2.png","b2.png",
			this,menu_selector(UILayer::backMainMenu));
		CCMenu * menu = CCMenu::create(backMenu,NULL);
		menu->setPosition(ccp(m_winSize.width-backMenu->getContentSize().width/2,
			m_winSize.height-backMenu->getContentSize().height/2));
		this->addChild(menu);

		bRet = true;
	}
	while(0);

	return bRet;
}

//实时的更新玩家的分数
void UILayer::update(float tm)
{
	CCString * string = CCString::createWithFormat("score:%d",m_score);
	this->m_font->setString(string->getCString());
	m_font->setPosition(ccp(m_font->getContentSize().width/2,m_winSize.height-m_font->getContentSize().height/2));
}
//返回到游戏的开始界面
void UILayer::backMainMenu(CCObject * object)
{
	CCDirector::sharedDirector()->replaceScene(StartGameScene::scene());
}

Cocos2d-x游戏实例之忍者飞镖 在主场景中我们需要做的事是在init函数中加入UI的初始化,添加UI到主场景,同时在手指按下触发的事件时也应该播放音效,具体的实现如下。

//加入UI之前先进行初始化的操作
		UILayer::sharedUILayer()->init();
		this->addChild(UILayer::sharedUILayer(),2);
//当手指按下的时候触发该事件
bool GameMainLayer::ccTouchBegan(CCTouch * touch,CCEvent * pEvent)
{
	CCPoint touchPoint = touch->getLocation();
	//玩家将手指按下的时候发射子弹
	m_hero->fire(touchPoint);

	//播放子弹发射的音效
	if(UserData::sharedUserData()->getEffectValue())
	{
		AudioPretreat::sharedAudioPretreat()->playEffect();
	}

	return true;
}

下面再来贴一下Appdelegate中的代码,其中包含了声音和数据析构的处理以及适配的代码。

AppDelegate::~AppDelegate()
{
    SimpleAudioEngine::end();
	AudioPretreat::freeAudioPretreat();
	UserData::freeUserData();
}
bool AppDelegate::applicationDidFinishLaunching()
{
    // initialize director
    CCDirector *pDirector = CCDirector::sharedDirector();

	CCEGLView* pEGLView = CCEGLView::sharedOpenGLView();

    pDirector->setOpenGLView(CCEGLView::sharedOpenGLView());

    // turn on display FPS
    pDirector->setDisplayStats(true);

    // set FPS. the default value is 1.0/60 if you don't call this
    pDirector->setAnimationInterval(1.0 / 60);

	//以下就是如何进行适配的具体方法
	//getFrameSize()获得实际屏幕的大小
	 CCSize frameSize = pEGLView->getFrameSize();
	 //这填写的就是一般你作为背景图片的那种图片的大小,适配的原理就是放到和缩小,而以什么为参照,当然就是
	 //以最大的那张图片为参照,什么图片最大,当然是背景图片了,以后美工做图的时候用的就是以下的这个尺寸
	 CCSize winSize=CCSize(480,320);

	 //将宽和高做一个比,通过这个比,来具体的调整逻辑分辨率的大小
	 float widthRate = frameSize.width/winSize.width;
	 float heightRate = frameSize.height/winSize.height;

	 //如果是if中的语句,说明逻辑的高度有点大了,就把逻辑的高缩小到和宽度一样的比率
    if (widthRate > heightRate)
	{
		//里边传入的前俩个参数就是逻辑分辨率的大小,也就是通过getWinSize()得到的大小
		pEGLView->setDesignResolutionSize(winSize.width,
			winSize.height*heightRate/widthRate, kResolutionNoBorder);
	}
    else
	{
		pEGLView->setDesignResolutionSize(winSize.width*widthRate/heightRate, winSize.height,
			kResolutionNoBorder);
	}

	//在这里进行游戏的数据和声音的初始化

	//进行数据类的初始化,数据类要先于声音类初始化,因为声音类中用到了数据类中的变量
	UserData::sharedUserData();

	//进行声音类的初始化,将声音加载进来
	AudioPretreat::sharedAudioPretreat()->init();

    // create a scene. it's an autorelease object
    //CCScene *pScene = GameMainLayer::scene();
	CCScene *pScene = StartGameScene::scene();

    // run
    pDirector->runWithScene(pScene);
    return true;
}

最后的最后我们来为游戏添加对手机返回键的监听,方法是如果你的类没有继承自CCLayer的话,就要继承CCKeypadDelegate这个类,默认的情况下CCLayer是继承了这个类,所以我们只要是继承自CClayer的话就不需要再继承这个类了。然后在场景的初始化函数中加入this->setKeypadEnabled(true);这句代码。接着就可以在void keyBackClicked () ,void keyMenuClicked ()这俩个函数中加入对返回键的处理代码和对菜单键的处理代码。我们要在这四个场景中都加入对返回键的响应,代码如下:

void GameMainLayer::keyBackClicked()
{
	CCDirector::sharedDirector()->replaceScene(StartGameScene::scene());
}
//加上对手机返回键的支持
void StartGameScene::keyBackClicked()
{
	CCDirector::sharedDirector()->end();
}

除了开始界面的场景,其他的场景我使用的是使用popScene()和replaceScene()这个函数。到这里为止,我们的这个小项目就做完了。通过这个项目,我个人学到了不少的东西,虽然广告平台发布什么的还不知道,但是接下来会继续学习这个引擎的,不断记录自己的学习过程和大家分享。以上的步骤大家有不清楚的欢迎给我留言。最后我把自己的项目源码和生成的APP文件都给大家留下,欢迎测试!