首先上效果图:
这个怎么实现的呢,其实就是通过 TouchEvent 事件实现;
ui::Widget::TouchEventType::BEGAN
ui::Widget::TouchEventType::MOVED
ui::Widget::TouchEventType::CANCELED
ui::Widget::TouchEventType::ENDED
协调这4个类型处理,主要逻辑在TouchEventType::MOVED中;通过getTouchBeganPosition获取到起始点,通过getTouchMovePosition获取到当前移动到的位置,统一使用 当前位置的 Y轴,X轴在两点之间每隔10.0f生成一个检测点,检测该点是否存在扑克牌。判断函数代码主要如下:
bool UIHelper::IsSpriteInTouch(cocos2d::Vec2 kWorldPos, cocos2d::Node *pSrite) { kWorldPos = pSrite->convertToNodeSpace(kWorldPos); //转换成节点坐标 cocos2d::Size elementSize = pSrite->getContentSize(); cocos2d::Rect elementRect; cocos2d::Vec2 kAnchor = pSrite->getAnchorPoint(); elementRect = cocos2d::Rect( 0,0, elementSize.width, elementSize.height ); return elementRect.containsPoint(kWorldPos); }
pSrite 为扑克牌的指针,首先将触摸点的坐标,转换成相对于扑克节点的坐标,通过扑克牌的区域构建检测区域,通过containsPoint函数判断检测点是否在扑克牌的区域内。
这里需要注意的是斗地主 除了最后一张扑克以外有很大一部分被遮挡,所有需要根据遮挡部位调整检测的区域。
bool UIHelper::IsSpriteInTouch(cocos2d::Vec2 kWorldPos, cocos2d::Node *pSrite,cocos2d::Size checkSize) { kWorldPos = pSrite->convertToNodeSpace(kWorldPos); //转换成节点坐标 cocos2d::Rect elementRect; elementRect = cocos2d::Rect( 0,0, checkSize.width, checkSize.height ); return elementRect.containsPoint(kWorldPos); }
checkSize 为指定的检测范围。具体代码是下面这个样子:
case ui::Widget::TouchEventType::MOVED: { Vec2 a = pCard->getTouchBeganPosition(); Vec2 b = pCard->getTouchMovePosition(); if (abs(b.x - a.x) > 30) { //出牌判定 m_bMove = true; } //取消状态 ui::Layout *pHandCardNode = dynamic_cast<ui::Layout *>(UIHelper::seekNodeByName(m_pParseNode, "HandCard_0")); const auto &arrayRootChildren = pHandCardNode->getChildren(); for (auto &subWidget : arrayRootChildren) { subWidget->setName(""); UIHelper::seekNodeByName(subWidget, "ColorLayout")->setVisible(false); } float lx = a.x >= b.x ? a.x : b.x; float sx = a.x >= b.x ? b.x : a.x; float by = b.y; while (lx - sx > 10.0f) { //距离10检测一次 lx -= 10.0f; ui::Layout *pTempHandCardNode = dynamic_cast<ui::Layout *>(UIHelper::seekNodeByName(m_pParseNode, "HandCard_0")); const auto &arrayTempRootChildren = pTempHandCardNode->getChildren(); ssize_t lsize = arrayTempRootChildren.size(); for (int i = 0; i < lsize; i++) { ui::Layout *child = dynamic_cast<ui::Layout *>(arrayTempRootChildren.at(i)); Size _cardSize = child->getContentSize(); if (i == lsize - 1) { //最后一张 if (UIHelper::IsSpriteInTouch(Vec2(lx, by), child)) { child->setName("_InTouch_Card_"); UIHelper::seekNodeByName(child, "ColorLayout")->setVisible(true); break; //成功检测后退出 } } else { if (UIHelper::IsSpriteInTouch(Vec2(lx, by), child, Size(m_fBigCardW, _cardSize.height))) { child->setName("_InTouch_Card_"); UIHelper::seekNodeByName(child, "ColorLayout")->setVisible(true); break; //成功检测后退出 } } } } break; }
通过->setName(“_InTouch_Card_”);给扑克打标记,方便触摸结束时候处理;ColorLayout是一层颜色遮罩层,用来给选中的扑克添加底色;
后续的处理代码大致如下:筛选出最终的扑克牌列表,更改Y轴坐标。
case ui::Widget::TouchEventType::CANCELED: case ui::Widget::TouchEventType::ENDED: { if (m_bMove) { ui::Layout *pHandCardNode = dynamic_cast<ui::Layout *>(UIHelper::seekNodeByName(m_pParseNode, "HandCard_0")); const auto &arrayRootChildren = pHandCardNode->getChildren(); BYTE cbRemoveCard[MAX_COUNT]; //移除列表 ZeroMemory(cbRemoveCard, sizeof(cbRemoveCard)); BYTE cbRemoveCardCount = 0; //移除总数 BYTE cbAddCard[MAX_COUNT]; //添加列表 ZeroMemory(cbAddCard, sizeof(cbAddCard)); BYTE cbAddCardCount = 0; //添加总数 for (auto &subWidget : arrayRootChildren) { Node *child = dynamic_cast<Node *>(subWidget); if (child->getName() == "_InTouch_Card_") { //触摸的牌 bool isExist = false; BYTE cbTag = (BYTE) child->getTag(); for (int i = 0; i < m_cbOutCardCount; i++) { isExist = (m_cbOutCardData[i] == cbTag); if (isExist) break; //找到了就退出 } if (isExist) { cbRemoveCard[cbRemoveCardCount++] = cbTag; } else { cbAddCard[cbAddCardCount++] = cbTag; } child->setName(""); } } if (cbRemoveCardCount > 0) { m_pGameClient->m_pGameLogic->RemoveCardList(cbRemoveCard, cbRemoveCardCount, m_cbOutCardData, m_cbOutCardCount); m_cbOutCardCount -= cbRemoveCardCount; //减少数量 } CopyMemory(m_cbOutCardData + m_cbOutCardCount, cbAddCard, cbAddCardCount); m_cbOutCardCount += cbAddCardCount; //牌处理 CCLOG("选中牌的数量:%d,新增牌的数量:%d,移除牌的数量", m_cbOutCardCount, cbAddCardCount, cbRemoveCardCount); ShowSearchCard(m_cbOutCardData, m_cbOutCardCount); return; }
Cocostudio 斗地主滑动选牌实现