ccui.ScrollView 扩展
大多数游戏都有背包这个东西.
道具列表通常用 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 扩展的更多相关文章
- cocos js 3.8.1 clippingNode 不能被 ccui.ScrollView 或者ccui.Layout裁剪的bug
clippingNode不能被ccui.ScrollView.ccui.ListView.ccui.Layout裁剪问题,只需要 设置scrollView ...的裁剪类型 scrollView.se ...
- cocos2d js ScrollView的使用方法
游戏中非常多须要用到ScrollView的情况,也就是须要滚动一片区域. 这里有两种实现方法,一种是使用cocos studio的方式,另外一种是手写代码.先看第一种 第一种记得在设置滚动区域时选取裁 ...
- ScrollView示例(转载)
// 初始化var scrollView = new ccui.ScrollView(); // 设置方向scrollView.setDirection(ccui.ScrollView.DIR_VER ...
- cocos2D-X LUA 常用功能封装和工作经验的一些解决方案
--[[ Packaging_KernelEngine.h 文件说明:所有对象在建立时位置是优先的,传入位置参数必须cc.p(X,Y) CurObj:表示要传入当前的对象 将3.10 lua api ...
- 【cocos2d-js公文】十七、事件分发机制
简单介绍 游戏开发中一个非常重要的功能就是交互,假设没有与用户的交互.那么游戏将变成动画,而处理用户交互就须要使用事件监听器了. 总概: 事件监听器(cc.EventListener) 封装用户的事件 ...
- 【cocos2d-js公文】十八、Cocos2d-JS v3.0物业风格API
1. 新的API风格 我们直接来看看你能够怎样使用Cocos2d-JS v3.0: 曾经的API 新的API node.setPosition(x, y); node.x = x; node.y = ...
- React Native之ListView实现九宫格效果
概述 在安卓原生开发中,ListView是很常用的一个列表控件,那么React Native(RN)如何实现该功能呢?我们来看一下ListView的源码 ListView是基于ScrollView扩展 ...
- 【cocos2d-js官方文档】事件分发监听机制(摘录)
简介 游戏开发中一个很重要的功能就是交互,如果没有与用户的交互,那么游戏将变成动画,而处理用户交互就需要使用事件监听器了. 总概: 事件监听器(cc.EventListener) 封装用户的事件处理逻 ...
- cocos jsb工程转html 工程
1 CCBoot.js prepare方法:注掉下面这行,先加载moduleConfig中的脚本后加载user脚本 //newJsList = newJsList.concat(jsList); // ...
随机推荐
- Solr4.4的安装与配置
最近准备用Solr搭建项目,所以对其作了一些了解,我采用的是Solr4.4版本:这个版本的Solr相对于以前的版本改变很大,这里记一下自己安装与配置的过程. 网上很多关于Solr的教程都很老了,很多教 ...
- 【转】Ubuntu下搭建SVN环境-Apache
原文网址:http://www.cnblogs.com/candle806/archive/2012/12/20/2826280.html 环境描述:ubuntu server 12.04 / sv ...
- 游戏开发Camera之Cinematic Camera-深度
人的视觉系统是二维的,它通过生理和心理的暗示来感知图像的深度,在现实世界中视觉系统会自动用深度线索depth cue来确定对象之间的距离游戏画面也是二维的,用x,y轴来定义,画面深度用z轴来定义,可以 ...
- HDU 3507 Print Article(DP+斜率优化)
Print Article Time Limit: 9000/3000 MS (Java/Others) Memory Limit: 131072/65536 K (Java/Others) ...
- poj 3678 Katu Puzzle(Two Sat)
题目链接:http://poj.org/problem?id=3678 代码: #include<cstdio> #include<cstring> #include<i ...
- Java程序员必知的8大排序算法
8种排序之间的关系 直接插入排序 (1)基本思想:在要排序的一组数中,假设前面(n-1)[n>=2] 个数已经是排 好顺序的,现在要把第n个数插到前面的有序数中,使得这n个数 也是排好顺序的.如 ...
- Windows 安装Django并创建第一个应用
学习python 也有一段时间了,语法也学得差不多了,突然就想学一学python的web开源开源框架Django,我用的是Django-1.6.2.tar.gz,可以在官网https://www.dj ...
- 开发期间的GWT设置---加快编译速度
随着项目功能的完善,GWT模块(Module)越来越多,当要以web模式编译给测试组使用时,编译的总时间越来越多,我的机器编译完8个模块,需要10分钟左右. 抽空研究了一下GWT的编译参数和GWT编译 ...
- Android中的FrameLayout帧布局
帧布局由FrameLayout所代表,FrameLayout直接继承了ViewGoup组件. 帧布局容器为每一个增加当中的组件创建一个空白的区域(称为一个帧),每一个子组件占领一帧,这些帧都会依据gr ...
- c++ 字符串流 sstream(常用于格式转换) 分类: C/C++ 2014-11-08 17:20 150人阅读 评论(0) 收藏
使用stringstream对象简化类型转换 C++标准库中的<sstream>提供了比ANSI C的<stdio.h>更高级的一些功能,即单纯性.类型安全和可扩展性.在本文中 ...