寻找更好的匹配3宝石碰撞检测算法

时间:2013-08-31 17:02:12

标签: algorithm

我建立简单匹配3游戏的学习建议,现在我有简单的游戏部分 当宝石移动到某个方向(X或Y)时,需要找出周围的宝石是否为
相同,超过1连续我编程不是那么聪明的解决方案,我正在寻找想法,使其更一般。 这是我的代码注释:

/

* 
 detect and store the gems that are alike the selected gem
*/

bool GameController::matchDetector(Gem* pSelected)
{
    // get the gem that are near the selected gem based on the selected gem movement type 
    // for example if moved right the movement type is (RightMovment) so the next gem is row,col+1
    Gem* pNextSprite = getNextGem(pSelected,pSelected->getGemState());
    // array that will store the Gems that are found for each direction array of its own
    CCArray * rightGemsToRemove = CCArray::create();
    CCArray * leftGemsToRemove = CCArray::create();
    CCArray * upperGemsToRemove = CCArray::create();
    CCArray * downGemsToRemove = CCArray::create();

    if(pNextSprite == NULL)
    {
        return false;
    }
    //copy the selected NEXT gem to the selected gem
    //so the calculation to find the next gems will be right 
    pSelected->swap(pNextSprite);
    int col = pSelected->getColNum();
    int row = pSelected->getRowNum();
    /*

        its long switch case that on its option doing the same so only the first one commented 

    */
    switch(pSelected->getGemState())
    {
        case kMoveRight:
        {
            // if its right direction i need to run on all the right gems until its NOT the same and stor it 
            for(int i=pSelected->getColNum()+1;i < maxGemsInCol;i++)
            {
                std::string nextInnerSpriteId = pUT->setGemId(i,row);
                // get the next gem from the container 
                Gem* pNextInnerSprite = (Gem*)GameSingleTone::getInstance()->getGemsDictionary()->objectForKey(nextInnerSpriteId);

                if(pNextInnerSprite == NULL)
                {
                    return false;
                }
                else
                {
                    // add it to the container 
                    rightGemsToRemove->addObject(pNextInnerSprite);
                }
            }
            break;
        }
        case kMoveLeft:
        {

            for(int i=pSelected->getColNum()-1;i < maxGemsInCol;i++)
            {
                std::string nextInnerSpriteId = pUT->setGemId(i,row);
                Gem* pNextInnerSprite = (Gem*)GameSingleTone::getInstance()->getGemsDictionary()->objectForKey(nextInnerSpriteId);

                if(pNextInnerSprite == NULL)
                {
                    return false;
                }
                else
                {
                    leftGemsToRemove->addObject(pNextInnerSprite);
                }
            }
            break;
        }
        case kMoveUp:
        {
            for(int i=pSelected->getRowNum()+1;i < maxGemsInRow ;i++)
            {
                std::string nextInnerSpriteId = pUT->setGemId(col,i);
                Gem* pNextInnerSprite = (Gem*)GameSingleTone::getInstance()->getGemsDictionary()->objectForKey(nextInnerSpriteId);

                if(pNextInnerSprite == NULL)
                {
                    return false;
                }
                else
                {
                    upperGemsToRemove->addObject(pNextInnerSprite);
                }
            }
            break;
        }
        case kMoveDown:
        {
            for(int i=pSelected->getRowNum()-1;i < maxGemsInRow ;i++)
            {
                std::string nextInnerSpriteId = pUT->setGemId(col,i);
                Gem* pNextInnerSprite = (Gem*)GameSingleTone::getInstance()->getGemsDictionary()->objectForKey(nextInnerSpriteId);

                if(pNextInnerSprite == NULL)
                {
                    return false;
                }
                else
                {
                    downGemsToRemove->addObject(pNextInnerSprite);
                }
            }
            break;
        }
    }

    /*
    this function will run on all the arrays and will check which gems needs to be removed from the GRID and all the rest ( fill the grid with new gems and so on .. ) 
    */
    handleGems(downGemsToRemove,upperGemsToRemove,leftGemsToRemove,rightGemsToRemove)

}

1 个答案:

答案 0 :(得分:1)

我认为你正在使用的算法绝对没有问题(“在给定的方向上循环宝石,直到你找到一个不同的算法”)。除非游戏板有数百万行或列,否则最多只需几微秒,这是迄今为止最简单的算法。

我不明白的一件事是你积累了四个单独的列表rightGemsToRemoveleftGemsToRemove等等。handleGems()会对每种列表做些不同的事情吗?如果没有,只需使用一个gemsToRemove列表。

另一个建议:你有四个案例,每个案例包含基本相同的代码。这种重复是产生错误的肥沃土壤:如果你需要对逻辑进行一些改变,很容易忘记在所有四个副本中进行相同的更改,或者意外地做出错误的更改(使用例如复制和粘贴) )。我建议将switch声明缩减为:

int dx, dy;
switch (switch(pSelected->getGemState())) {
case kMoveRight: dx = 1;  dy = 0;  break;
case kMoveLeft:  dx = -1; dy = 0;  break;
case kMoveUp:    dx = 0;  dy = -1; break;
case kMoveDown:  dx = 0;  dy = 1;  break;
}

之后,您只需编写一个循环,将dx添加到x,将dy添加到y

int x = pSelected->getColNum() + dx;
int y = pSelected->getRowNum() + dy;
while (x >= 0 && x < maxGemsInRow && y >= 0 && x < maxGemsInCol) {
    std::string nextInnerSpriteId = pUT->setGemId(x, y);
    Gem* pNextInnerSprite = (Gem*)GameSingleTone::getInstance()->getGemsDictionary()->objectForKey(nextInnerSpriteId);

    if(pNextInnerSprite == NULL) {
        return false;
    } else {
        gemsToRemove->addObject(pNextInnerSprite);
    }

    x += dx;
    y += dy;
}

可以说更好:如果kMoveRight等都是小整数值,你可以直接从静态数组中查找它们:

static int dxFromMovement[] = { 1, -1, 0, 0 };
static int dyFromMovement[] = { 0, 0, -1, 1 };

dx = dxFromMovement[pSelected->getGemState()];
dy = dyFromMovement[pSelected->getGemState()];

这可能会稍微快一些,但在我看来,它稍微不那么明确,而且速度差异远远低于我的意见,这是不值得的。