三消類遊戲《萬聖大作戰》03:觸摸事件與精靈的交換

1.觸摸事件

我們玩三消遊戲,就要對屏幕進行滑動,所以需要做一個觸摸事件來處理對屏幕的觸摸。

這裏主要是要獲得開始觸摸觸摸方向兩個,

因爲只需要知道移動的起始精靈移動的終止精靈

所以,在遊戲界面的初始函數,進行觸摸事件的設置(綁定函數添加監聽器

// 觸摸事件處理  
    auto touchListener = EventListenerTouchOneByOne::create();  
    touchListener->onTouchBegan = CC_CALLBACK_2(GameScene::onTouchBegan, this);  
    touchListener->onTouchMoved = CC_CALLBACK_2(GameScene::onTouchMoved, this);  
    _eventDispatcher->addEventListenerWithSceneGraphPriority(touchListener, this);

PS:關於這個監聽器,共有五種:觸摸事件、鍵盤響應事件、加速記錄事件、鼠標響應事件和自定義事件。而且觸摸事件的監聽器還分爲兩種,單點觸摸和多點觸摸。

而且,在3.0版本以前,之前所用的 CCTouchBegan、CCTouchMoved、CCTouchEnd這些都已經被OUT了,現在是讓監聽器自己綁定函數。

再回到本文,之前說過,觸摸事件最重要的是得到起始精靈終止精靈,所以要定義這兩個變量,然後在onTouchBegan和onTouchMoved進行操作。

先是 onTouchBegan函數:

bool GameScene::onTouchBegan(Touch *touch, Event *unused)  
{  
    staSprite = NULL;  
    endSprite = NULL;  
  
    if ( isTouchEna ) {  
        auto location = touch->getLocation();  
        staSprite = spriteOfPoint(&location);  
    }  
    return isTouchEna;  
}

這裏出現了一個新變量——isTouchEna,從名字中可以看出它的作用,是否可以觸摸。

什麼時候不可以呢? 檢測是否有可消除精靈的時候,精靈正在下落的時候,均不可以觸摸。

這個變量還需要在前面設置一下,

要在構造函數中,設置變量爲 true,

然後在 update函數中  isTouchEna = !isAction;    (如果精靈正在移動中,就應該忽視觸摸事件)

在這裏,又出現了一個工具函數——spriteOfPoint(根據觸摸點的位置,返回是地圖中哪個精靈)

// 根據觸摸的點位置,返回是地圖中哪個精靈  
SpriteShape *GameScene::spriteOfPoint(Point *point)  
{  
    SpriteShape *spr = NULL;  
    Rect rect = Rect(0, 0, 0, 0);  
    Size sz;  
    sz.height=SPRITE_WIDTH;  
    sz.width=SPRITE_WIDTH;  
  
    for( int r = 0 ; r < ROWS ; ++r )    {  
        for( int c = 0 ; c < COLS ; ++c )    {  
            spr = map[r][c];  
            if( spr )   {  
                rect.origin.x = spr->getPositionX() - ( SPRITE_WIDTH / 2);  
                rect.origin.y = spr->getPositionY() - ( SPRITE_WIDTH / 2);  
  
                rect.size = sz;  
                if (rect.containsPoint(*point)) {  
                    return spr;  
                }  
            }  
        }  
    }  
      
    return NULL;  
}

然後是 onTouchMoved函數:

// 觸摸後移動的方向  
void GameScene::onTouchMoved(Touch *touch, Event *unused)   {  
    // 如果沒有初始精靈 或者 觸摸事件不可行,直接返回  
    if (!staSprite || !isTouchEna) {  
        return;  
    }  
      
    // 獲取 初始精靈 的行列  
    int row = staSprite->getRow();  
    int col = staSprite->getCol();  
      
    // 獲取移動到的 點 的位置  
    auto location = touch->getLocation();  
    auto halfSpriteWidth = SPRITE_WIDTH / 2;  
    auto halfSpriteHeight = SPRITE_WIDTH / 2;  
      
    auto  upRect = Rect(staSprite->getPositionX() - halfSpriteWidth,  
                        staSprite->getPositionY() + halfSpriteHeight,  
                        SPRITE_WIDTH,  
                        SPRITE_WIDTH);  
      
    // 判斷是在向哪個方向移動,  
    if (upRect.containsPoint(location)) {  
        ++row;  
        if ( row < ROWS ) {  
            endSprite = map[row][col];  
        }  
        swapSprite();  
        return;  
    }  
      
    auto  downRect = Rect(staSprite->getPositionX() - halfSpriteWidth,  
                        staSprite->getPositionY() - (halfSpriteHeight * 3),  
                        SPRITE_WIDTH,  
                        SPRITE_WIDTH);  
      
    if (downRect.containsPoint(location)) {  
        --row;  
        if ( row >= 0 ) {  
            endSprite = map[row][col];  
        }  
        swapSprite();  
        return;  
    }  
      
    auto  leftRect = Rect(staSprite->getPositionX() - (halfSpriteWidth * 3),  
                          staSprite->getPositionY() - halfSpriteHeight,  
                          SPRITE_WIDTH,  
                          SPRITE_WIDTH);  
      
    if (leftRect.containsPoint(location)) {  
        --col;  
        if ( col >= 0 ) {  
            endSprite = map[row][col];  
        }  
        swapSprite();  
        return;  
    }  
      
    auto  rightRect = Rect(staSprite->getPositionX() + halfSpriteWidth,  
                          staSprite->getPositionY() - halfSpriteHeight,  
                          SPRITE_WIDTH,  
                          SPRITE_WIDTH);  
      
    if (rightRect.containsPoint(location)) {  
        ++col;  
        if ( col < COLS ) {  
            endSprite = map[row][col];  
        }  
        swapSprite();  
        return;  
    }  
      
    // 否則,並非一個有效的移動  
}

這裏還有一個函數 swapSprite,顧名思義,就是判斷好向哪個方向移動後,直接交換這兩個精靈。


2. 交換精靈

關於交換精靈,有兩種情況

> 交換後,滿足消除條件,消除

> 交換後,不滿足消除條件,返回原樣

所以,函數是這樣的:

// 交換精靈  
void GameScene::swapSprite()    {  
    // 移動中,不允許再次觸摸,執行動作設置爲true  
    isAction = true;  
    isTouchEna = false;  
  
    // 初始精靈 和 終止精靈 均不能爲空  
    if (!staSprite || !endSprite) {  
        return;  
    }  
      
    Point posOfSrc = staSprite->getPosition();  
    Point posOfDest = endSprite->getPosition();  
  
    float time = 0.2;  
      
    // 在數組中交換位置  
    map[ staSprite -> getRow() ][staSprite -> getCol() ] = endSprite;  
    map[ endSprite -> getRow() ][endSprite -> getCol() ] = staSprite;  
  
    int tmpRow = staSprite->getRow();  
    int tmpCol = staSprite->getCol();  
    staSprite->setRow(endSprite->getRow());  
    staSprite->setCol(endSprite->getCol());  
    endSprite->setRow(tmpRow);  
    endSprite->setCol(tmpCol);  
      
    // 檢查是否能消除  
    std::list<SpriteShape *> colChainListOfFirst;  
    getColChain(staSprite, colChainListOfFirst);  
      
    std::list<SpriteShape *> rowChainListOfFirst;  
    getRowChain(staSprite, rowChainListOfFirst);  
      
    std::list<SpriteShape *> colChainListOfSecond;  
    getColChain(endSprite, colChainListOfSecond);  
      
    std::list<SpriteShape *> rowChainListOfSecond;  
    getRowChain(endSprite, rowChainListOfSecond);  
      
    if (colChainListOfFirst.size() >= 3  
        || rowChainListOfFirst.size() >= 3  
        || colChainListOfSecond.size() >= 3  
        || rowChainListOfSecond.size() >= 3) {  
        // 如果能夠消除,僅僅進行移動(不會移動回來)  
        staSprite->runAction(MoveTo::create(time, posOfDest));  
        endSprite->runAction(MoveTo::create(time, posOfSrc));  
        return;  
    }  
      
    // 不能消除,則移動過去還要返回  
    map[ staSprite -> getRow()][staSprite -> getCol() ] = endSprite;  
    map[ endSprite -> getRow()][endSprite -> getCol() ] = staSprite;  
  
    tmpRow = staSprite->getRow();  
    tmpCol = staSprite->getCol();  
    staSprite->setRow(endSprite->getRow());  
    staSprite->setCol(endSprite->getCol());  
    endSprite->setRow(tmpRow);  
    endSprite->setCol(tmpCol);  
      
    staSprite->runAction(Sequence::create(  
                                      MoveTo::create(time, posOfDest),  
                                      MoveTo::create(time, posOfSrc),  
                                      NULL));  
    endSprite->runAction(Sequence::create(  
                                      MoveTo::create(time, posOfSrc),  
                                      MoveTo::create(time, posOfDest),  
                                      NULL));  
}

這裏,再看一下這個函數,

就是先獲取初始精靈和終止精靈的位置,

然後,只是單純在地圖中交換(後臺交換,數組變動,在遊戲界面中還是沒有變動的)

判斷是否可以消除,如果可以消除了,那就執行動作 交換兩個精靈位置。

如果不可以消除,不要忘了把後臺交換過的兩個精靈再交換過來,然後在執行兩個動作(就是交換一次,再交換回來)。

這裏,並不是先交換,再判斷,再執行接下來的動作;

而是,先後臺數組交換,然後判斷,然後執行 交換一次加消除 還是交換兩次動作。


好啦,編寫到這裏,我們可以運行一下,看看效果。

到這,精靈的交換已經完成了。


本章資源和代碼:點擊下載


感謝本文筆者LT大樹_的分享,
Cocos引擎中文官網歡迎更多的開發者分享開發經驗,來稿請發送至[email protected]

來源網址:http://blog.csdn.net/lttree/article/details/43191329

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章