cocos2d-x3.14中国象棋AI(四)获取棋子和选中棋子

要获取和选中棋子我们需要要在原来LayerGameMain基础上添加多三个成员变量和六个成员函数。几个函数和变量间依赖性比较高,大体实现功能分为:通过棋子id从数组获取棋子、通过点击选中棋子。

__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去掉了,不过有部分还是兼容,如果用旧的命名创建对应的类会有警告提示/错误提示
*/

USING_NS_CC;

class LayerGameMain : public Layer
{
public:
    static Scene* createScene();
    virtual bool init();
    CREATE_FUNC(LayerGameMain);

    //添加棋盘和棋子
    void addPlate();//用于在LayerGameMain上添加棋盘层/精灵
    void addStones();//用于在LayerGameMain上添加棋子层/精灵

    //触摸事件回调函数
    bool touchBeganCallBack(Touch *pTouch, Event *pEvent);
    void touchEndedCallBack(Touch *pTouch, Event *pEvent);

    //选中棋子相关
    Sprite *selectBox;//选中款精灵
    int _selectedId;//标记当前选中的棋子id,没有点中为-1
    bool Screen2Plate(Point &point, int &row, int &col);//循环棋盘上所有点,通过Plate2Screen获取到棋子中心点,用引用输出中心点
    Point Plate2Screen(int row, int col);//获取棋子中心点返回到世界坐标给Screen2Plate
    void selectStone(Touch *pTouch);//选中棋子,将选中框精灵移动到选中的棋子上

    //获取棋子相关
    __Array *arrStone;//用于存放棋子
    Stone* getStoneFromArrById(int id);//通过棋子id从arrStone获取对应棋子
    int getStoneIdFromRowCol(int row, int col);//通过行列获取棋子id
};

#endif // !__LAYERGAMEMAIN_H__

获取棋子

想要获取棋子就需要先将它们放进一个数组中管理起来,然后通过一些函数方法从数组中取出我们想要的棋子。这里使用的是cocos的数组类,也可以用vector存储。

我们直接上对应代码,因为需要初始化数组,所以先贴出init函数

bool LayerGameMain::init()
{
    if (!Layer::init())
    {
        return false;
    }
    arrStone = __Array::create();
    arrStone->retain();//计数器+1,否则会被回收
    selectBox = Sprite::create("selected.png");
    selectBox->setVisible(false);
    selectBox->setZOrder(1000);//设置显示优先级
    this->addChild(selectBox);

    this->addPlate();
    this->addStones();

    //cocos2d-x3.14.1触摸事件,创建监听
    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从数组获取棋子函数

Stone* LayerGameMain::getStoneFromArrById(int stoneId)
{
    Stone *ret;
    ret = nullptr;
    if (stoneId > 0)
    {
        ret = (Stone *)arrStone->getObjectAtIndex(stoneId);
    }
    
    return ret;
}

有必要提一下,棋子数组初始化后并没有挂在渲染树上,一帧之后就会被回收,这里涉及到内存管理计数器问题,我们需要在初始化数组时让数组调用retain()函数使计数器+1。

选中棋子

当我们选中棋子时,我们希望看到棋子被选中后有所反馈,那么我们就需要一个选中框精灵重叠在棋子上面以得到我们想要的效果。那么要把选中框重叠在棋子上就必需先知道棋子的行和列,想得到棋子的行列就需要先知道被点击棋子的中心点,想知道棋子的中心点就必需先知道玩家触摸点的位置。
这样我们就可以通过倒着推过去来写我们需要的函数。玩家触摸点的位置可以通过cocos的触摸事件获得,棋子中心点可以通过遍历棋盘上所有的点并通过触点与棋盘点的距离是否小于半径判断是否选中棋盘上的点,如果棋盘上的点存在棋子,那么该点即为棋子中心点,在获得棋子中心点后可以通过棋子自身属性获取棋子的行列位置,通过棋子的行列位置我们可以将其换算成世界坐标,最后这个世界坐标就是我们选中框的位置。

将棋子的相对棋盘坐标转换为世界坐标

Point LayerGameMain::Plate2Screen(int row, int col)//该函数与Stone的getPositionFromPlate类似
{
    Point ret = Point(Stone::_offx + col*Stone::_d, Stone::_offy + row*Stone::_d);
    
    return ret;
}

遍历棋盘上所有的点并通过触点与棋盘点的距离判断是否选中该点上的棋子,如果棋盘点上有棋子返回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))//获取点距的平方并比较,如果小于半径平方则为能选中中心点上的棋子
            {
                return true;
            }
        }
    }

    return false;
}

通过棋子行列获取棋子id,当行列上没有棋子时返回-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))//点中范围不在棋盘上直接返回
    {
        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的代码,头文件在上面已经贴出,这里就不再贴出了。
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();//计数器+1,否则会被回收
    selectBox = Sprite::create("selected.png");
    selectBox->setVisible(false);
    selectBox->setZOrder(1000);//设置显示优先级
    this->addChild(selectBox);

    this->addPlate();
    this->addStones();

    //cocos2d-x3.14.1触摸事件,创建监听
    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);//将棋子添加进数组
        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))//获取点距的平方并比较,如果小于半径平方则为能选中中心点上的棋子
            {
                return true;
            }
        }
    }

    return false;
}
Point LayerGameMain::Plate2Screen(int row, int col)//该函数与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))//点中范围不在棋盘上直接返回
    {
        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
}

运行效果:

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,214评论 6 481
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,307评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 152,543评论 0 341
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,221评论 1 279
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,224评论 5 371
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,007评论 1 284
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,313评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,956评论 0 259
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,441评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,925评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,018评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,685评论 4 322
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,234评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,240评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,464评论 1 261
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,467评论 2 352
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,762评论 2 345

推荐阅读更多精彩内容

  • 我们在选中棋子之后理所当然就是要移动棋子,要移动棋子我们不知需要知道选中的棋子点信息,还需要知道选中棋子后玩家下一...
    lable阅读 534评论 0 0
  • 有做完上一篇的同学会发现,移动棋子存在很多bug,这也是正常,我们只是写了移动的规则,具体的细节并没有完善,在这一...
    lable阅读 505评论 0 0
  • 我们要通过AI类计算下一步棋该如何走的话就必需让AI获得当前棋盘上棋子的局势、轮到谁执棋等各种棋盘上的信息,而这种...
    lable阅读 1,489评论 1 3
  • 怎样改掉爱说话的毛病? 柏拉图说:理性是灵魂最高贵的因素。如他所说,我这个灵魂注定无法高贵。 认识我的人都知道,我...
    熊宴阅读 5,087评论 2 3
  • !!!!转载请注明作者和本文链接!!!! 最近因为工作内容的变动,要去做后台了,所以就入坑PHP。 在找PHP框架...
    CodingLady阅读 7,646评论 0 0