原文请猛戳:
http://galoisplusplus.coding....
承接上一篇,这篇主要谈谈本渣在quickx用的一些脚本或自己折腾的一些定制,本文也将不时更新。
如无特殊说明,相关函数放在一个MyPackage
的lua global table中:
MyPackage = MyPackage or {}
UI组件
滚动列表相关
--[[-- Refresh UIListView at the current postion. NOTE: only needed in async mode ]] function MyPackage.refreshUIListView(listView) if not listView.bAsyncLoad then listView:reload() return end if #listView.items_ <= 0 then listView:reload() return end local originPos = MyPackage.getOriginPosOfUIListView(listView) -- index of the prevIoUs beginning item local beginIdx = listView.items_[1].idx_ listView:removeAllItems() listView.container:setPosition(0,0) listView.container:setContentSize(cc.size(0,0)) MyPackage.drawUIListViewFromIdx(listView,beginIdx,originPos.x,originPos.y) end --[[-- NOTE: only needed in async mode ]] function MyPackage.getOriginPosOfUIListView(listView) if not listView.bAsyncLoad then return end local getContainerCascadeBoundingBox = function (listView) local boundingBox for i,item in ipairs(listView.items_) do local w,h = item:getItemSize() local x,y = item:getPosition() local anchor = item:getAnchorPoint() x = x - anchor.x * w y = y - anchor.y * h if boundingBox then boundingBox = cc.rectUnion(boundingBox,cc.rect(x,y,w,h)) else boundingBox = cc.rect(x,h) end end local point = listView.container:convertToWorldSpace(cc.p(boundingBox.x,boundingBox.y)) boundingBox.x = point.x boundingBox.y = point.y return boundingBox end local cascadeBound = getContainerCascadeBoundingBox(listView) -- local cascadeBound = listView.scrollNode:getCascadeBoundingBox() local localPos = listView:convertToNodeSpace(cc.p(cascadeBound.x,cascadeBound.y)) local originPosX = 0 local originPosY = 0 if cc.ui.UIScrollView.DIRECTION_VERTICAL == listView.direction then -- ahead part of view originPosY = localPos.y + cascadeBound.height - listView.viewRect_.y - listView.viewRect_.height else -- left part of view originPosX = - listView.viewRect_.x + localPos.x end return cc.p(originPosX,originPosY) end --[[-- Draw UIListView from the `beginIdx`th item at position (`originPosX`,`originPosY`). NOTE: only needed in async mode ]] function MyPackage.drawUIListViewFromIdx(listView,originPosX,originPosY) if not listView.bAsyncLoad then listView:reload() return end listView:removeAllItems() listView.container:setPosition(0,0)) local beginIdx = beginIdx or 1 local originPosX = originPosX or 0 local originPosY = originPosY or 0 local count = listView.delegate_[cc.ui.UIListView.DELEGATE](listView,cc.ui.UIListView.COUNT_TAG) listView.items_ = {} local itemW,itemH = 0,0 local item local containerW,containerH = 0,0 for i = beginIdx,count do item,itemW,itemH = listView:loadOneItem_(cc.p(originPosX,originPosY),i) if cc.ui.UIScrollView.DIRECTION_VERTICAL == listView.direction then originPosY = originPosY - itemH containerH = containerH + itemH else originPosX = originPosX + itemW containerW = containerW + itemW end if containerW > listView.viewRect_.width + listView.redundancyViewVal or containerH > listView.viewRect_.height + listView.redundancyViewVal then break end end if cc.ui.UIScrollView.DIRECTION_VERTICAL == listView.direction then listView.container:setPosition(listView.viewRect_.x,listView.viewRect_.y + listView.viewRect_.height) else listView.container:setPosition(listView.viewRect_.x,listView.viewRect_.y) end listView:increaSEOrReduceItem_() end function MyPackage.elasticMoveUIScrollView(scrollView,scrollToBottom,scrollToRight) local cascadeBound = scrollView:getScrollNodeRect() local disX,disY = 0,0 local viewRect = scrollView:getViewRectInWorldSpace() if cascadeBound.width < viewRect.width then if scrollToRight then disX = viewRect.x + viewRect.width - cascadeBound.x - cascadeBound.width else disX = viewRect.x - cascadeBound.x end else if cascadeBound.x > viewRect.x then disX = viewRect.x - cascadeBound.x elseif cascadeBound.x + cascadeBound.width < viewRect.x + viewRect.width then disX = viewRect.x + viewRect.width - cascadeBound.x - cascadeBound.width end end if cascadeBound.height < viewRect.height then if scrollToBottom then disY = viewRect.y - cascadeBound.y else disY = viewRect.y + viewRect.height - cascadeBound.y - cascadeBound.height end else if cascadeBound.y > viewRect.y then disY = viewRect.y - cascadeBound.y elseif cascadeBound.y + cascadeBound.height < viewRect.y + viewRect.height then disY = viewRect.y + viewRect.height - cascadeBound.y - cascadeBound.height end end if 0 == disX and 0 == disY then return end local posX,posY = scrollView.scrollNode:getPosition() scrollView.position_ = cc.p(posX + disX,posY + disY) scrollView.scrollNode:setPosition(scrollView.position_) end
更新:以上改动已挪到yszheda/quickx-extensions的UIScrollView或UIListView中。
lua语言相关
bool转数字
function MyPackage.bool2number(bool) return bool and 1 or 0 end
table相关
function MyPackage.removeValueFromArray(array,value) local idx for i,v in ipairs(array) do if v == value then idx = i break end end if idx then table.remove(array,idx) end end function MyPackage.hasValueInArray(array,value) local hasValue = false for i,v in ipairs(array) do if v == value then hasValue = true break end end return hasValue end
UTF8字符串
cocos2d-x的label默认为UTF8编码,一般场景下主要需要以下两个功能:
字符串长度
截取子串
原先本渣用cocos2d-x时写了个C++函数来求长度:
long long utf8StringSize(const std::string& str) { char* charArray = new char[str.length() + 1]; strcpy(charArray,str.c_str()); char* s = charArray; /*----------------------------------------------------------------------------- * References: http://stackoverflow.com/questions/4063146/getting-the-actual-length-of-a-utf-8-encoded-stdstring *-----------------------------------------------------------------------------*/ long long len = 0; while (*s) len += (*s++ & 0xc0) != 0x80; delete [] charArray; return len; }
cocos2d-x Helper
也提供了接口来做字符串截取:
static std::string getSubStringOfUTF8String(const std::string& str,std::string::size_type start,std::string::size_type length);
在lua方面,quickx已经提供string.utf8len
来求字符串长度,本渣仿照其实现写了个截取子串的函数:
function MyPackage.utf8str(str,start,num) local function utf8CharSize(char) local size = 0 local arr = {0,0xc0,0xe0,0xf0,0xf8,0xfc} local size = #arr while arr[size] do if char >= arr[size] then break end size = size - 1 end return size end local startIdx = 1 while start > 1 do local char = string.byte(str,startIdx) startIdx = startIdx + utf8CharSize(char) start = start - 1 end local endIdx = startIdx while num > 0 do if endIdx > #str then endIdx = #str break end local char = string.byte(str,endIdx) endIdx = endIdx + utf8CharSize(char) num = num - 1 end return str:sub(startIdx,endIdx - 1) end
不过目前lua5.3已经有UTF8库,可以不用自行造轮子了。另外,关于其他UTF8相关的lua问题可以参考Lua Unicode。
其他Helper Functions
更新view的callbackWrapper
我们经常碰到如下的情景:
游戏向后端请求数据,在拿到数据之后执行某个callback去更新某个view。
这种网络请求通常是异步的,如果所请求的数据回来时相关的view被释放,则执行操作该view的callback会导致问题(例如访问非法内存地址)。
这时候我们可以用tolua.isnull
来判断相关的view对象是否被释放。
由于每个这种类型的callback都有必要加上这样的guard code,所以本渣干脆做了如下的接口:
function MyPackage.callbackWrapper(views,callback) return function(...) for _,view in pairs(views) do if tolua.isnull(view) then return end end if callback ~= nil then callback(...) end end end
拿到一个node九个端点的坐标
--[[-- get the nine positions of a node (the following variables are defined in display.lua of quickx): display.CENTER display.LEFT_TOP display.CENTER_TOP display.RIGHT_TOP display.CENTER_LEFT display.CENTER_RIGHT display.BOTTOM_LEFT display.BOTTOM_RIGHT display.BOTTOM_CENTER ]] function MyPackage.getPositionOfNode(node,alignType) if not node or tolua.isnull(node) then return end local size = node:getContentSize() if size.width == 0 and size.height == 0 then size = node:getCascadeBoundingBox() end local pos = cc.p(node:getPosition()) local anchorPoint = cc.p(node:getAnchorPoint()) if alignType == display.LEFT_TOP or alignType == display.LEFT_CENTER or alignType == display.LEFT_BOTTOM then pos.x = pos.x - size.width * anchorPoint.x elseif alignType == display.CENTER_TOP or alignType == display.CENTER or alignType == display.CENTER_BOTTOM then pos.x = pos.x - size.width * anchorPoint.x + size.width * 0.5 elseif alignType == display.RIGHT_TOP or alignType == display.RIGHT_CENTER or alignType == display.RIGHT_BOTTOM then pos.x = pos.x - size.width * anchorPoint.x + size.width end if alignType == display.BOTTOM_LEFT or alignType == display.BOTTOM_CENTER or alignType == display.BOTTOM_RIGHT then pos.y = pos.y - size.height * anchorPoint.y elseif alignType == display.CENTER_LEFT or alignType == display.CENTER or alignType == display.CENTER_RIGHT then pos.y = pos.y - size.height * anchorPoint.y + size.height * 0.5 elseif alignType == display.TOP_LEFT or alignType == display.TOP_CENTER or alignType == display.TOP_RIGHT then pos.y = pos.y - size.height * anchorPoint.y + size.height end return pos end
在某个container中加入sprite,可指定根据container大小进行缩放及对齐方式
function MyPackage.displaySpriteOnContainer(sprite,container,scaleToFit,alignType) if tolua.isnull(container) then return end -- default settings local scaleToFit = (scaleToFit ~= false) local alignType = alignType or display.CENTER if not tolua.isnull(sprite) then local originSize = sprite:getContentSize() if originSize.width == 0 or originSize.height == 0 then originSize = sprite:getCascadeBoundingBox() end local targetSize = container:getContentSize() if targetSize.width == 0 or targetSize.height == 0 then targetSize = container:getCascadeBoundingBox() end if scaleToFit then sprite:setScale(targetSize.width / originSize.width,targetSize.height / originSize.height) end -- NOTE: ignore container's anchor point local pos = MyPackage.getPositionOfNode(container,alignType) local leftBottomPos = MyPackage.getPositionOfNode(container,display.LEFT_BOTTOM) local posX = pos.x - leftBottomPos.x local posY = pos.y - leftBottomPos.y display.align(sprite,alignType,posX,posY) container:addChild(sprite) end end原文链接:https://www.f2er.com/cocos2dx/340299.html