cocos2d-x实现一个PopStar(消灭星星)游戏的逻辑分析及源码
Posted 明立
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了cocos2d-x实现一个PopStar(消灭星星)游戏的逻辑分析及源码相关的知识,希望对你有一定的参考价值。
前言
说起PopStar这个游戏,或许很多人都不知道是啥,但是如果说起消灭星星的话,可能就会有很多人恍然大悟,原来是它。那么,这个消灭星星长得什么样子呢?我们用一张图来看看:
emmm,是的,具体来说,长得就是这样,我们通过点击图片上某一个颜色的星星块,如果,这个颜色块周围存在和他相同的颜色块时,它就会消除掉所有相同的颜色块。直到屏幕上没有颜色块或者不能找到相邻的同色颜色块块时,游戏就结束。
以上呢就是游戏的一个玩法,而我们设计游戏的人,首先要了解的,也是这个游戏的玩法,并且提取有用信息,作为我们的头脑风暴的结果。比如以下几个点:
1.点击事件
2.消除相同颜色块
3.如果有消除,颜色块从上到下填充
4.如果某一列为空,颜色块从右往左填充
以上五点,应该就是整个游戏的核心功能。因此,我们接下来就逐一来探讨以下逻辑的实现:
1.如何响应点击事件
在cocos2d-x中,对鼠标的响应事件封装得很好,在本次的游戏中,我们只需要响应其单点响应即可,具体的一个写法可以为:
#创建一个鼠标监听对象
auto touchListener = EventListenerTouchOneByOne::create();
#为该对象指定相应事件
touchListener->onTouchBegan = CC_CALLBACK_2(HelloWorld::onTouchBegan, this);
#注册鼠标监听对象
Director::getInstance()->getEventDispatcher()->addEventListenerWithSceneGraphpriority(touchListener, this);
以上三个步骤,实际上应该是所有响应事件的日常操作了吧,当然也只是应该,毕竟我目前遇到的套路大致都如此,如果你不是用cocos来进行游戏开发的话,只需要把这部分调整成你所用的语言或者框架的响应事件逻辑即可。
以上,我们是实现了如何响应鼠标事件,但怎么响应呢?实际上就是上面代码中的第二部分:
#HelloWorld::onTouchBegan 此处为响应逻辑,也是主要的游戏逻辑入口
CC_CALLBACK_2(HelloWorld::onTouchBegan, this);
实际上,它在游戏中的逻辑是这样的:
bool HelloWorld::onTouchBegan(cocos2d::Touch *t, cocos2d::Event *e)
#获取当前颜色块
Vec2 point1 = t->getLocation();
Size visibleSize = Director::getInstance()->getVisibleSize();
PopSprite *cur = getPopSpriteByPoint(visibleSize, point1);
if (cur != NULL)
index = 0;
memset(visit, 0, sizeof(visit));
#收集相同颜色块
checkPopUDLR(cur);
#删除相同颜色块
if (index>1)
for (int i = 0; i < index; i++)
sameStart[i]->setNumber(-1);
index = 0;
#更新上下
updateUD();
#更新左右
updateLR();
return true;
注意以上的几个注释:是不是就和我们剩下的几个步骤很是接近?实际上,这个游戏的核心都已经封装在这一小小的逻辑里面,那事不宜迟,我们来揭露以下的几个问题:
怎么收集到相同的颜色块?
这个问题其实很简单,获取相同的颜色块就如同走迷宫,如何获取全部可走的迷宫呢?这里用到的是深搜的思想:何为深搜,就是从当前的颜色块出发,按照上下左右(这里的顺序可以调整)去访问附近的颜色块,如果附近的颜色块颜色相同,重复搜索的步骤,否则,跳过。当等到不能在往下搜索的时候,就代表了全部的相同且相邻的颜色块被找齐了,此时,我们只需要用一个数组存储这些相同的颜色块,等到搜索结束后,删除即可:搜索部分如下:
/**
这部分是实现准备好的变量,所以此处注释了
#x的两个方向
int xx[4] = 1,0,0,-1 ;
#y的两个方向,联合就是针对x和y的上下左右四个方向
int yy[4] = 0,1,-1,0 ;
#是否被访问过,防止重复访问
int visit[10][10] = 0 ;
#保存相同颜色块的数组
PopSprite* sameStart[10*10];**/
void HelloWorld::checkPopUDLR(PopSprite* cur)
#获取当前颜色块的坐标
int x = cur->getX();
int y = cur->getY();
#设置该坐标的访问标识为1,代表访问过
visit[x][y] = 1;
#添加当前颜色块
sameStart[index++] = cur;
#循环,实现四个方向的轮询
for (int i = 0; i < 4; i++)
#获取第一个方向:根据xx和yy的顺序调整
int x1 = x + xx[i];
int y1 = y + yy[i];
#判断是否出界
if (x1 >= 0 && x1 < 10 && y1 >= 0 && y1 < 10)
#如果符合相同颜色,并且没有被访问过
if (popStarSprite[x1][y1]->getNumber() == cur->getNumber() && visit[x1][y1] == 0)
#从当前颜色块出发,继续轮询,知道所有轮询结束
checkPopUDLR(popStarSprite[x1][y1]);
通过上面的方法,我们就可以实现手机相同颜色块,接下来就是,消灭这些颜色块。具体如下:
#注意:此处的index代表相同颜色块的个数,如果index为1时
#代表只有一个颜色块,此时不做消灭操作
if (index>1)
#遍历所有颜色块,删除
#删除是指将其内部的值设置为初值,此处为-1
for (int i = 0; i < index; i++)
sameStart[i]->setNumber(-1);
#清空数组
index = 0;
以上是消灭操作,消灭完之后,需要把空的地方天上,需要满足两个步骤:
上下填充,以及左右填充:
先看上下填充
上下填充的方式,其实是把每一列的星星抽出来,值为-1的值挪到前面,剩下的自然按顺序往下降,具体做法是:按从下网上的顺序,把值不为初值的数全部按顺序抽取排列,再把剩余的空位补-1.最后把这一列数按顺序回归该列:如下:
void HelloWorld::updateUD()
#轮询10列
for (int x = 0; x < 10; x++)
dataIndex = 0;
#抽取每一列的各个数
for (int y = 0; y <10; y++)
#如果初值不为1(-1)
if (popStarSprite[x][y]->getNumber() != -1)
#将其放入新的数组
data[dataIndex++] = popStarSprite[x][y]->getNumber();
#剩下的位数,填充为-1
for(;dataIndex<10; dataIndex++)
data[dataIndex] = -1;
dataIndex = 0;
for (int y = 0; y < 10; y++)
#按顺序填充回到原二位数组
popStarSprite[x][y]->setNumber(data[dataIndex++]);
再看左右填充
左右填充的做法是:从左往右,查询某列为空,如果是,将其挪至最后一列,注意,如果已经挪了一次,则我们所查询的次数就响应减少即可:具体如
void HelloWorld::updateLR()
#从左往右遍历。此处的count初始为0,代表每有被挪动的列数
for (int x = 0; x < 9-count; x++)
#查询是否某列全部为空
bool isHasToLeft = true;
for (int y = 0; y < 10; y++)
if (popStarSprite[x][y]->getNumber() != -1)
isHasToLeft = false;
break;
#如果为空,则 isHasToLeft值为true
if (isHasToLeft)
# isHasToLeft值为true,代表需要挪动该列,count+1,
count++;
#往右挪动整列
for (int j=x; j< 9;j++)
for (int k = 0; k < 10; k++)
popStarSprite[j][k]->setNumber(popStarSprite[j + 1][k]->getNumber());
popStarSprite[j+1][k]->setNumber(-1);
x--;
至此:关于这款游戏的核心点已经讲解完毕:附上一个DEMO版本,仅供参考:
链接:https://pan.baidu.com/s/1U6v3TXS7A60FGVM6CbokPw
提取码:wobh
以上是关于cocos2d-x实现一个PopStar(消灭星星)游戏的逻辑分析及源码的主要内容,如果未能解决你的问题,请参考以下文章