欢迎大家转载http://blog.csdn.net/demon_wu/article/details/9925663
上一章节是一个下午的功劳,做了基础的界面和发射的功能,发射完了我们需要停止,停止是在两种情况下,一是在顶层,一是碰撞到其他球的时候,所以需要添加一个函数来进行判断的
bool MainLayer::checCollideBoard()
{
bool bRet = false;
//判断是否是顶层
if (ready->getPosition().y > 960 -30)
{
bRet = true;
return bRet;
}
//检验是否与其他的泡泡发生碰撞
for (int i = MAX_ROWS - 1; i >= 0; --i)
{
for (int j = 0; j < MAX_COLS; ++ j)
{
PaoPao *obj = board[i][j];
//采取圆形碰撞检验
if (obj && isCircleCollision(obj->getPosition(), 30.0, ready->getPosition(), 30.0))
{
bRet = true;
break;
}
}
if (bRet) break;
}
return bRet;
}
同时需要在update里面移动完位置的时候进行此判断,然后执行位置确认,因为我们如果现在停止,那么位置将不会是准确的位置,所以需要进行修改,修改完位置过后需要做的是判断是否有可以消除的泡泡以及是否有可以掉落的泡泡,如果有的话执行相关操作。先添加update里面需要添加的代码:
void MainLayer::update(float fDelta) //update函数
{
if (isCollideBorder()) //先判断是否碰撞
{
real.x = -real.x; //如果碰撞就需要反方向移动
}
CCPoint pos = ready->getPosition(); //获取当前发射的泡泡的位置
ready->setPosition(ccp(pos.x + real.x * PAOPAO_SPEED, pos.y + real.y * PAOPAO_SPEED)); //设置泡泡的位置
if (checCollideBoard()) //检验可以停止碰撞了
{
real = CCPointZero;
correctReadyPosition(); //修正位置
this->unscheduleUpdate(); //取消update
changeWaitToReady(); //将等待使用的泡泡移动位置
setEnable();
return ;
}
}
我们判断可以停止过后先做修正位置,因为之前有一个函数是通过行、列和_flag来确定泡泡的位置,所以我采用了一个笨办法来确认位置,就是遍历所有的泡泡位置,哪一个位置与我当前位置最近并且没有泡泡存在,那么我将泡泡移动过去,使用的效果还不错。
//确认发射出去泡泡的位置
void MainLayer::correctReadyPosition()
{
int offX, offY;
offX = 0;
offY = 0;
CCPoint pos = ready->getPosition();
float length = FLT_MAX;
bool flag = getFirstRowFlag(); //获取第一行的flag值,虽然暂时没有做下移,但是当增加下移的时候这个方法是需要的
bool tempFlag = flag;
for (int i = 0; i < MAX_ROWS; ++ i) //此方法可以优化,暂时先采取笨办法
{
for (int j = 0; j < MAX_COLS; ++ j)
{
if (!board[i][j])
{
CCPoint tPos = getPointByRowAndCol(i, j, flag);
if (ccpDistance(tPos, pos) < length)
{
offX = i;
offY = j;
tempFlag = flag;
length = ccpDistance(tPos, pos);
}
}
}
flag = !flag;
}
//将ready数据转换
board[offX][offY] = ready;
ready->setFlag(tempFlag);
ready->setPosition(getPointByRowAndCol(offX, offY, tempFlag));
ready = NULL;
sameSum = 0;
findTheSamePaoPao(offX, offY, tempFlag, board[offX][offY]->getType()); //检查出所有相同的泡泡,并且执行消除动画效果
resetAllPass(); //初始化所有的pass,表示所有泡泡是不能到达
checkDownPaoPao(); //检验出哪些泡泡是能够到达的
downPaoPao(); //对于不能到达的泡泡来说是可以掉落的
}
当确认泡泡停止的位置时候将ready也就是使用中的球球状态设置为NULL,同时去查找出所有相同的泡泡,重点来了,对于泡泡龙游戏来说,只是根据我当前发射泡泡停的位置开始寻找出附近是否是有相同的泡泡,如果有相同的泡泡并且超过或等于三个的时候表示可以消除。一个泡泡与它相邻的位置有六个,左、右、左上、右上、左下、右下,只要其中任何一个位置泡泡符合相同这个条件,那么我们需要通过那个位置泡泡以相同的方法去寻找,这正是用递归的好时候呀,代码如下:
void MainLayer::findTheSamePaoPao(int i, int j, bool flag, PAOPAO_TYPE type)
{
if (i < 0 || i >= MAX_ROWS || j < 0 || j >= MAX_COLS) //退出递归条件一:超出范围
{
return ;
}
if (!board[i][j]) //退出递归条件二:该位置没有泡泡
{
return ;
}
if (board[i][j]->getType() != type) //退出递归条件三:当前的类型不一样
{
return ;
}
if (board[i][j]->getIsSame()) //退出递归条件三:当前已经判断过是相同的
{
return;
}
//现在时符合条件的,将会进行递归调用
/*
首先将自己isSame设置为true,并且增加theSame
从当前位置左上,右上,左下,右下,左,右六个方向进行寻找
*/
board[i][j]->setIsSame(true);
++sameSum;
//左上
if (flag && j > 0 && i > 0) //当该行是最左的时候,要求不是第一个
{
findTheSamePaoPao(i - 1, j - 1, !flag, type);
}
else if (!flag && i > 0) //不是最左的时候只需要控制不是第一行
{
findTheSamePaoPao(i - 1, j, !flag, type);
}
//右上
if (flag && i > 0) //当时最左的时候右上
{
findTheSamePaoPao(i - 1, j, !flag, type);
}
else if (!flag && i > 0 && j < MAX_COLS - 1) //当不是最左的时候右上
{
findTheSamePaoPao(i - 1, j + 1, !flag, type);
}
//左下
if (flag && j > 0 && i < MAX_ROWS) //当该行是最左的时候,要求不是第一个
{
findTheSamePaoPao(i + 1, j - 1, !flag, type);
}
else if (!flag && i < MAX_ROWS) //不是最左的时候只需要控制不是第一行
{
findTheSamePaoPao(i + 1, j, !flag, type);
}
//右下
if (flag && i < MAX_ROWS) //当时最左的时候右上
{
findTheSamePaoPao(i + 1, j, !flag, type);
}
else if (!flag && i < MAX_ROWS && j < MAX_COLS - 1) //当不是最左的时候右上
{
findTheSamePaoPao(i + 1, j + 1, !flag, type);
}
//左
if (j > 0)
{
findTheSamePaoPao(i, j - 1, flag, type);
}
//右
if (j < MAX_COLS)
{
findTheSamePaoPao(i, j + 1, flag, type);
}
//当找到三个以上的时候开始进行设置消除,如果没有三个的时候将会还原
if (sameSum >= 3)
{
PaoPao *obj = board[i][j];
paopaoAction(obj);
board[i][j] = NULL;
}
else
{
board[i][j]->setIsSame(false);
}
}
上面说的六个方向是对于正常的泡泡,但是在边界的泡泡需要采取判断,判断依据是通过flag和是否是第一个或者是最后一个等,找到泡泡后通过paopaoAction函数来给泡泡相应的动画效果,执行完动画后将其移除掉。
当泡泡消除后将会使一些泡泡是孤立在一起的,也就是没有悬挂点,这些泡泡是需要掉落的泡泡,当初想怎么判断是否没有悬挂点的时候走了弯路,我直接说出现在的思想,因为第一行的是不用判断是否有悬挂点,因为他们就是初始的悬挂点,但是我们需要通过这些悬挂点找出有哪些是被悬挂的,现在假如这个泡泡是悬挂点,那么我们要判断它左、右、左下、右下是否是有泡泡,有的话设置pass值为true,表示可以到达,也就是可以继续作为悬挂点,因为使用循环一行一行找的话有一个问题,我从该行第一个找到最后一个的时候是通过自身来判断的,但是有可能右边一个是悬挂点,但是自己不是悬挂点,那么将会影响到判断,所有采取了两次遍历,一次从第一个找到最后一个,一次是从最后找到第一个来解决。刚说的情况如下图:
如果按照一次遍历,左边那个泡泡将不会被认为是悬挂点,所以需要从左到右两次遍历才可以的,其代码如下:
void MainLayer::checkDownPaoPao()
{
for (int i = 0; i < MAX_COLS; ++ i) //设置好第一行关联
{
if (board[0][i]) board[0][i]->setIsPass(true);
}
//通过第一行来设置下一行的链接情况
for (int i = 0; i < MAX_ROWS; ++ i)
{
//当该点符合条件的时候,因为从左到右判断一次,再从右到左判断一次
/*
当第一次的时候横着只关心右边,第二次的时候横着只关心左边
剩下关心与自己相关的下面两个
*/
//第一次
for (int j = 0; j < MAX_COLS; ++ j)
{
if (board[i][j] && board[i][j]->getIsPass())
{
//右边
if (j < MAX_COLS - 1 && board[i][j + 1]) board[i][j + 1]->setIsPass(true);
if (i < MAX_ROWS - 1)
{
//左下
if (board[i][j]->getFlag() && j > 0 && board[i + 1][j - 1]) board[i + 1][j - 1]->setIsPass(true);
else if (!(board[i][j]->getFlag()) && board[i + 1][j]) board[i + 1][j]->setIsPass(true);
//右下
if (board[i][j]->getFlag() && board[i + 1][j]) board[i + 1][j]->setIsPass(true);
else if (!(board[i][j]->getFlag()) && j < MAX_COLS - 1 && board[i + 1][j + 1]) board[i + 1][j + 1]->setIsPass(true);
}
}
}
//第二次
for (int j = MAX_COLS - 1; j >= 0; -- j)
{
if (board[i][j] && board[i][j]->getIsPass())
{
//左边
if (j > 0 && board[i][j - 1]) board[i][j - 1]->setIsPass(true);
if (i < MAX_ROWS - 1)
{
//左下
if (board[i][j]->getFlag() && j > 0 && board[i + 1][j - 1]) board[i + 1][j - 1]->setIsPass(true);
else if (!(board[i][j]->getFlag()) && board[i + 1][j]) board[i + 1][j]->setIsPass(true);
//右下
if (board[i][j]->getFlag() && board[i + 1][j]) board[i + 1][j]->setIsPass(true);
else if (!(board[i][j]->getFlag()) && j < MAX_COLS - 1 && board[i + 1][j + 1]) board[i + 1][j + 1]->setIsPass(true);
}
}
}
}
}
当找到所有可以到达点,就只需要知道哪些不可以到达,不可以到达就需要掉落动画就可以了。
欢迎大家光临。