要獲取和選中棋子我們需要要在原來LayerGameMain基礎(chǔ)上添加多三個成員變量和六個成員函數(shù)秸苗。幾個函數(shù)和變量間依賴性比較高,大體實(shí)現(xiàn)功能分為:通過棋子id從數(shù)組獲取棋子、通過點(diǎn)擊選中棋子柱宦。
__Array *arrStone;
Sprite *selectBox;
int _selectedId;
Stone* getStoneFromArrById(int id);
int getStoneIdFromRowCol(int row, int col);
bool Screen2Plate(Point &point, int &row, int &col);
Point Plate2Screen(int row, int col);
void selectStone(Touch *pTouch);
這里先直接貼出LayerGameMain.h代碼
#ifndef __LAYERGAMEMAIN_H__
#define __LAYERGAMEMAIN_H__
#include "cocos2d.h"
#include "Plate.h"
#include "Stone.h"
/*
cocos2d-x3.14.1版本將大部分類的前綴CC去掉了总寒,不過有部分還是兼容抽米,如果用舊的命名創(chuàng)建對應(yīng)的類會有警告提示/錯誤提示
*/
USING_NS_CC;
class LayerGameMain : public Layer
{
public:
static Scene* createScene();
virtual bool init();
CREATE_FUNC(LayerGameMain);
//添加棋盤和棋子
void addPlate();//用于在LayerGameMain上添加棋盤層/精靈
void addStones();//用于在LayerGameMain上添加棋子層/精靈
//觸摸事件回調(diào)函數(shù)
bool touchBeganCallBack(Touch *pTouch, Event *pEvent);
void touchEndedCallBack(Touch *pTouch, Event *pEvent);
//選中棋子相關(guān)
Sprite *selectBox;//選中款精靈
int _selectedId;//標(biāo)記當(dāng)前選中的棋子id特占,沒有點(diǎn)中為-1
bool Screen2Plate(Point &point, int &row, int &col);//循環(huán)棋盤上所有點(diǎn),通過Plate2Screen獲取到棋子中心點(diǎn)云茸,用引用輸出中心點(diǎn)
Point Plate2Screen(int row, int col);//獲取棋子中心點(diǎn)返回到世界坐標(biāo)給Screen2Plate
void selectStone(Touch *pTouch);//選中棋子是目,將選中框精靈移動到選中的棋子上
//獲取棋子相關(guān)
__Array *arrStone;//用于存放棋子
Stone* getStoneFromArrById(int id);//通過棋子id從arrStone獲取對應(yīng)棋子
int getStoneIdFromRowCol(int row, int col);//通過行列獲取棋子id
};
#endif // !__LAYERGAMEMAIN_H__
獲取棋子
想要獲取棋子就需要先將它們放進(jìn)一個數(shù)組中管理起來,然后通過一些函數(shù)方法從數(shù)組中取出我們想要的棋子标捺。這里使用的是cocos的數(shù)組類懊纳,也可以用vector存儲。
我們直接上對應(yīng)代碼亡容,因?yàn)樾枰跏蓟瘮?shù)組嗤疯,所以先貼出init函數(shù)
bool LayerGameMain::init()
{
if (!Layer::init())
{
return false;
}
arrStone = __Array::create();
arrStone->retain();//計(jì)數(shù)器+1,否則會被回收
selectBox = Sprite::create("selected.png");
selectBox->setVisible(false);
selectBox->setZOrder(1000);//設(shè)置顯示優(yōu)先級
this->addChild(selectBox);
this->addPlate();
this->addStones();
//cocos2d-x3.14.1觸摸事件闺兢,創(chuàng)建監(jiān)聽
EventDispatcher* eventDispatcher = Director::getInstance()->getEventDispatcher();
auto listener = EventListenerTouchOneByOne::create();
listener->setEnabled(true);
listener->setSwallowTouches(true);
listener->onTouchBegan = CC_CALLBACK_2(LayerGameMain::touchBeganCallBack, this);
listener->onTouchEnded = CC_CALLBACK_2(LayerGameMain::touchEndedCallBack, this);
eventDispatcher->addEventListenerWithSceneGraphPriority(listener, this);
return true;
}
通過id從數(shù)組獲取棋子函數(shù)
Stone* LayerGameMain::getStoneFromArrById(int stoneId)
{
Stone *ret;
ret = nullptr;
if (stoneId > 0)
{
ret = (Stone *)arrStone->getObjectAtIndex(stoneId);
}
return ret;
}
有必要提一下茂缚,棋子數(shù)組初始化后并沒有掛在渲染樹上,一幀之后就會被回收屋谭,這里涉及到內(nèi)存管理計(jì)數(shù)器問題脚囊,我們需要在初始化數(shù)組時讓數(shù)組調(diào)用retain()函數(shù)使計(jì)數(shù)器+1。
選中棋子
當(dāng)我們選中棋子時桐磁,我們希望看到棋子被選中后有所反饋悔耘,那么我們就需要一個選中框精靈重疊在棋子上面以得到我們想要的效果。那么要把選中框重疊在棋子上就必需先知道棋子的行和列我擂,想得到棋子的行列就需要先知道被點(diǎn)擊棋子的中心點(diǎn)衬以,想知道棋子的中心點(diǎn)就必需先知道玩家觸摸點(diǎn)的位置。
這樣我們就可以通過倒著推過去來寫我們需要的函數(shù)校摩。玩家觸摸點(diǎn)的位置可以通過cocos的觸摸事件獲得看峻,棋子中心點(diǎn)可以通過遍歷棋盤上所有的點(diǎn)并通過觸點(diǎn)與棋盤點(diǎn)的距離是否小于半徑判斷是否選中棋盤上的點(diǎn),如果棋盤上的點(diǎn)存在棋子秧耗,那么該點(diǎn)即為棋子中心點(diǎn)备籽,在獲得棋子中心點(diǎn)后可以通過棋子自身屬性獲取棋子的行列位置,通過棋子的行列位置我們可以將其換算成世界坐標(biāo)分井,最后這個世界坐標(biāo)就是我們選中框的位置。
將棋子的相對棋盤坐標(biāo)轉(zhuǎn)換為世界坐標(biāo)
Point LayerGameMain::Plate2Screen(int row, int col)//該函數(shù)與Stone的getPositionFromPlate類似
{
Point ret = Point(Stone::_offx + col*Stone::_d, Stone::_offy + row*Stone::_d);
return ret;
}
遍歷棋盤上所有的點(diǎn)并通過觸點(diǎn)與棋盤點(diǎn)的距離判斷是否選中該點(diǎn)上的棋子霉猛,如果棋盤點(diǎn)上有棋子返回true
bool LayerGameMain::Screen2Plate(Point &point, int &row, int &col)
{
int distance = Stone::_d/2 * Stone::_d/2;//以半徑作為距離
for (row = 0; row <= 9; row++)
{
for (col = 0; col <= 8; col++)
{
Point ptCenter = Plate2Screen(row, col);
if (distance > ptCenter.getDistanceSq(point))//獲取點(diǎn)距的平方并比較尺锚,如果小于半徑平方則為能選中中心點(diǎn)上的棋子
{
return true;
}
}
}
return false;
}
通過棋子行列獲取棋子id,當(dāng)行列上沒有棋子時返回-1
int LayerGameMain::getStoneIdFromRowCol(int row, int col)
{
int ret = -1;
Ref *obj;
CCARRAY_FOREACH(arrStone,obj)
{
Stone *stone = (Stone *)obj;
if (stone->_row == row && stone->_col == col)
{
ret = stone->_id;
return ret;
}
}
return ret;
}
選棋操作
void LayerGameMain::selectStone(Touch *pTouch)
{
Point point = pTouch->getLocation();
int row, col;
if (!Screen2Plate(point, row, col))//點(diǎn)中范圍不在棋盤上直接返回
{
selectBox->setVisible(false);
return;
}
int clickedid = getStoneIdFromRowCol(row, col);
if (clickedid < 0)//沒選中棋子直接返回
{
selectBox->setVisible(false);
return;
}
Stone *clickedStone = getStoneFromArrById(clickedid);
selectBox->setPosition(Plate2Screen(row, col));
selectBox->setVisible(true);
_selectedId = clickedid;//記錄下棋子id
}
最后貼出修改后LayerGameMain的代碼惜浅,頭文件在上面已經(jīng)貼出瘫辩,這里就不再貼出了。
LayerGameMain.cpp
#include "LayerGameMain.h"
Scene* LayerGameMain::createScene()
{
auto ret = Scene::create();
auto layer = LayerGameMain::create();
ret->addChild(layer);
return ret;
}
bool LayerGameMain::init()
{
if (!Layer::init())
{
return false;
}
arrStone = __Array::create();
arrStone->retain();//計(jì)數(shù)器+1,否則會被回收
selectBox = Sprite::create("selected.png");
selectBox->setVisible(false);
selectBox->setZOrder(1000);//設(shè)置顯示優(yōu)先級
this->addChild(selectBox);
this->addPlate();
this->addStones();
//cocos2d-x3.14.1觸摸事件伐厌,創(chuàng)建監(jiān)聽
EventDispatcher* eventDispatcher = Director::getInstance()->getEventDispatcher();
auto listener = EventListenerTouchOneByOne::create();
listener->setEnabled(true);
listener->setSwallowTouches(true);
listener->onTouchBegan = CC_CALLBACK_2(LayerGameMain::touchBeganCallBack, this);
listener->onTouchEnded = CC_CALLBACK_2(LayerGameMain::touchEndedCallBack, this);
eventDispatcher->addEventListenerWithSceneGraphPriority(listener, this);
return true;
}
void LayerGameMain::addPlate()
{
Plate *plate = Plate::create();
this->addChild(plate);
}
void LayerGameMain::addStones()
{
int i = 0;
Stone *stone;
for (i = 0; i < 32; i++)
{
stone = Stone::create(i);
arrStone->addObject(stone);//將棋子添加進(jìn)數(shù)組
this->addChild(stone);
}
}
Stone* LayerGameMain::getStoneFromArrById(int stoneId)
{
Stone *ret;
ret = nullptr;
if (stoneId > 0)
{
ret = (Stone *)arrStone->getObjectAtIndex(stoneId);
}
return ret;
}
bool LayerGameMain::touchBeganCallBack(Touch *pTouch, Event *pEvent)
{
return true;
}
void LayerGameMain::touchEndedCallBack(Touch *pTouch, Event *pEvent)
{
selectStone(pTouch);
}
bool LayerGameMain::Screen2Plate(Point &point, int &row, int &col)
{
int distance = Stone::_d/2 * Stone::_d/2;//以半徑作為距離
for (row = 0; row <= 9; row++)
{
for (col = 0; col <= 8; col++)
{
Point ptCenter = Plate2Screen(row, col);
if (distance > ptCenter.getDistanceSq(point))//獲取點(diǎn)距的平方并比較承绸,如果小于半徑平方則為能選中中心點(diǎn)上的棋子
{
return true;
}
}
}
return false;
}
Point LayerGameMain::Plate2Screen(int row, int col)//該函數(shù)與Stone的getPositionFromPlate類似
{
Point ret = Point(Stone::_offx + col*Stone::_d, Stone::_offy + row*Stone::_d);
return ret;
}
int LayerGameMain::getStoneIdFromRowCol(int row, int col)
{
int ret = -1;
Ref *obj;
CCARRAY_FOREACH(arrStone,obj)
{
Stone *stone = (Stone *)obj;
if (stone->_row == row && stone->_col == col)
{
ret = stone->_id;
return ret;
}
}
return ret;
}
void LayerGameMain::selectStone(Touch *pTouch)
{
Point point = pTouch->getLocation();
int row, col;
if (!Screen2Plate(point, row, col))//點(diǎn)中范圍不在棋盤上直接返回
{
selectBox->setVisible(false);
return;
}
int clickedid = getStoneIdFromRowCol(row, col);
if (clickedid < 0)//沒選中棋子直接返回
{
selectBox->setVisible(false);
return;
}
Stone *clickedStone = getStoneFromArrById(clickedid);
selectBox->setPosition(Plate2Screen(row, col));
selectBox->setVisible(true);
_selectedId = clickedid;//記錄下棋子id
}
運(yùn)行效果: