cocos2d-x路~使得第一个字游戏(一个)

前言

去年的回忆。另外,在第三、他们开发了他们的第一场比赛四月,它是游戏。所以我决定走上独立开发的道路上。了。第一款游戏达到它应有的盈利水平。然而这款游戏开发后的时间里。都没再取得还有一款令自己惬意的作品。

直到今年的三、四月,我使用cocos2d-x开发出我的第一款文字游戏。

第一款游戏的传送门

第一款文字游戏的传送门

自从使用cocos2d-x后。发现自己爱上了这个引擎。

它也许还不够强大和完好。可是使用它。能够体验编码的乐趣。还能够为我重拾C++这门技术(究竟对C++有多么的执着啊),还能增进NDK和JNI的学习。恰恰满足我各种各样的追求。

这个第一款文字游戏。名字我取作Anagram Puzzle。事实上这款游戏是參照RayWenderlich上的这篇教程来改写的。教程里使用的是iOS的UIKit编写。虽说原理相通。可是在改写过程中还是遇到不少折腾的地方。因为初次编写cocos2d-x游戏。所以错误难免百出,希望阅读者们高抬贵手,点到即止……废话不多说,立即開始coco2d-x之道~怎样制作第一款文字游戏!

Anagram简单介绍

Anagram是一种把单词或短语的字母顺序打乱,又一次排列后变成一个新单词或短语的游戏。

比如,单词cinema能够又一次排列成iceman。游戏中就要求玩家进行你所提供单词或短语的又一次排列。完毕游戏的画面会如图所看到的:

watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvdTAxMTc4MTgzNA==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast" >

在开发这个游戏过程中,会接触到下面这些知识:

  • MVC型的游戏结构
  • 怎样从文件配置载入级别
  • 载入第三方字体
  • 简单使用音乐音效
  • 分离HUD层与游戏层
  • 手势拖动及动画
  • Particle的效果

还有其它的一些cocos2d-x的基础知识,都会在开发过程中接触到。

初始化project

首先最重要的当然是使用命令行来创建cocos2d-xproject,当然也有其它方法也能够创建project。可是我觉得掌握命令行来创建是必须的基本功。

创建方法能够在这里找到。创建完毕后各个平台的project目录都有了。我们的主要project目录是proj.android和proj.ios两个。

整个开发过程,我使用Mac OS来开发,所以编码是在XCode上进行,而Androidproject的编译则使用命令行,具体教程能够參考这里

建立好project后,先把所需的资源文件复制到Resource目录中。打开Xcodeproject,眼下Resource目录下还是原来的资源文件,通过右击Resource目录 -> Add Files to ...,把资源文件都加到project里。编辑后project会如图

1)载入级别配置文件

打开level1.plist,能够看到里面内容

watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvdTAxMTc4MTgzNA==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast" >

有三个最顶端的key,各自是:

pointsPerTile: 每一个单词填对后获得的分数。

timeToSolve: 解决这一关的时间(秒)。

anagrams: 是题目的列表,包括两个item。各自是原始的短语以及最后要拼出的短语。

level文件的介绍就到此为止。以下開始编写Level类,在Level.h中加入以下内容

class Level:public CCObject{
public:
	static Level * levelWithNum(int levelNum);

public:
	int mPointPerTile;
	int mTimeToSovle;
	CCArray * pAnagrams;
};

当中,三个变量相应level文件中的三个最顶端的item。另一个初始化函数。是给外部调用初始化level文件。

如今。打开Level.cpp。实现levelWithNum函数

Level * Level::levelWithNum(int levelNum){
	char fileName[50];
	char fullPath[150];
	sprintf(fileName,"level%d.plist",levelNum);
	CCFileUtils::sharedFileUtils()->fullPathFromRelativeFile(fileName,fullPath);
	CCDictionary * pListDict = CCDictionary::createWithContentsOfFile(fileName);

	if(pListDict == NULL){
		CCLog("level config not found");
	}

	Level * l = new Level();
	CCString * tempStr;
	tempStr = dynamic_cast<CCString*>(pListDict->objectForKey("pointsPerTile"));
	l->mPointPerTile = tempStr->intValue();
	tempStr = dynamic_cast<CCString*>(pListDict->objectForKey("timeToSolve"));
	l->mTimeToSovle = tempStr->intValue();
	l->pAnagrams = dynamic_cast<CCArray*>(pListDict->objectForKey("anagrams"));
	l->pAnagrams->retain();

	return l;
}

这里首先用CCDictionary读出level文件里数值,然后就是读取出相应key里的值,并存储起来。

如今。打开主界面文件。默认是HelloWorldScene类,可是我改写成MainScene,当中MainScene.h是这种

class MainScene : public cocos2d::CCLayer
{
public:
    ~MainScene();
    // Here‘s a difference. Method ‘init‘ in cocos2d-x returns bool, instead of returning ‘id‘ in cocos2d-iphone
    virtual bool init();  

    // there‘s no ‘id‘ in cpp, so we recommend returning the class instance pointer
    static cocos2d::CCScene* scene();

    // implement the "static node()" method manually
    CREATE_FUNC(MainScene);
private:
	Level * pLevel;
};

可见。添加了Level变量。在MainScene.cpp中的init函数。编写

pLevel = Level::levelWithNum(1);

当然。这里能够通过CCLog来打印出pLevel里的内容来看看。会得到如图所看到的

在MainScene里加入个新的函数

void dealRandomAnagram();

详细实现要这样

void MainScene::dealRandomAnagram(){
	Common::random(0, pLevel->pAnagrams->count() - 1);
	int randomIndex =  Common::random(0, pLevel->pAnagrams->count() - 1);

	CCAssert((randomIndex >= 0 && randomIndex < pLevel->pAnagrams->count()),"error random index!");

	CCArray * anagram = (CCArray*)pLevel->pAnagrams->objectAtIndex(randomIndex);

	CCString * ana1 = (CCString*)anagram->objectAtIndex(0);
	CCString * ana2 = (CCString*)anagram->objectAtIndex(1);

	int ana1len = ana1->length();
	int ana2len = ana2->length();
}

Common::random是我自己编写的。生成两个数值之间的随机数

int Common::random(int s,int e){
	float i = CCRANDOM_0_1()*(e-s+1)+s;
	return (int)i;
}

这样就把初始状态的短语和终于状态的短语获取到了,把dealRandomAnagram函数加入到MainScene的init函数里。

pLevel = Level::levelWithNum(1);
dealRandomAnagram();

2)创建单词的View

watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvdTAxMTc4MTgzNA==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast" >

在project中新增一个继承于CCNode的类,名字叫做TileView,在TileView.h中加入下面代码

public:
	static TileView * initWithLetter(const char * l,float sideLen);

private:
	CCSprite * pSprite;
	char mLetter;
	bool mIsMatch;

当中initWithLetter是初始化函数,pSprite是显示的精灵。mLetter是相应的字母。mIsMatch表示结果是否已经配对上(就是找到字母所应该在的位置)。

在TileView.cpp里。加入下面代码

#include "TileView.h"

TileView * TileView::initWithLetter(const char * l, float sideLen){
	TileView * tile = new TileView();
	CCSprite * bg = CCSprite::create("tile.png");
	tile->addChild(bg);
	tile->pSprite = bg;
	float scale = sideLen / bg->getContentSize().width;
	bg->setScale(scale);

	char chLetter[2];
	sprintf(chLetter,"%c",l[0] - 32);
	CCLabelTTF * letter = CCLabelTTF::create(chLetter,"Arial",75 * scale);
	letter->setColor(ccWHITE);
	tile->addChild(letter);

	tile->mIsMatch = false;
	tile->mLetter = chLetter[0];

	return tile;
}

函数中,首先的是创建一个以tile.png为图案的精灵。然后创建图案上的字母

接下来就要在界面中显示出来了。在MainScene中加入

private:
	Level * pLevel;
	CCArray * pTiles;
	CCArray * pTargets;

pTiles是TileView的数组,pTargets是TargetView的数组,当中TileView是放在底部给出的短语的各个单词,TargetView是目标短语的各个单词。在MainScene.cpp的dealRandomAnagram函数中继续加入代码

int ana1len = ana1->length();
int ana2len = ana2->length();

float tileSide = ceilf( Common::getCameraWith()*0.9 / (float)std::max(ana1len, ana2len) ) - kTileMargin;

float xOffset = (Common::getCameraWith() - std::max(ana1len,ana2len) * (tileSide + kTileMargin)) / 2;
xOffset += tileSide/2;

此时,開始计算各个TileView的位置。

首先,比較得出原始短语和目标短语中长度最长的。然后算出各个View所需的宽度tileSide,以及各个View之间的间隔xOffset

对了,不要忘了定义全局的空隙

#define kTileMargin 20

接着,就要创建我们的TileView了

	pTiles = CCArray::createWithCapacity(ana1len);

	const char * ana1Letter = ana1->getCString();
	for(int i = 0;i < ana1len; i++){
		char letter[3];
		sprintf(letter,"%c",ana1Letter[i]);

		if(letter[0] != ‘ ‘){
			TileView * tile = TileView::initWithLetter(letter,tileSide);
			tile->setPosition(ccp(xOffset + i * (tileSide + kTileMargin),Common::getCameraHeight() / 4));
			this->addChild(tile);
			pTiles->addObject(tile);
		}
	}
	pTiles->retain();

创建方法比較简单。可是要注意的是,原始短语中能够会有空字符。空字符的地方须要留空。如图所看到的

watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvdTAxMTc4MTgzNA==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast" >

3)单词View优化

方方正正的TileView看着有些拘谨,以下进行一些优化来让它们生动一些。

在TileView中加入randomize函数

void TileView::randomize(){
	float rotation = Common::random(0,50) /(float)100 - 0.2;
	this->setRotation(rotation * 10);

	int yOffset = Common::random(0,10);
	this->setPositionY(this->getPositionY() + yOffset);
}

让TileView稍作旋转和偏移,然后在MainScene的dealRandomAnagram函数中的 this->addChild(tile); 语句后加入以下语句

tile->randomize();

4)加入TargetView

有了原始短语,以下就要開始创建目标短语的View了。对照TileView。TargetView要相对简单一些。由于它是固定位置及不须要显示字母。

TargetView.h中加入以下代码:

class TargetView : public CCNode
{
public:
	TargetView(void);
	~TargetView(void);

	static TargetView * initWithLetter(const char * l,float sideLen);

private:
	CCSprite * pSprite;
	char mLetter;
	bool mIsMatch;
};

与TileView相类似的。一个初始化函数,三个私有变量。

与TileView的是一一相应。

TargetView * TargetView::initWithLetter(const char * l, float sideLen){
	TargetView * tile = new TargetView();
	CCSprite * bg = CCSprite::create("slot.png");
	tile->addChild(bg);
	tile->pSprite = bg;

	float scale = sideLen / bg->getContentSize().width;
	bg->setScale(scale);

	char chLetter[2];
	sprintf(chLetter,"%c",l[0] - 32);
	/*
	CCLabelTTF * letter = CCLabelTTF::create(chLetter,"Arial",78 * scale);
	letter->setColor(ccWHITE);
	tile->addChild(letter);*/

	tile->mIsMatch = false;
	tile->mLetter = chLetter[0];

	return tile;
}

TargetView的initWithLetter函数中,凝视的语句是为显示一下结果。可是在实际游戏中是不显示TargetView上的字母。

接下来,就要把TargetView显示到场景上了。找到MainScene的dealRandomAnagram方法,在末尾处加入上下面代码

	pTargets = CCArray::createWithCapacity(ana2len);

	const char * ana2Letter = ana2->getCString();
	for(int i = 0;i < ana2len; i++){
		char letter[3];
		sprintf(letter,"%c",ana2Letter[i]);

		if(letter[0] != ‘ ‘){
			TargetView * target = TargetView::initWithLetter(letter,tileSide);
			target->setPosition(ccp(xOffset + i * (tileSide + kTileMargin),Common::getCameraHeight() / 4 * 3));
			this->addChild(target);
			pTargets->addObject(target);
		}
	}
	pTargets->retain();

是否可看到TargetView也出来,这里。我们就完毕了AnagramPuzzle的第一部分开发工作,最后上个截图

感觉还不错吧,轻松的把所须要的游戏界面展示出来。

这次接触到cocos2d-x知识还是比較少。主要是如何往主场景中加入内容,如何创建精灵。下一次,我们就要编写一些有点挑战性的东西了。比方怎么拖动精灵,怎么推断是否摆在正确的位置,怎么进行倒计时等等,真正的Code乐趣快要上场!

请听下回分解。


版权声明:本文博客原创文章,博客,未经同意,不得转载。

时间: 2024-10-10 19:21:01

cocos2d-x路~使得第一个字游戏(一个)的相关文章

HTML5移动开发之路(12)——从一个多媒体标签说起 一、视频播放

本文为 兄弟连IT教育 机构官方 HTML5培训 教程,主要介绍:HTML5移动开发之路(12)--从一个多媒体标签说起 一.视频播放 [html] view plain copy print? <html> <head> <title>多媒体播放</title> </head> <body> <embed src="http://demo.inwebson.com/html5-video/iceage4.mp4&qu

智能交通行业车车通信和车路通信成为ITS下一个技术亮点

智能交通行业是根据建立智能交通系统所需的设备.服务.技术而衍生出来行业群.智能交通系统(即 ITS--Intelligent Transportation System)是将先的电子传感技术.信息技术.数据通信传输技术.网络技术.控制技术及计算技术等有效地集成运用于整个交通管理体系,而建立起的一种在大范围.全方发挥作用的,实时.准确.高效的综合交通管理系统. 新一代智能交通系统的出现 车车通信和车路通信成为ITS下一个技 术亮点 ITS在起步之时就提出车与路.车与车之间的通信和信息联接,其主要目

Cocos2D将v1.0的tileMap游戏转换到v3.4中一例(五)

大熊猫猪·侯佩原创或翻译作品.欢迎转载,转载请注明出处. 如果觉得写的不好请告诉我,如果觉得不错请多多支持点赞.谢谢! hopy ;) 为了暂时不影响原来的cat移动方法,我们在CatSprite.m中新建一个移动方法,内容如下,其中考虑了与地图的碰撞情况: -(void)moveTowardOneTile:(CGPoint)location{ CGPoint diff = ccpSub(location, self.position); CGPoint desiredTileCoord = [

cocos2d中分步实现飞机大战----游戏场景中背景的滚动

上一节说了场景的跳转,现在开始布置游戏游戏界面.在游戏的主界面,首先要有游戏背景,为了使GameScene的代码不至于太多,可以吧自己的背景进行封装,在GameScene中调用就好,飞机的正常飞行移动可以用北京的移动来实现.创建BackGround: background.h: #include "cocos2d.h" USING_NS_CC; class background:public Node{ public: CREATE_FUNC(background); bool ini

【前端小小白的学习之路】----&gt;用JS编写一个函数,返回数组中重复出现过的元素

用JS编写一个函数,返回数组中重复出现过的元素,见下面的代码: var arr = [1, 2, 3, 1, 2, 3, 4, 5]; var getRepeat = function (arr) { var obj = {}; for (var i = 0, len = arr.length; i < len; i++) { if (obj[arr[i]] == undefined) { obj[arr[i]] = 1; } else { obj[arr[i]]++; } } for (var

“挖掘机”升级路 二篇(04)--分享一个自动配置的脚本

掰着指头算算,今天是周三,也就意味着我从接触Hadoop到搭建集群Hadoop.HBase.Hive已经过去了四天,结果是我依然没有搭建完成,还在苦苦挣扎.这周一定要让完整的Hadoop跑起来,不然也真是太不像话了. 今天我想想干了些啥,早上路过青年路的时候买了个馒头,他居然要了我两块钱!!!不是什么营养馒头,就是路边摊.一笔带过,发泄一下. 今天的工作要分为两段来说,早上是自己接着在研究HBase的集群配置,遇到的主要问题就是两个,第一个就是当我配置slave机器的时候,在hbase-site

Cocos2D将v1.0的tileMap游戏转换到v3.4中一例(三)

大熊猫猪·侯佩原创或翻译作品.欢迎转载,转载请注明出处. 如果觉得写的不好请告诉我,如果觉得不错请多多支持点赞.谢谢! hopy ;) 下面看一下CatSprite中最复杂的moveToward方法,我们一开始只是想要确保cat在屏幕上正确显示出来,动画正确播放出来,所以可以先不管与地图碰撞检测的问题.于是简化到如下代码: -(void)moveToward:(CGPoint)targetLocation{ CGPoint diff = ccpSub(targetLocation, self.p

Cocos2d JS 之消灭星星(五) 游戏主场景

1 /* 2 * 游戏主场景 3 */ 4 var GameMainScene = ccui.Layout.extend( 5 { 6 ctor:function() 7 { 8 this._super(); 9 this.zinit(); 10 this.setTopInfor(); 11 this.addStarLayout(); 12 }, 13 //游戏主场景顶部显示信息 14 setTopInfor:function() 15 { 16 var gameTopInfo = new Ga

Cocos2d JS 之消灭星星(四) 游戏主场景顶部显示

1 /* 2 * 游戏主场景顶部显示信息 3 */ 4 var GameTopInformation = ccui.Layout.extend( 5 { 6 size:null, 7 isPause:false,//是否暂停游戏 8 maxScoreLabel:null,//最高纪录 9 getScoreNum:null,//当前得分 10 currentLevel:null,//当前关卡 11 ctor:function() 12 { 13 this._super(); 14 this.zin