[Qboy原创]
在Cocos2dX 3.0
中已经实现一些牛逼的滚动层,但是对于有一些需要实现循环滚动的要求确没有实现,笔者在前段时间的一个做了一个游戏,需求是实现在少有的(13个)英雄中进行循环滚动层,即用户可以无限的向一个方向滚动,当到最后时,由前面的进行重复出现。
如下图:
为了满足以上需求,我第一反应就想到了采用大学数据结构中所学的双向链表。想想还真称靠谱诶。那就说干就干吧。
1、定义双向链接表结构:
struct CycNode{//构建双向链表结构
CycNode* preNode;//前一个节点
cocos2d::gui::ImageView* node; //所对应的Node
CycNode* nextNode;//后一个节点
};
2、定义回调函数
由于在本游戏中拖拽还有一些事件,所以需要向外暴露一些事件。定义如下:
class CycScrollDelegate{
public:
virtual void dragBeginNode(cocos2d::Node*
node,cocos2d::Touch* touch) = 0; //开始拖拽时拖拽的节点
virtual void dragMoveNode(cocos2d::Node*
node,cocos2d::Touch* touch) = 0; //拖拽移动时拖拽的节点
virtual void dragEndNode(cocos2d::Node* node,cocos2d::Touch*
touch) = 0; //拖拽结束后拖拽的节点
其实以上事件都会在层的Touch事件中实现
3、定义实现类
.h文件:
class CycScrollView:public cocos2d::gui::Widget{
CC_SYNTHESIZE(float, scrollHeight,
ScrollHeight);//设置滚动时的高度限制 CC_SYNTHESIZE(CycScrollDelegate*, owerner,
Owerner);
private:
CycNode* pFirstCycNode;
cocos2d::Node* selNode;
Size winSize;
bool canScroll;
virtual void onExit();
virtual bool init();
CREATE_FUNC(CycScrollView);
public:
void
loadScrollView(std::vector<cocos2d::gui::ImageView*> listNode);
//真实加载循环滚动条中的Vector文件
.cpp 文件
(1)实现双向链表,并将双向链表构成环状
for (cocos2d::gui::ImageView* n: listNode)
{//定义成双向链表节点
CycNode* cycnode = new CycNode();
cycnode->node = n;
n->setUserData(&cycnode);//将节点反向回双向链表
cycnode->preNode = pcycNode;
if(pcycNode){
pcycNode->nextNode =
cycnode;
}
pcycNode = cycnode;
if(pFirstNode==NULL){
pFirstNode =
}
(2)将节点设定相应的锚点和坐标,并添加到Widge上
int index=0;
for (cocos2d::gui::ImageView* n: listNode) {
n->setAnchorPoint(Point::ZERO);
n->setPosition(Point(index*C_WIDTH,0));
addChild(n);
index++;
canScroll =
C_WIDTH*listNode.size()>winSize.width;//设定是否需要循环滚动,如果小于可视化大小的话,则不需要滚动。
(3)注册页面的Touch事件,回调相应的Touch事件。
auto listener =
EventListenerTouchOneByOne::create();
listener->setSwallowTouches(true);
listener->onTouchBegan = [this](Touch*
touch,Event* e){
curPoint =
touch->getLocation();
convertToNodeSpace(curPoint);
selNode = nullptr;
if(owerner){
CycNode* pcurNode =
pFirstCycNode;
do {
Size
nodeSize = pcurNode->node->getSize();
Point p =
pcurNode->node->getPosition();
Rect r =
Rect(p.x, p.y, nodeSize.width, nodeSize.height);
if(r.containsPoint(curPoint)){
selNode = pcurNode->node;
owerner->dragBeginNode(pcurNode->node, touch);
break;
}
pcurNode=pcurNode->nextNode;
} while
(pcurNode!=pFirstCycNode);
if(curPoint.y>0&&curPoint.y<scrollHeight){
return true;
return false;
};
listener->onTouchMoved = [this](Touch*
if(!canScroll){
return;
Point newPoint =
newPoint =
convertToNodeSpace(newPoint);
float deltaX =
newPoint.x-curPoint.x;
CycNode* pmoveFirst = NULL;
CycNode* pcurNode =
this->pFirstCycNode;
int index = 0;
float y;
if(deltaX<0){//向左移
float maxX = 0;
Point
nPoint = (pcurNode->node)->getPosition();
float preX
= nPoint.x;
if(preX>maxX&&preX<=winSize.width){
pmoveFirst = pcurNode;
maxX = preX;
y=nPoint.y;
index++;
pcurNode =
pcurNode->nextNode;
}while
pmoveFirst->nextNode->node->setPosition(Point(maxX+C_WIDTH,y));
if(deltaX>0){//向右移
float minX = 1200;
float y;
if(preX<minX&&preX>=0){
minX = preX;
pmoveFirst->preNode->node->setPosition(Point(minX-C_WIDTH,y));
if(pmoveFirst){
pcurNode=pmoveFirst;
float newX
= nPoint.x+deltaX;
(pcurNode->node)->setPosition(Point(newX,y));
(pcurNode!=pmoveFirst);
if(owerner&&selNode){
owerner->dragMoveNode(selNode, touch);
curPoint = newPoint;
listener->onTouchEnded=[this](Touch*
touch,Event*){
owerner->dragEndNode(selNode, touch);
listener->onTouchCancelled=[this](Touch*
_eventDispatcher->addEventListenerWithSceneGraphPriority(listener, this);
4、后续
在本例已大体体现了需求,如果有需要比如上下滚动的可以相应的进行调整修改,其他的需求进行酌情进行增减。另外,在本例中也没有实现IOS中滚动层滚动手势加速功能(目前也还没有想好,有思路的朋友可以告诉我哦)。