cocos2d-x的初步学习二十七之连连看三

时间:2022-12-13 20:25:19

接下来,我们将完成剩下的游戏界面部分。连连看我们可以看做是一个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

cocos2d-x的初步学习二十七之连连看三

我们定义第一关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;
    
    }


    
}
我们运行下,看下效果

cocos2d-x的初步学习二十七之连连看三


~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

接下来,我们加入触摸事件,代码如下

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;

    
    
}

运行,效果如下

cocos2d-x的初步学习二十七之连连看三

选中的时候,放大精灵~~~~


~~~~~这里时间有限,下一篇的文章将探讨一些自动消除,还有用粒子效果来实现消除时的动画等,还有一些其他问题~~~