接下来,我们将完成剩下的游戏界面部分。连连看我们可以看做是一个m行乘以n列的一个矩行,其中我们规定0为空的,其余数字可以看作是图片的引用id,通过这个id,我们可以直接找到这个图片,有了图片,我们就可以初始化出这个对应的精灵。然后通过touch事件判断出是否选中或是没选中这个精灵,然后通过相应的算法,算出所选两个精灵对象是否是一样的,并且符合我们的游戏规则,符合就消掉,不符合再重新选取。。。。。。
00001000200003
10000300000002
00040000040000
OK,,我们先新建一个类,叫MapLayer,这个类主要是游戏地图层的部分
//地图层 class MapLayer :public cocos2d::CCLayerColor { public: virtual bool init(); CREATE_FUNC(MapLayer); void initUI(void); void initData(void); ~MapLayer(); private: };上面部分就是新建一个类,定义一些初始化的函数。对于数据部分,你可以存储在一个一维数组里,当然也可以存储到文件中,只要你能获取到数据,那你怎么存都OK的~~~
这里,我们把数据存到一个plist文件里,plist可以看作是一个xml,我们新建一个plist,叫levelinfo.plist
我们定义第一关001,里面有total_x,列数,total_y,行数,也就是上面我们定义了一个5*9的一个矩形,array里面存了图片对应的id,0表示无,没有。
OK。。接下来,我们来解析这个xml,,代码如下
//读取plist数据文件 const char *plistPath=CCFileUtils::sharedFileUtils()->fullPathFromRelativeFile("levelinfo.plist","levelinfo.plist"); CCDictionary *plistDic=CCDictionary::createWithContentsOfFile(plistPath); CCDictionary *levelDic=dynamic_cast<CCDictionary *>(plistDic->objectForKey("001")); CCString *xstring=dynamic_cast<CCString *>(levelDic->objectForKey("total_x")); total_x=xstring->intValue(); CCString *ystring=dynamic_cast<CCString *>(levelDic->objectForKey("total_y")); total_y=ystring->intValue(); CCArray *array=CCArray::create(); array=dynamic_cast<CCArray *>(levelDic->objectForKey("imageidarr"));
这样,我们就读取到plist里相应的数据,接下来,我们定义一个类,叫MapNode类,它就提供两个属性,order跟id,代码如下
class MapNode :public cocos2d::CCObject { public: //序号 int order; //图片的id int imgid; };
接下来,我们对把plist的array里的数据取出来,然后赋值给MapNode的imgid属性,代码如下
mapArray=CCArray::create(); mapArray->retain(); CCArray *array2=CCArray::create(); //种子 srandom((unsigned int)time(NULL)); for (int i=0; i<(total_x-1)*(total_y-1); i++) { MapNode *node=new MapNode(); node->autorelease(); //产生唯一的orderid node->order=(int)(CCRANDOM_0_1()*INT_MAX)%(int)(CCRANDOM_0_1()*INT_MAX); CCString *idString=(CCString *)(array->objectAtIndex(i)); node->imgid=idString->intValue(); array2->addObject(node); } //排序 qsort(array2->data->arr, array2->data->num, sizeof(long),compare); for (int x=0; x<total_x; x++) { for (int y=0; y<total_y; y++) { if (x==0 || y==0) { MapNode *node=new MapNode(); node->autorelease(); node->order=0; node->imgid=0; mapArray->addObject(node); }else { int i = (y - 1) * (total_x - 1) + x - 1; mapArray->addObject(array2->objectAtIndex(i)); } } }mapArray里存的都是经过排序后的mapnode,c排序函数
void qsort(void *, size_t, size_t,int (*)(const void *, const void *));第一个参数是数组头部首地址,第二个参数数组长度,第三个是数组每个元素大小size,第四个是一个int型函数指针,
//排序比较 int compare(const void *a,const void *b) { MapNode *node1=(MapNode *)a; MapNode *node2=(MapNode *)b; if (node1->order>node2->order) { return 1; } else if (node1->order==node2->order) { return 0; } else { return -1; } }OK,接下来,我们来布局我们的图片sprite,代码如下
//布局sprite for (int y = 0; y < total_y; ++y) { for (int x = 0; x < total_x; ++x) { int index=y*total_x+x; if (this->imageFilename(index)) { CCSprite *sprite=CCSprite::createWithSpriteFrameName(this->imageFilename(index)->getCString()); sprite->setScale(1.0); sprite->setPosition(ccp(OFFSET_X * x + (SIZE_W / 2) + SIZE_W * x, OFFSET_Y * y + (SIZE_H / 2) + SIZE_H * y)); this->addChild(sprite, 1, TAG_START_SPRITE+index); } } }
//获取图片 CCString* MapLayer::imageFilename(int index) { int n=((MapNode *)(mapArray->objectAtIndex(index)))->imgid; // CCLOG("n------:%d",index); if (n>=1 && n<=20) { return CCString::createWithFormat("%d.png",n); } else { return NULL; } }我们运行下,看下效果
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
接下来,我们加入触摸事件,代码如下
在
MapLayer.h中加入
virtual bool ccTouchBegan(cocos2d::CCTouch *pTouch, cocos2d::CCEvent *pEvent); virtual void ccTouchEnded(cocos2d::CCTouch *pTouch, cocos2d::CCEvent *pEvent);
MapLayer.cpp中加入
//添加touch监听 CCDirector::sharedDirector()->getTouchDispatcher()->addTargetedDelegate(this, 1, true);
// bool MapLayer::ccTouchBegan(cocos2d::CCTouch *pTouch, cocos2d::CCEvent *pEvent) { return true; } // void MapLayer::ccTouchEnded(cocos2d::CCTouch *pTouch, cocos2d::CCEvent *pEvent) { }我们将在touchend里处理事件,我们获取手指触摸点的坐标,然后把它转换成本地坐标,不然获取的坐标是整个下层的坐标,再把本地坐标转换成地图坐标,就像坦克大战里的,比如(1,2)之类的,看代码
// bool MapLayer::ccTouchBegan(cocos2d::CCTouch *pTouch, cocos2d::CCEvent *pEvent) { CCPoint location = CCDirector::sharedDirector()->convertToGL(pTouch->getLocationInView()); //在这个层区域内返回true if (this->boundingBox().containsPoint(location)) { return true; } //否则返回false,阻止接下来的touch函数 return false; } // void MapLayer::ccTouchEnded(cocos2d::CCTouch *pTouch, cocos2d::CCEvent *pEvent) { CCPoint location = CCDirector::sharedDirector()->convertToGL(pTouch->getLocationInView()); location = this->convertToNodeSpace(location); //location=CCPointMake(location.x, location.y-40); location=this->pointOfView(location); // CCLOG("x:%f",location.x); // CCLOG("y:%f",location.y); }
//屏幕坐标转换成地图坐标 CCPoint MapLayer::pointOfView(cocos2d::CCPoint point) {
int x = -1;
int y = -1;
if (point.x > 0 && point.x < total_x * SIZE_W + OFFSET_X * (total_x-1))
x = (point.x ) / (SIZE_W+OFFSET_X);
if (point.y > 0 && point.y < (total_y-1)* OFFSET_Y + total_y * SIZE_H )
y = (point.y) / (SIZE_H+OFFSET_Y);
return CCPoint(x, y);
}OK。。。。接下来,我们会把剩下的一些算法,判断函数全部写下来,大家直接看代码吧
//是否在有效范围内 bool MapLayer::isValiableNode(cocos2d::CCPoint point) { return point.x >= 0 && point.x < total_x && point.y >= 0 && point.y < total_y; } //是否是空的坐标点 bool MapLayer::isEmptyNode(cocos2d::CCPoint point) { int index=this->indexFromPoint(point); MapNode *node=(MapNode *)mapArray->objectAtIndex(index); return (node->imgid==0); } //每个sprite的index int MapLayer::indexFromPoint(cocos2d::CCPoint point) { return point.y * total_x + point.x; } //是否是相同的点 bool MapLayer::isSamePoints(cocos2d::CCPoint p1, cocos2d::CCPoint p2) { return (p1.x == p2.x && p1.y == p2.y); } //清除 void MapLayer::clearNode(cocos2d::CCPoint point) { int index=this->indexFromPoint(point); MapNode *node=(MapNode *)mapArray->objectAtIndex(index); node->imgid=0; } //判断两个是否可以消除 bool MapLayer::canClearTwo(cocos2d::CCPoint pointpre, cocos2d::CCPoint pointcurrent) { bool bMatch = false; int pre = this->indexFromPoint(pointpre); int current = this->indexFromPoint(pointcurrent); int p = ((MapNode *)(mapArray->objectAtIndex(pre)))->imgid; int c = ((MapNode *)(mapArray->objectAtIndex(current)))->imgid; if (p == c && this->match(pointcurrent, pointpre)) { bMatch = true; } return bMatch; } //放大缩小动画 void MapLayer::scaleAnimation(cocos2d::CCSprite* sprite) { CCScaleTo *ac1=CCScaleTo::create(0.07f, 1.0); CCScaleTo *ac2=CCScaleTo::create(0.07f, 0.9); CCScaleTo *ac3=CCScaleTo::create(0.07f, 1.0); CCSequence *seq=CCSequence::create(ac1,ac2,ac3,NULL); sprite->runAction(seq); }
//三种匹配算法 //一直线 bool MapLayer::match_direct(cocos2d::CCPoint a, cocos2d::CCPoint b) { if (!(a.x == b.x || a.y == b.y)) { return false; } int i; bool match_x = false; if(a.x == b.x) { match_x = true; if(a.y > b.y) { for(i = a.y - 1; i > b.y; --i) { CCPoint point = CCPointMake(a.x, i); if(!this->isValiableNode(point) || !this->isEmptyNode(point)){ match_x = false; } } } if(b.y > a.y) { for(i = b.y - 1; i > a.y; --i) { CCPoint point = CCPointMake(a.x, i); if(!this->isValiableNode(point) || !this->isEmptyNode(point)) { match_x = false; } } } } bool match_y = false; if(a.y == b.y) { match_y = true; if(a.x > b.x) { for(i = a.x - 1; i > b.x; --i) { CCPoint point = CCPointMake(i, a.y); if(!this->isValiableNode(point) || !this->isEmptyNode(point)) { match_y = false; } } } if(b.x > a.x) { for(i = b.x - 1; i > a.x; --i) { CCPoint point = CCPointMake(i, a.y); if(!this->isValiableNode(point) || !this->isEmptyNode(point)) { match_y = false; } } } } return match_x || match_y; } //一个拐点的 bool MapLayer::match_one_corner(cocos2d::CCPoint a, cocos2d::CCPoint b) { CCPoint point = CCPointMake(b.x, a.y); if( this->isValiableNode(point) && this->isEmptyNode(point) && this->match_direct(a, point) && this->match_direct(b, point)){ return true; } point = CCPointMake(a.x, b.y); if( this->isValiableNode(point) && this->isEmptyNode(point) && this->match_direct(a, point) && this->match_direct(b, point)){ return true; } return false; } //两个拐点的 bool MapLayer::match_two_corner(cocos2d::CCPoint a, cocos2d::CCPoint b) { for(int i = a.x - 1; i >= 0; --i) { CCPoint point = CCPointMake(i, a.y); if (!this->isValiableNode(point) || !this->isEmptyNode(point)) { break; } else { if (this->match_one_corner(point, b)) { return true; } } } for(int i = a.x + 1; i < total_x; ++i) { CCPoint point = CCPointMake(i, a.y); if (!this->isValiableNode(point) || !this->isEmptyNode(point)) { break; } else { if (this->match_one_corner(point, b)) { return true; } } } for(int i = a.y - 1; i >= 0; --i) { CCPoint point = CCPointMake(a.x ,i); if (!this->isValiableNode(point) || !this->isEmptyNode(point)) { break; } else { if (this->match_one_corner(point, b)) { return true; } } } for(int i = a.y + 1; i < total_y; ++i) { CCPoint point = CCPointMake(a.x ,i); if (!this->isValiableNode(point) || !this->isEmptyNode(point)) { break; } else { if (this->match_one_corner(point, b)) { return true; } } } return false; } bool MapLayer::match(cocos2d::CCPoint a,cocos2d::CCPoint b) { if (this->match_direct(a, b)) { return true; } if (this->match_one_corner(a, b)) { return true; } if (this->match_two_corner(a, b)) { return true; } return false; }
重新写touch事件
// bool MapLayer::ccTouchBegan(cocos2d::CCTouch *pTouch, cocos2d::CCEvent *pEvent) { CCPoint location = CCDirector::sharedDirector()->convertToGL(pTouch->getLocationInView()); //在这个层区域内返回true if (this->boundingBox().containsPoint(location)) { return true; } //否则返回false,阻止接下来的touch函数 return false; } // void MapLayer::ccTouchEnded(cocos2d::CCTouch *pTouch, cocos2d::CCEvent *pEvent) { CCPoint location = CCDirector::sharedDirector()->convertToGL(pTouch->getLocationInView()); location = this->convertToNodeSpace(location); //location=CCPointMake(location.x, location.y-40); location=this->pointOfView(location); CCLOG("x:%f",location.x); CCLOG("y:%f",location.y); if (this->isValiableNode(location)==false) { return; } if (this->isEmptyNode(location)) { return; } SimpleAudioEngine::sharedEngine()->playEffect("12.wav"); if (this->isSamePoints(location, prePoint)) { return; } //点击当前精灵 CCSprite *spritecurrent=(CCSprite *)this->getChildByTag(TAG_START_SPRITE+this->indexFromPoint(location)); spritecurrent->setScale(1.3); CCLOG("%d",this->indexFromPoint(location)); if (this->isValiableNode(prePoint)) { //前一个 CCSprite *spritepre=(CCSprite *)this->getChildByTag(TAG_START_SPRITE+this->indexFromPoint(prePoint)); if (this->canClearTwo(prePoint, location)) { SimpleAudioEngine::sharedEngine()->playEffect("4.wav"); this->clearNode(location); this->clearNode(prePoint); spritecurrent->setVisible(false); spritepre->setVisible(false); } else { spritepre->setScale(0.9); this->scaleAnimation(spritepre); } } prePoint=location; }
运行,效果如下
~~~~~这里时间有限,下一篇的文章将探讨一些自动消除,还有用粒子效果来实现消除时的动画等,还有一些其他问题~~~