消除类游戏核心算法

来源:互联网 发布:relief算法原理 编辑:程序博客网 时间:2024/04/26 13:27

如今消除类游戏很多,比如:消灭寿司,消灭星星等。这篇文章我就共享下我这方面的理解,希望对大家有帮助,如有不好的地方也希望大家指出。

                       

这是我用到资源。同种颜色的2个或者2个以上的就可以消除,消除的越多分越高。

首先,我们来定义一些要用到的变量:

<pre class="cpp" name="code">static const int GRID_COUNT_LANDSCAPE = 10;//方块横总长度static const int GRID_COUNT_PORTRAIT = 10;//方块竖总长度static const string GRID_PIC_PATHS[GRID_TYPE_COUNT] = {string("hongse.png"), string("huangse.png"), string("lanse.png"), string("lvse.png"), string("zise.png")};static const int GRID_TYPE_COUNT = 5;static const int GRID_EMPTY_DATA = GRID_TYPE_COUNT+1;char m_gridData[GRID_COUNT_LANDSCAPE * GRID_COUNT_PORTRAIT];std::vector<GridPos> m_promptGrids;//提示的格子bool m_scaledPromptGrids;//已经缩小的提示格子 cocos2d::gui::Widget *m_gridContentLayer;struct GridPos{    GridPos(int x = 0, int y = 0):m_x(x), m_y(y){    }    int m_x;    int m_y;};struct EliminateGrid{    EliminateGrid(const GridPos &pos, int type):m_gridPos(pos), m_type(type){    }    GridPos m_gridPos;    int m_type;};

 

在GaeScene中初始化:

bool GameScene::init(){      do{            C_BREAK_IF(!TouchGroup::init());       for (int i=0;i<GRID_COUNT_PORTRAIT * GRID_COUNT_LANDSCAPE; i++)        {            m_gridData[i] = GRID_EMPTY_DATA;        }       m_gridContentLayer = Widget::create();        CC_BREAK_IF(!m_gridContentLayer);        m_gridContentLayer->retain();        m_gridContentLayer->setAnchorPoint(ccp(0,0));        m_gridContentLayer->setPosition(ccp(0, 0));        this->addWidget(m_gridContentLayer);        return true;      }while(0);        return false;}


 

得到屏幕上的像素坐标:

void GameScene::getGridPosition(int x, int y, CCPoint &point){    point.x = GRID_WIDTH / 2 + GRID_WIDTH * x;    point.y = GRID_HEIGHT / 2 + GRID_HEIGHT * y;<span style="color:#000000;">}</span>

把屏幕上的像素坐标转换成我们的坐标

bool GameScene::getPointGridPos(const CCPoint &point, GridPos &pos){    float x = point.x - GRID_BEGIN_X;    float y = point.y - GRID_BEGIN_Y;    if (x < 0 || x > GRID_WIDTH * GRID_COUNT_LANDSCAPE        || y < 0 || y > GRID_HEIGHT * GRID_COUNT_PORTRAIT)    {        return false;    }    pos.m_x = ((int)x) / GRID_WIDTH;    pos.m_y = ((int)y) / GRID_HEIGHT;    return true;}

 这里把屏幕上的像素方块坐标转换成我们的坐标是为了我们好操作,这里转换的坐标相当于方块数组的下标,后面有转换的方法。

得到方块的颜色:

std::string GameScene::getGridPath(int data){    if (data == GRID_EMPTY_DATA || data >= GRID_TYPE_COUNT)    {        return "";    }else{        return GAME_SCENE_ROOT_PATH + GRID_PIC_PATHS[data];    }}

 

创建一个10*10的方块组:

void GameScene::initGridsData(){    for(int i=0;i<GRID_COUNT_PORTRAIT * GRID_COUNT_LANDSCAPE; i++){        m_gridData[i] = rand() % (GRID_TYPE_COUNT);    }}

得到方块的下标:

static int getGridIndex(const GridPos &pos){return getGridIndex(pos.m_x, pos.m_y);}

 

显示方块:

void GameScene::showGrids(float duration){    this->removeChildByTag(LEVEL_PASS_AMN_TAG, true);    for (int x = 0; x < GRID_COUNT_LANDSCAPE; x++)    {        for (int y=0;y<GRID_COUNT_PORTRAIT;y++)        {            int index = x * GRID_COUNT_PORTRAIT + y;            string path = getGridPath(m_gridData[index]);            if (path.length() > 0)            {                ImageView *pic = ImageView::create();                pic->loadTexture(path.c_str());                pic->setAnchorPoint(ccp(0.5f,0.5f));                CCPoint position;                getGridPosition(x,y,position);                pic->setPosition(position);                pic->setTag(getGridTag(x, y));                this->m_gridContentLayer->addChild(pic);            }        }    }    m_gridContentLayer->setPositionY(MyGame::CUR_STANDARD_HEIGHT);    CCDelayTime *delay = CCDelayTime::create(duration);    CCMoveTo *moveTo = CCMoveTo::create(BEGIN_GAME_DROP_DOWN_DURATION, ccp(GRID_BEGIN_X, GRID_BEGIN_Y));    CCAction* action = CCSequence::create(delay, moveTo, NULL);    m_gridContentLayer->runAction(action);}



 

触摸方块:

bool GameScene::ccTouchBegan(CCTouch *touch, CCEvent *pEvent){    m_hitChild = TouchGroup::ccTouchBegan(touch, pEvent);    if(GRID_BEGIN_X != m_gridContentLayer->getPositionX() || GRID_BEGIN_Y != m_gridContentLayer->getPositionY()){//格子整体移动的时候不响应点击事件        m_hitChild = true;    }    if (!m_hitChild)    {        bool within = getPointGridPos(touch->getLocation(), m_touchGrid);        if (!within)//没有击中格子,不处理消除        {            m_hitChild = true;        }    }    return true;}

 

void GameScene::ccTouchEnded(CCTouch *touch, CCEvent *pEvent){    TouchGroup::ccTouchEnded(touch, pEvent);    if (!m_hitChild)    {        CCPoint pos = touch->getLocation();        GridPos gridPos;        bool within = getPointGridPos(pos, gridPos);        if (within && gridPos.m_x == m_touchGrid.m_x && gridPos.m_y == m_touchGrid.m_y)        {            vector<GridPos> grids;            this->extendPos(gridPos, grids);            if (0 == this->eliminateGrids(grids))//消除成功,计算是否可以继续消除            {                int score = this->getScore(grids.size());                this->setScore(m_score + score, true, pos, true);//加上所得分改变分数                showEliminatePrompt(grids.size(), score);                clearPromptGrids();            }        }    }}


 

下面开始介绍最核心的部分:

//检测一个方块周围是否有和它一样颜色的 如果有就把它们放到数组中void GameScene::extendPos(const GridPos &pos, vector<GridPos> &validGrids) const{    validGrids.clear();    validGrids.push_back(pos);//把有方块的左边放入validGrids中    char color = m_gridData[getGridIndex(pos)];    if (GRID_EMPTY_DATA == color)    {        return;    }    int checkedGrids[GRID_COUNT_PORTRAIT * GRID_COUNT_LANDSCAPE];    for (int i=0;i<GRID_COUNT_PORTRAIT * GRID_COUNT_LANDSCAPE; i++)    {        checkedGrids[i] = 0;    }    unsigned int index = 0;    while(index < validGrids.size()){        GridPos checkedPos = validGrids[index];//得到每一个方块坐标        int checkedIndex = getGridIndex(checkedPos);        GridPos left(checkedPos.m_x-1, checkedPos.m_y);//检测左边        if (checkSameGrid(left,checkedGrids,color))        {            validGrids.push_back(left);            checkedGrids[getGridIndex(left)]++;        }        GridPos right(checkedPos.m_x+1, checkedPos.m_y);        if (checkSameGrid(right,checkedGrids,color))        {            validGrids.push_back(right);            checkedGrids[getGridIndex(right)]++;        }        GridPos up(checkedPos.m_x, checkedPos.m_y-1);        if (checkSameGrid(up,checkedGrids,color))        {            validGrids.push_back(up);            checkedGrids[getGridIndex(up)]++;        }        GridPos down(checkedPos.m_x, checkedPos.m_y+1);        if (checkSameGrid(down,checkedGrids,color))        {            validGrids.push_back(down);            checkedGrids[getGridIndex(down)]++;        }        checkedGrids[checkedIndex]++;        index++;    }}

 

检测点击的方块周围是否有相同颜色的方块:

//检测同种颜色的方块bool GameScene::checkSameGrid(GridPos &pos, int *checkedGrids, char color) const{    if (pos.m_x < 0 || pos.m_x >= GRID_COUNT_LANDSCAPE || pos.m_y < 0 || pos.m_y >= GRID_COUNT_PORTRAIT)//out range    {        return false;    }    int index = getGridIndex(pos);    if (0 != checkedGrids[index])//is checked    {        return false;    }    return color == m_gridData[index];//check color}

 

消除方块:

int GameScene::eliminateGrids(std::vector<GridPos> &eliminateGrids){    if (eliminateGrids.size() <= 1)    {        return 1;    }    for (vector<GridPos>::iterator iter = eliminateGrids.begin(); iter != eliminateGrids.end(); iter++)//消除    {        GridPos p = *iter;        int index = getGridIndex(p);        vector<EliminateGrid>::iterator iterPos = m_waitEliminateGrids.end();        for (vector<EliminateGrid>::iterator m_iter = m_waitEliminateGrids.begin(); m_iter != m_waitEliminateGrids.end(); m_iter++)        {            if ((*m_iter).m_gridPos.m_x > p.m_x || ((*m_iter).m_gridPos.m_x == p.m_x && (*m_iter).m_gridPos.m_y < p.m_y))            {                iterPos = m_iter;                break;            }        }        EliminateGrid eliminateGrid(p,m_gridData[index]);        m_waitEliminateGrids.insert(iterPos, 1, eliminateGrid);        m_gridData[index] = GRID_EMPTY_DATA;    }    if (eliminateGrids.size() >= SHOW_REWARD_AMN_ELIMINATE_GRID_MIN_COUNT)//消除大于等于5个格子的特效    {        CCDirector::sharedDirector()->getScheduler()->scheduleSelector(schedule_selector(GameScene::playEliminateRewardEffect), this, eliminateGrids.size()*ELIMINATE_INTERVAL, false);    }    m_finishEliminate=false;    showEliminateAmn();//消除方块时播放的动画    return 0;}

 

消除之后,移动方块:

void GameScene::eliminateEmptyGrids(float waitTime){    int index = 0;    for (int x = 0; x < GRID_COUNT_LANDSCAPE; x++)//落下    {        int empty = 0;        for (int y = 0; y < GRID_COUNT_PORTRAIT; y++)        {            if (GRID_EMPTY_DATA == m_gridData[index])            {                empty++;            }else if (empty > 0)            {                moveGrid(index, index-empty, 0, -empty * GRID_HEIGHT, DROP_DOWN_DURATION, waitTime);            }            index++;        }    }    int empty = 0;    for (int x = 0; x < GRID_COUNT_LANDSCAPE; x++)//平移    {        if (GRID_EMPTY_DATA == m_gridData[this->getGridIndex(x, 0)])        {            empty++;        }else if (empty > 0)        {            for (int y = 0; y < GRID_COUNT_PORTRAIT; y++)            {                int oldIndex = getGridIndex(x, y);                if (GRID_EMPTY_DATA != m_gridData[oldIndex])                {                    moveGrid(oldIndex, oldIndex - empty * GRID_COUNT_PORTRAIT, -empty * GRID_WIDTH, 0, MOVE_TO_LEFT_DURATION, waitTime + DROP_DOWN_DURATION);                }            }        }    }}void GameScene::moveGrid(int oldIndex, int newIndex, int disX, int disY, float duration, float waitTime){    m_gridData[newIndex]=m_gridData[oldIndex];//数据移动    m_gridData[oldIndex] = GRID_EMPTY_DATA;    int oldTag =  oldIndex;//图像移动    CCNode* gridSprite = this->m_gridContentLayer->getChildByTag(oldTag);    int newTag =  newIndex;    gridSprite->setTag(newTag);    CCMoveBy *moveBy = CCMoveBy::create(duration, ccp(disX,  disY));    CCEaseSineIn *moveAction = CCEaseSineIn::create(moveBy);    CCAction* action = 0;    if (waitTime > 0)    {        CCDelayTime *delay = CCDelayTime::create(waitTime);        action = CCSequence::create(delay, moveAction, NULL);    }else{        action = CCSequence::create(moveAction, NULL);    }    gridSprite->runAction(action);}



无可消除的方块,结束:

bool GameScene::finish(int remainCount){    int reward = this->getRewardScore(remainCount);    this->setScore(m_score + reward, true, ccp(MyGame::CUR_STANDARD_WIDTH/2,MyGame::CUR_STANDARD_HEIGHT/2), true);    this->showRemainRewardPrompt(remainCount, reward, SHOW_FINISH_INFO_DELAY_TIME);    m_waitEliminateGrids.clear();    for (int x = 0; x < GRID_COUNT_LANDSCAPE; x++)    {        for (int y = GRID_COUNT_PORTRAIT - 1; y >= 0; y--)        {            int index = getGridIndex(x,y);            if (GRID_EMPTY_DATA != m_gridData[index])            {                EliminateGrid eliminateGrid(GridPos(x,y), (int)(m_gridData[index]));                m_waitEliminateGrids.push_back(eliminateGrid);                m_gridData[index] = GRID_EMPTY_DATA;            }        }    }    m_finishEliminate=true;    CCDirector::sharedDirector()->getScheduler()->scheduleSelector(schedule_selector(GameScene::showEliminateAmn), this, ELIMINATE_INTERVAL, kCCRepeatForever, SHOW_FINISH_INFO_DELAY_TIME + REMAIN_REWARD_MOVE_DURATION, false);    if (m_score < m_levelPassScore)//分数没达到要求,游戏结束    {        std::stringstream curLevelSS;        curLevelSS << m_level;        MyGame::getInstance()->tJSendLogDataBy3k("850", curLevelSS.str().c_str());        return false;    }else{       //下一关游戏    }}

我们再加点提示可以消除的方块功能:

计算可以消除的方块:

void GameScene::calculatePromptGrids(){    m_promptGrids.clear();    bool checkedGrids[GRID_COUNT_PORTRAIT * GRID_COUNT_LANDSCAPE];    for (int i=0;i<GRID_COUNT_PORTRAIT * GRID_COUNT_LANDSCAPE; i++)    {        checkedGrids[i] = false;    }    vector<GridPos> validGrids;    GridPos pos;    for (int x = 0; x < GRID_COUNT_LANDSCAPE; x++)//落下    {        for (int y = 0; y < GRID_COUNT_PORTRAIT; y++)        {            int index = getGridIndex(x,y);            if (GRID_EMPTY_DATA == m_gridData[index])            {                break;            }else if (!checkedGrids[index])            {                pos.m_x=x;                pos.m_y=y;                validGrids.clear();                extendPos(pos, validGrids);                //检测所有方块,如果有第一个可以消除的放到validGrids,传给m_promptGrids,然后接着检测,最后把消除最多的传给m_promptGrids                bool changeGrids = validGrids.size() > 1 && validGrids.size()>m_promptGrids.size();                if (changeGrids)                {                    m_promptGrids.clear();                }                for (vector<GridPos>::iterator iter = validGrids.begin(); iter != validGrids.end(); iter++)                {                    checkedGrids[getGridIndex(*iter)]=true;                    if (changeGrids)                    {                        m_promptGrids.push_back(*iter);                    }                }            }        }    }}
//提示消除方块动作void GameScene::showPromptGrids(float interval){    if (m_promptGrids.size()>0)    {        float scale = m_scaledPromptGrids ? 1.0f : PROMPT_GRIDS_MIN_SCALE;        for (vector<GridPos>::iterator iter=m_promptGrids.begin(); iter!=m_promptGrids.end(); iter++)        {            CCNode *gridNode = m_gridContentLayer->getChildByTag(getGridTag(*iter));            CCScaleTo *scaleTo= CCScaleTo::create(PROMPT_GRIDS_DURATION, scale, scale);            CCSequence *action = CCSequence::create(scaleTo, NULL);            gridNode->runAction(action);        }        m_scaledPromptGrids=!m_scaledPromptGrids;    }}

如果点击提示的格子就清除提示格子

void GameScene::clearPromptGrids(){    if (m_scaledPromptGrids)    {        for (vector<GridPos>::iterator iter=m_promptGrids.begin(); iter!=m_promptGrids.end(); iter++)        {            CCNode *gridNode = m_gridContentLayer->getChildByTag(getGridTag(*iter));            if (gridNode)            {                CCScaleTo *scaleTo= CCScaleTo::create(PROMPT_GRIDS_DURATION, 1.0f, 1.0f);                CCSequence *action = CCSequence::create(scaleTo, NULL);                gridNode->runAction(action);            }        }    }    m_promptGrids.clear();    m_scaledPromptGrids=false; }



 

 

0 0