大多数游戏都有背包这个东西.

道具列表通常用 ScrollView 来实现.

这个ScrollView内部有一个Layout, 滑动都是由移动这个Layout来实现.

道具摆放通常从上往下, 从左到右.

假设你有一个道具数组, 你遍历这个数组来摆放道具.

因为数组长度是已知的, 你可以计算出Layout需要的尺寸, 再把道具摆上去.

这个实现是很容易的. 但是, 如果你提前不知道数组长度, 就是不知道道具数量,

可能随时会添加道具或者删除道具.

因为cocos2dx的坐标系是左下角为原点, 因此动态增加或删除都需要把所有的道具都移动位置,

光移动Layout是不行的.

说了一堆的废话.

 --    增加, 删除.
 function scrollView:beginEditChilds(childWidth, childHeight)
     self.contentSize = self:getContentSize();
     self.childCount = #(self:getChildren());
     self.colCount = math.floor(self.contentSize.width / childWidth);
     self.childWidth = (self.contentSize.width - childWidth * self.colCount) / (self.colCount + ) + childWidth;
     self.childHeight = childHeight;
     self.innerSize = self:getInnerContainerSize();
     self.innerOffsetY = self:getInnerContainerPosition().y + self.innerSize.height - self.contentSize.height;
 end

 function scrollView:endEditChilds()
     local rowCount = math.ceil(self.childCount / self.colCount);
     self.innerSize.height = math.max(self.contentSize.height, rowCount * self.childHeight);
     self:setInnerContainerSize(self.innerSize);
     self:setInnerContainerPosition(
         cc.p(, , self.contentSize.height + self.innerOffsetY - self.innerSize.height)));

     local offsetY = self.innerSize.height - self.childHeight;
     self.childs = self:getChildren();
     , - do
         ) / self.colCount);
         ) % self.colCount);
         local x = col * self.childWidth + self.childWidth * 0.5;
         local y = row * self.childHeight + self.childHeight * 0.5;
         self.childs[i]:setPosition(x, self.innerSize.height - y);
         self.childs[i].__pos = i - ;
     end
 end

 function scrollView:appendChild(child)
     child:setAnchorPoint(cc.p(0.5, 0.5));
     self.childCount = self.childCount + ;
     self:addChild(child);
 end

 function scrollView:deleteChild(child)
     self.childCount = self.childCount - ;
     self:removeChild(child);
 end

scrollView 是指 ccui.ScrollView:create() 返回的对象.

可以通过一个工厂函数给对象扩展成员函数. 这个下面在贴代码.

使用方法就是, 在add, del之前调用 begin, 之后调用end.

begin和end的目的是, 避免每一次 add, del 都要全部排列节点, 并且省去了每次数值计算.

这段代码实现了ccui.ScrollView动态增加|删除子节点.

在end函数里面, 还调整了Layout的坐标, 每次修改不会察觉到Layout的坐标变化.

有些用ccui.ScrollView做城镇地图, 可以缩放, 顶点缩放.

直接缩放Layout会影响拖动效果, 这个问题直接修改引擎或者继承这个对象.

 float Widget::getLeftBoundary() const
 {
     return getPosition().x - getAnchorPoint().x * _contentSize.width * _scaleX;
 }

 float Widget::getBottomBoundary() const
 {
     return getPosition().y - getAnchorPoint().y * _contentSize.height * _scaleY;
 }

 float Widget::getRightBoundary() const
 {
     return getLeftBoundary() + _contentSize.width * _scaleX;
 }

 float Widget::getTopBoundary() const
 {
     return getBottomBoundary() + _contentSize.height * _scaleY;
 }

下面是顶点缩放, 直接缩放Layout会把锚点作为中心,

我们这个缩放也是以锚点作为中心, 但是会缩放的同时移动坐标, 效果就达到了.

 --    获取内容缩放值.
 function scrollView:getInnerContainerScale()
     return self:getInnerContainer():getScale();
 end

 --    获取内容高宽.
 function scrollView:getInnerContainerSize()
     return self:getInnerContainer():getContentSize();
 end

 --    获取内容位置.
 function scrollView:getInnerContainerPosition()
     return cc.p(self:getInnerContainer():getPosition());
 end

 --    坐标转换为内容内部坐标.
 function scrollView:convertToInnerContainer(point)
     return self:getInnerContainer():convertToNodeSpace(point);
 end

 function scrollView:setInnerContainerScale(scale)
     self:getInnerContainer():setScale(scale);
 end

 function scrollView:setInnerContainerSize(size)
     self:getInnerContainer():setContentSize(size);
 end

 --    设置内容位置.
 function scrollView:setInnerContainerPosition(point)
     self:getInnerContainer():setPosition(point);
 end

 --    矫正内容位置.
 function scrollView:adjustmentInnerContainerPosition()
     local curPoint = self:getInnerContainerPosition();
     local viewSize = self:getContentSize();
     local innerSize = self:getInnerContainerSize();
     local curScale = self:getInnerContainerScale();

       end;
       end;
     if curPoint.x < viewSize.width - innerSize.width * curScale then
         curPoint.x = viewSize.width - innerSize.width * curScale;
     end
     if curPoint.y < viewSize.height - innerSize.height * curScale then
         curPoint.y = viewSize.height - innerSize.height * curScale;
     end

     self:setInnerContainerPosition(curPoint);
 end

 --    定点缩放.
 function scrollView:scaleByPoint(worldPoint, scale)
     local function callChildScaleHandler(node, scale)
         for k, child in pairs(node:getChildren()) do
             if child.onScaleHandler then
                 child:onScaleHandler(scale);
             end
             callChildScaleHandler(child, scale);
         end
     end

     local viewSize = self:getContentSize();
     local curScale = self:getInnerContainerScale();
     local localPoint = self:convertToInnerContainer(worldPoint);

     --    计算缩放.
     local newScale = curScale + scale;
     if newScale < 0.5 then newScale = 0.5 end;
       end;

     --    实际增加的缩放值.
     scale = scale - ((curScale + scale) - newScale);
      then
         local diffWidth = localPoint.x * scale;
         local diffHeight = localPoint.y * scale;
         local curPoint = self:getInnerContainerPosition();
         curPoint.x = curPoint.x - diffWidth;
         curPoint.y = curPoint.y - diffHeight;

         self:setInnerContainerScale(newScale);
         self:setInnerContainerPosition(curPoint);
         self:adjustmentInnerContainerPosition();

         callChildScaleHandler(self, newScale);
     end
 end
callChildScaleHandler 这个函数是后来补充上的,因为父节点缩放会导致子节点缩放,地图上摆放房子, 房子上会有名字. scrollView是父节点, 房子摆在上面就是子节点, 房子上的名字也是子节点.如果不做控制, 名字也会跟着缩放, 于是就看不见了, 或者模糊了.然后通过callChildScaleHandler递归调用子节点onScaleHandler函数.子节点在父节点每次缩放时处理这个缩放值.
 function utils.transformScrollView(scrollView)

     --    获取内容缩放值.
     function scrollView:getInnerContainerScale()
         return self:getInnerContainer():getScale();
     end

     --    获取内容高宽.
     function scrollView:getInnerContainerSize()
         return self:getInnerContainer():getContentSize();
     end

     --    获取内容位置.
     function scrollView:getInnerContainerPosition()
         return cc.p(self:getInnerContainer():getPosition());
     end

     --    坐标转换为内容内部坐标.
     function scrollView:convertToInnerContainer(point)
         return self:getInnerContainer():convertToNodeSpace(point);
     end

     function scrollView:setInnerContainerScale(scale)
         self:getInnerContainer():setScale(scale);
     end

     function scrollView:setInnerContainerSize(size)
         self:getInnerContainer():setContentSize(size);
     end

     --    设置内容位置.
     function scrollView:setInnerContainerPosition(point)
         self:getInnerContainer():setPosition(point);
     end

     --    矫正内容位置.
     function scrollView:adjustmentInnerContainerPosition()
         local curPoint = self:getInnerContainerPosition();
         local viewSize = self:getContentSize();
         local innerSize = self:getInnerContainerSize();
         local curScale = self:getInnerContainerScale();

           end;
           end;
         if curPoint.x < viewSize.width - innerSize.width * curScale then
             curPoint.x = viewSize.width - innerSize.width * curScale;
         end
         if curPoint.y < viewSize.height - innerSize.height * curScale then
             curPoint.y = viewSize.height - innerSize.height * curScale;
         end

         self:setInnerContainerPosition(curPoint);
     end

     --    定点缩放.
     function scrollView:scaleByPoint(worldPoint, scale)
         local function callChildScaleHandler(node, scale)
             for k, child in pairs(node:getChildren()) do
                 if child.onScaleHandler then
                     child:onScaleHandler(scale);
                 end
                 callChildScaleHandler(child, scale);
             end
         end

         local viewSize = self:getContentSize();
         local curScale = self:getInnerContainerScale();
         local localPoint = self:convertToInnerContainer(worldPoint);

         --    计算缩放.
         local newScale = curScale + scale;
         if newScale < 0.5 then newScale = 0.5 end;
           end;

         --    实际增加的缩放值.
         scale = scale - ((curScale + scale) - newScale);
          then
             local diffWidth = localPoint.x * scale;
             local diffHeight = localPoint.y * scale;
             local curPoint = self:getInnerContainerPosition();
             curPoint.x = curPoint.x - diffWidth;
             curPoint.y = curPoint.y - diffHeight;

             self:setInnerContainerScale(newScale);
             self:setInnerContainerPosition(curPoint);
             self:adjustmentInnerContainerPosition();

             callChildScaleHandler(self, newScale);
         end
     end

     --    将内容位置移至中心.
     function scrollView:lockByPoint(point, isFade)
         local viewSize = self:getContentSize();
         , viewSize.height / );
         local curPoint = self:getInnerContainerPosition();
         curPoint.x = curPoint.x - (curPoint.x + point.x - viewCenter.width);
         curPoint.y = curPoint.y - (curPoint.y + point.y - viewCenter.height);

         if isFade then
             --    这里可以实现一个移动动画.
         else
             self:setInnerContainerPosition(curPoint);
             self:adjustmentInnerContainerPosition();
         end
     end

     --    增加, 删除.
     function scrollView:beginEditChilds(childWidth, childHeight)
         self.contentSize = self:getContentSize();
         self.childCount = #(self:getChildren());
         self.colCount = math.floor(self.contentSize.width / childWidth);
         self.childWidth = (self.contentSize.width - childWidth * self.colCount) / (self.colCount + ) + childWidth;
         self.childHeight = childHeight;
         self.innerSize = self:getInnerContainerSize();
         self.innerOffsetY = self:getInnerContainerPosition().y + self.innerSize.height - self.contentSize.height;
     end

     function scrollView:endEditChilds()
         local rowCount = math.ceil(self.childCount / self.colCount);
         self.innerSize.height = math.max(self.contentSize.height, rowCount * self.childHeight);
         self:setInnerContainerSize(self.innerSize);
         self:setInnerContainerPosition(
             cc.p(, , self.contentSize.height + self.innerOffsetY - self.innerSize.height)));

         local offsetY = self.innerSize.height - self.childHeight;
         self.childs = self:getChildren();
         , - do
             ) / self.colCount);
             ) % self.colCount);
             local x = col * self.childWidth + self.childWidth * 0.5;
             local y = row * self.childHeight + self.childHeight * 0.5;
             self.childs[i]:setPosition(x, self.innerSize.height - y);
             self.childs[i].__pos = i - ;
         end
     end

     function scrollView:appendChild(child)
         child:setAnchorPoint(cc.p(0.5, 0.5));
         self.childCount = self.childCount + ;
         self:addChild(child);
     end

     function scrollView:deleteChild(child)
         self.childCount = self.childCount - ;
         self:removeChild(child);
     end

 end

这是完整的代码. 全部函数封装在utils.transformScrollView工厂函数中.

这里面还少了一个手势缩放的功能.

这个功能只有城镇会用到, 所以我把它单独移出来.

同样的, 写一个独立的工厂函数, 为scrollView扩展.

 function utils.transformScaleScrollView(parent, scrollView)
     local touchs = {};
     ;
     local function onTouchBegan(touch, event)
         local touchId = touch:getId();
         local point = touch:getLocation();
         ] == nil then
             touchs[] = {id = touchId, point = point};
         ] == nil then
             touchs[] = {id = touchId, point = point};
             preDistance = cc.pGetDistance(touchs[].point, touchs[].point);
         end
         ] ].id ] ].id;
     end

     local function onTouchMoved(touch, event)
         local touchId = touch:getId();
         ].id then
             touchs[].point = touch:getLocation();
         else
             touchs[].point = touch:getLocation();
         end

         ] ] then
             ].point, touchs[].point);
             local diff = distance - preDistance;
             local curScale = scrollView:getInnerContainerScale();
             ].point, touchs[].point);
             scrollView:scaleByPoint(lockPos, diff * 0.0025);
             preDistance = distance;
         end
     end

     local function onTouchEnded(touch, event)
         local touchId = touch:getId();
         ].id == touchId then
             touchs[] = touchs[];
         end
         touchs[] = nil;
     end

     --    手指点击缩放.
     local listener = cc.EventListenerTouchOneByOne:create();
     listener:registerScriptHandler(onTouchBegan, cc.Handler.EVENT_TOUCH_BEGAN);
     listener:registerScriptHandler(onTouchMoved, cc.Handler.EVENT_TOUCH_MOVED);
     listener:registerScriptHandler(onTouchEnded, cc.Handler.EVENT_TOUCH_ENDED);
     listener:registerScriptHandler(onTouchEnded, cc.Handler.EVENT_TOUCH_CANCELLED);
     cc.Director:getInstance():getEventDispatcher():addEventListenerWithSceneGraphPriority(listener, parent);
 end

原理很简单, 确定两点,

已两点的中心为缩放点,

已当前移动的距离和上次移动的距离只差为缩放值, 这个缩放值可能有点大, 我把它乘以 0.0025, 效果刚刚好.

然后就可以实现海盗旗兵那种手势缩放效果了...

 

												

ccui.ScrollView 扩展的更多相关文章

  1. cocos js 3.8.1 clippingNode 不能被 ccui.ScrollView 或者ccui.Layout裁剪的bug

    clippingNode不能被ccui.ScrollView.ccui.ListView.ccui.Layout裁剪问题,只需要 设置scrollView ...的裁剪类型 scrollView.se ...

  2. cocos2d js ScrollView的使用方法

    游戏中非常多须要用到ScrollView的情况,也就是须要滚动一片区域. 这里有两种实现方法,一种是使用cocos studio的方式,另外一种是手写代码.先看第一种 第一种记得在设置滚动区域时选取裁 ...

  3. ScrollView示例(转载)

    // 初始化var scrollView = new ccui.ScrollView(); // 设置方向scrollView.setDirection(ccui.ScrollView.DIR_VER ...

  4. cocos2D-X LUA 常用功能封装和工作经验的一些解决方案

    --[[ Packaging_KernelEngine.h 文件说明:所有对象在建立时位置是优先的,传入位置参数必须cc.p(X,Y) CurObj:表示要传入当前的对象 将3.10 lua api ...

  5. 【cocos2d-js公文】十七、事件分发机制

    简单介绍 游戏开发中一个非常重要的功能就是交互,假设没有与用户的交互.那么游戏将变成动画,而处理用户交互就须要使用事件监听器了. 总概: 事件监听器(cc.EventListener) 封装用户的事件 ...

  6. 【cocos2d-js公文】十八、Cocos2d-JS v3.0物业风格API

    1. 新的API风格 我们直接来看看你能够怎样使用Cocos2d-JS v3.0: 曾经的API 新的API node.setPosition(x, y); node.x = x; node.y = ...

  7. React Native之ListView实现九宫格效果

    概述 在安卓原生开发中,ListView是很常用的一个列表控件,那么React Native(RN)如何实现该功能呢?我们来看一下ListView的源码 ListView是基于ScrollView扩展 ...

  8. 【cocos2d-js官方文档】事件分发监听机制(摘录)

    简介 游戏开发中一个很重要的功能就是交互,如果没有与用户的交互,那么游戏将变成动画,而处理用户交互就需要使用事件监听器了. 总概: 事件监听器(cc.EventListener) 封装用户的事件处理逻 ...

  9. cocos jsb工程转html 工程

    1 CCBoot.js prepare方法:注掉下面这行,先加载moduleConfig中的脚本后加载user脚本 //newJsList = newJsList.concat(jsList); // ...

随机推荐

  1. java基础(七)面向对象(二)

    这里有我之前上课总结的一些知识点以及代码大部分是老师讲的笔记 个人认为是非常好的,,也是比较经典的内容,真诚的希望这些对于那些想学习的人有所帮助! 由于代码是分模块的上传非常的不便.也比较多,讲的也是 ...

  2. ACM1228_STL的应用

    #include<iostream> #include<string> #include<map> using namespace std; map<stri ...

  3. zabbix web场景模拟监控配置

    一,zabbix2.2.3 VMware Vsphere exsi监控配置步骤, 1,添加监控主机 2,添加聚集macro;{$PASSWORD} = yoodo.com{$URL} = http:/ ...

  4. hdoj 2524 矩形A + B【递推】

    矩形A + B Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Sub ...

  5. 正经学C#_变量与其转换:《c#入门经典》

    上一节上了变量.末尾简单了说了下 命名方式,声明变量. 命名方式在C#,或者任何语言都是非常重要的一门学问.值得去深入思考一下.变量名的优化与其工作效率的提升,有很多大的关系的. 声明变量,上节介绍了 ...

  6. python_list和tuple互转

    Python中,tuple和list均为内置类型, 以list作为参数将tuple类初始化,将返回tuple类型 tuple([1,2,3,4]) list->tuple 以tuple做为参数, ...

  7. IOS 多个ImageView图片层叠透明区域点击事件穿透

    经常用到多个透明图片层叠,但又需要获取不同图片的点击事件,本文实现图片透明区域穿透点击事件 实现人体各个部位点击 - (BOOL) pointInside:(CGPoint)point withEve ...

  8. 构建ASP.NET MVC4+EF5+EasyUI+Unity2.x注入的后台管理系统(4)-构建项目解决方案 创建EF DataBase Frist模式

    原文:构建ASP.NET MVC4+EF5+EasyUI+Unity2.x注入的后台管理系统(4)-构建项目解决方案 创建EF DataBase Frist模式 进行本次文章之前,我们可能需要补充一些 ...

  9. 对vpn的认识

    网上关于vpn的资料非常多,看后眼花缭乱,仍然感觉一片混沌.网上,网下參考一些资料后.试着理清一些概念问题,由于,概念理清了,找到门了,才不至于左右徘徊,一片混沌. 首先vpn,这个我们都知道叫虚拟专 ...

  10. Systemtap kernel.trace("*") events source code

    http://blog.163.com/digoal@126/blog/static/16387704020131014562216/