cocos2d-x 3.2 之 三消類遊戲——萬聖大作戰 (第三篇),cocos2d-x三消
***************************************轉載請註明出處:http://blog.csdn.net/lttree********************************************
這是第三篇了,
前面已經建立了介面,建立的精靈,並且能自動消除精靈。
現在就要做我們的觸摸事件了
本文內容:
> 實現觸摸事件
> 實現交換的功能
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));}
這裡,在看一下這個函數,
就是先擷取 初始精靈 和 終止精靈 的位置,
然後,只是單純在地圖中交換(後台交換,數組變動,在遊戲介面中還是沒有變動的)
判斷是否可以消除,如果可以消除了,那就執行動作 交換兩個精靈位置。
如果不可以消除,不要忘了把後台交換過的兩個精靈再交換過來,然後在執行兩個動作(就是交換一次,再交換回來)。
這裡,並不是先交換,再判斷,再執行接下來的動作;
而是,先後台數組交換,然後判斷,然後執行 交換一次加消除 還是 交換兩次動作。
好啦,編寫到這裡,我們可以運行一下,看看效果。
到這,精靈的交換已經完成了。
本文的代碼: >這裡 <
***************************************轉載請註明出處:http://blog.csdn.net/lttree********************************************