[Qboy原創]node
在Cocos2dX 3.0 中已經實現一些牛逼的滾動層,可是對於有一些須要實現循環滾動的要求確沒有實現,筆者在前段時間的一個作了一個遊戲,需求是實如今少有的(13個)英雄中進行循環滾動層,即用戶能夠無限的向一個方向滾動,當到最後時,由前面的進行重複出現。數據結構
以下圖:函數
爲了知足以上需求,我第一反應就想到了採用大學數據結構中所學的雙向鏈表。想一想還真稱靠譜誒。那就說幹就幹吧。ui
一、定義雙向連接表結構:this
struct CycNode{//構建雙向鏈表結構spa
CycNode* preNode;//前一個節點blog
cocos2d::gui::ImageView* node; //所對應的Node遊戲
CycNode* nextNode;//後一個節點 事件
};get
二、定義回調函數
因爲在本遊戲中拖拽還有一些事件,因此須要向外暴露一些事件。定義以下:
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事件中實現
三、定義實現類
.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;
public:
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 = cycnode;
}
}
(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();
curPoint = 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* touch,Event* e){
if(!canScroll){
return;
}
Point newPoint = touch->getLocation();
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;
do {
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 (pcurNode!=pFirstCycNode);
pmoveFirst->nextNode->node->setPosition(Point(maxX+C_WIDTH,y));
}
if(deltaX>0){//向右移
float minX = 1200;
float y;
do {
Point nPoint = (pcurNode->node)->getPosition();
float preX = nPoint.x;
if(preX<minX&&preX>=0){
pmoveFirst = pcurNode;
minX = preX;
y=nPoint.y;
}
index++;
pcurNode = pcurNode->nextNode;
}while (pcurNode!=pFirstCycNode);
pmoveFirst->preNode->node->setPosition(Point(minX-C_WIDTH,y));
}
if(pmoveFirst){
pcurNode=pmoveFirst;
do {
Point nPoint = (pcurNode->node)->getPosition();
float newX = nPoint.x+deltaX;
(pcurNode->node)->setPosition(Point(newX,y));
pcurNode = pcurNode->nextNode;
}while (pcurNode!=pmoveFirst);
}
if(owerner&&selNode){
owerner->dragMoveNode(selNode, touch);
}
curPoint = newPoint;
};
listener->onTouchEnded=[this](Touch* touch,Event*){
Point newPoint = touch->getLocation();
newPoint = convertToNodeSpace(newPoint);
if(owerner&&selNode){
owerner->dragEndNode(selNode, touch);
}
};
listener->onTouchCancelled=[this](Touch* touch,Event*){
Point newPoint = touch->getLocation();
newPoint = convertToNodeSpace(newPoint);
if(owerner&&selNode){
owerner->dragEndNode(selNode, touch);
}
};
_eventDispatcher->addEventListenerWithSceneGraphPriority(listener, this);
四、後續
在本例已大致體現了需求,若是有須要好比上下滾動的能夠相應的進行調整修改,其餘的需求進行酌情進行增減。另外,在本例中也沒有實現IOS中滾動層滾動手勢加速功能(目前也尚未想好,有思路的朋友能夠告訴我哦)。