[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中利用双向链表实现无限循环滚动层的更多相关文章

  1. unity 背景无限循环滚动效果

    背景无限循环滚动效果如下示: 步骤如下: 导入背景图片后,设置图片的格式,如下图: 2.图片格式也可以设置是Texture格式,但是Wrap Mode 一定要是Repeat[重复发生]:然后记得App ...

  2. Android实现ViewPager无限循环滚动回绕

     Android实现ViewPager无限循环滚动回绕 Android系统提供的ViewPager标准方式是左右可以自由滑动,但是滑动到最左边的极限位置是第一个page,滑动到最右边的位置是最后一 ...

  3. Android中利用ant进行多渠道循环批量打包

    公司负责Android开发的小伙伴学习能力稍微偏弱,交代给他的自动化打包的任务,弄了好久依然没有成效.无奈只好亲自出手. 没有想到过程很顺利,我完全按照如下文章的步骤进行: 主要参考: Android ...

  4. 详细分析Android viewpager 无限循环滚动图片

    由于最近在忙于项目,就没时间更新博客了,于是趁着周日在房间把最近的在项目中遇到的技术总结下.最近在项目中要做一个在viewpager无限滚动图片的需求,其实百度一下有好多的例子,但是大部分虽然实现了, ...

  5. iOS无限循环滚动scrollview

    经常有园友会问"博主,有没有图片无限滚动的Demo呀?", 正儿八经的图片滚动的Demo我这儿还真没有,今天呢就封装一个可以在项目中直接使用的图片轮播.没看过其他iOS图片无限轮播 ...

  6. 封装一个ViewPager真正的实现图片无限循环滚动带导航点

    效果图: 大家在写项目的过程中常常会碰到须要实现Viewpager里面载入几张图片来循环自己主动轮播的效果,假设不封装一下的话代码分散在activity里面会显得非常乱.并且也不利于我们下次复用,所以 ...

  7. ASP.NET中利用DataList实现图片无缝滚动

    这个问题之前也困扰我,后来解决了,拿出来分享下,以后用也方便,代码很容易看懂,不多说什么了 <div id="demo" style="overflow: hidd ...

  8. Java中利用标签跳出外层循环break

    直接看代码: class ForLoop{ public static void main(String[] args){ //jump from outer loop outer:for(int i ...

  9. iOS开发系列--无限循环的图片浏览器

    --UIKit之UIScrollView 概述 UIKit框架中有大量的控件供开发者使用,在iOS开发中不仅可以直接使用这些控件还可以在这些控件的基础上进行扩展打造自己的控件.在这个系列中如果每个控件 ...

随机推荐

  1. PHP生成静态页面的方法

          在PHP网站开发中为了网站推广和SEO等需要,需要对网站进行全站或局部静态化处理,PHP生成静态HTML页面有多种方法,比如利用PHP模板.缓存 等实现页面静态化,今天就以PHP实例教程形 ...

  2. GET POST 区别详解

    Get是用来从服务器上获得数据,而Post是用来向服务器上传递数据. 2. Get将表单中数据的按照variable=value的形式,添加到action所指向的URL后面,并且两者使用“?”连接,而 ...

  3. 001MSP430概述

    1.MSP430系列单片机的特点 (1)超低功耗:生来就是为超低功耗设计的,从CPU内核结构到片上外设,以及整个芯片的生产制造都是本着超低功耗的原则来进行的,所以是一款实实在在的超低功耗单片机: (2 ...

  4. 实现弹出收回菜单效果ios源码

    REMenu能够提供下弹出来的菜单,跳转到不同的vc后菜单便会收起.菜单的弹收都有回弹(bounce)的效果.效果图: <ignore_js_op> 使用方法: 先把REMenu的文件夹复 ...

  5. CSS 3 中二维三维以及渐变过程简单总结 及效果(动图不好发)

    一. 不动,区域内的变化(本质生产一张图片) /*渐变                 1  长方形之渐变先定义长方形的宽高大小(好观察最好加边框)                           ...

  6. 判断字符串是否包含字母‘k’或者‘K’

    判断字符串是否包含字母‘k’或者‘K’ public bool IsIncludeK(string temp) { temp = temp.ToLower(); if (temp.Contains(' ...

  7. WPF: 读取XPS文件或将word、txt文件转化为XPS文件

    读取XPS格式文件或将doc,txt文件转化为XPS文件,效果图如下: 1.XAML页面代码: <Window x:Class="WpfWord.MainWindow" xm ...

  8. LevelDB源码之五Current文件\Manifest文件\版本信息

    版本信息有什么用?先来简要说明三个类的具体用途: Version:代表了某一时刻的数据库版本信息,版本信息的主要内容是当前各个Level的SSTable数据文件列表. VersionSet:维护了一份 ...

  9. php5.5新函数array_column

    php5.5新增了一个新的数组函数,感觉挺使用的,低版本的实现按照如下实现 if(!function_exists('array_column')){ function array_column($i ...

  10. Noise,Error,wighted pocket Algorithm

    错误衡量(Error Measure) 有两种错误计算方法: 第一种叫0/1错误,只要[预测≠目标]则认为犯错,通常用于分类:通常选择,错误比较大的值作为y˜的值 第二种叫平方错误,它衡量[预测与目标 ...