Cocos2dx中利用双向链表实现无限循环滚动层
[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;
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);
4、后续
在本例已大体体现了需求,如果有需要比如上下滚动的可以相应的进行调整修改,其他的需求进行酌情进行增减。另外,在本例中也没有实现IOS中滚动层滚动手势加速功能(目前也还没有想好,有思路的朋友可以告诉我哦)。
Cocos2dx中利用双向链表实现无限循环滚动层的更多相关文章
- unity 背景无限循环滚动效果
背景无限循环滚动效果如下示: 步骤如下: 导入背景图片后,设置图片的格式,如下图: 2.图片格式也可以设置是Texture格式,但是Wrap Mode 一定要是Repeat[重复发生]:然后记得App ...
- Android实现ViewPager无限循环滚动回绕
Android实现ViewPager无限循环滚动回绕 Android系统提供的ViewPager标准方式是左右可以自由滑动,但是滑动到最左边的极限位置是第一个page,滑动到最右边的位置是最后一 ...
- Android中利用ant进行多渠道循环批量打包
公司负责Android开发的小伙伴学习能力稍微偏弱,交代给他的自动化打包的任务,弄了好久依然没有成效.无奈只好亲自出手. 没有想到过程很顺利,我完全按照如下文章的步骤进行: 主要参考: Android ...
- 详细分析Android viewpager 无限循环滚动图片
由于最近在忙于项目,就没时间更新博客了,于是趁着周日在房间把最近的在项目中遇到的技术总结下.最近在项目中要做一个在viewpager无限滚动图片的需求,其实百度一下有好多的例子,但是大部分虽然实现了, ...
- iOS无限循环滚动scrollview
经常有园友会问"博主,有没有图片无限滚动的Demo呀?", 正儿八经的图片滚动的Demo我这儿还真没有,今天呢就封装一个可以在项目中直接使用的图片轮播.没看过其他iOS图片无限轮播 ...
- 封装一个ViewPager真正的实现图片无限循环滚动带导航点
效果图: 大家在写项目的过程中常常会碰到须要实现Viewpager里面载入几张图片来循环自己主动轮播的效果,假设不封装一下的话代码分散在activity里面会显得非常乱.并且也不利于我们下次复用,所以 ...
- ASP.NET中利用DataList实现图片无缝滚动
这个问题之前也困扰我,后来解决了,拿出来分享下,以后用也方便,代码很容易看懂,不多说什么了 <div id="demo" style="overflow: hidd ...
- Java中利用标签跳出外层循环break
直接看代码: class ForLoop{ public static void main(String[] args){ //jump from outer loop outer:for(int i ...
- iOS开发系列--无限循环的图片浏览器
--UIKit之UIScrollView 概述 UIKit框架中有大量的控件供开发者使用,在iOS开发中不仅可以直接使用这些控件还可以在这些控件的基础上进行扩展打造自己的控件.在这个系列中如果每个控件 ...
随机推荐
- 深入理解ASP.NET的内部运行机制(转)
WebForms和WebServices作为.NET平台构建Web程序的两大利器,以其开发简单.易于部署的特点得到了广泛的应用,但殊不知微软公司在背后为我们做了大量的基础性工作,以至于我们开发人员只需 ...
- JS常用的设计模式(9)——策略模式
策略模式的意义是定义一系列的算法,把它们一个个封装起来,并且使它们可相互替换.一个小例子就能让我们一目了然. 回忆下jquery里的animate方法. $( div ).animate( {&quo ...
- JAVA嵌入运行Groovy脚本
摘自: http://shift-alt-ctrl.iteye.com/blog/1938238 . 最近设计一个数据统计系统,系统中上百种数据统计维度,而且这些数据统计的指标可能随时会调整.如果基于 ...
- Java移位运算
java中移位运算符有三种“<<”.“>>”.“>>>”,没有“<<<”运算符. “<<”运算符将二进制位进行左移,低位用0来填 ...
- Android IOS WebRTC 音视频开发总结(五七)-- 网络传输上的一种QoS方案
本文主要介绍一种QoS的解决方案,文章来自博客园RTC.Blacker,欢迎关注微信公众号blacker,更多详见www.rtc.help QoS出现的背景: 而当网络发生拥塞的时候,所有的数据流都有 ...
- javaSE第十三天
第十三天 76 1. StringBuffer(掌握) 76 (1)说明: 77 (2)StringBuffer的构造方法 77 (3)StringBuffer的常见功能 ...
- void指针(void*)用法
首先看一段测试代码: #include <stdio.h> int void_test(void* data) { ; num = *(int*)data; printf("nu ...
- JAVA编程思想第一题出现错误
//: object/E01_DefaultInitialization.java public class E01_DefaultInitialization{ int i ; char c ; p ...
- kickstart简介 20140707
kickstart是红帽发行版中的一种安装方式,它通过以配置文件的方式来记录linux系统安装是的各项参数和想要安装的软件.只要配置正确, 整个安装过程中无需人工交互参与,达到无人值守安装的目的,因而 ...
- iOS中UIKit——UIButton设置边框
UIButton *testButton = [UIButton buttonWithType:UIButtonTypeSystem]; [testButton setFrame:CGRectMake ...