在quick-cocos2d-x中对非2的幂纹理进行平铺操作

在quick-cocos2d-x中对非2的幂纹理进行平铺操作

tile use NPOT texture in quick-cocos2d-x

本文基于 quick 2.2.1rc 版本

在 quick 的 framework.display 包中,有这样一个方法实现图片的平铺:

 1function display.newTilesSprite(filename, rect)
 2    if not rect then
 3        rect = CCRect(0, 0, display.width, display.height)
 4    end
 5    local sprite = CCSprite:create(filename, rect)
 6    if not sprite then
 7        echoError("display.newTilesSprite() - create sprite failure, filename %s", tostring(filename))
 8        return
 9    end
10
11    local tp = ccTexParams()
12    tp.minFilter = 9729
13    tp.magFilter = 9729
14    tp.wrapS = 10497
15    tp.wrapT = 10497
16    sprite:getTexture():setTexParameters(tp)
17    CCSpriteExtend.extend(sprite)
18
19    display.align(sprite, display.LEFT_BOTTOM, 0, 0)
20
21    return sprite
22end

这里直接通过调整 OpenGL ES 的纹理渲染参数来实现平铺,性能相当好。

但使用这个方法有个限制,就是被平铺的纹理必须是2的幂(POT, Power Of Two)。

于是,我尝试使用 CCSpriteBatchNode 来对纹理进行平铺,达到不用2的幂(NPOT)的纹理即可进行平铺的目的。

但是这个方法也有一个问题。当对这个 CCSpriteBatchNode 进行缩放的时候,平铺的纹理之间会出现非常细的空隙,导致最终看起来的效果像是栅栏一样,无法实现无缝平铺的效果。

这种缩放并不一定需要主动进行。假设你的游戏做了多分辨率处理(在如今的世界,这是不可避免的),在不同的设备分辨率中,cocos2d-x 会根据分辨率进行缩放处理。 这种情况下也会出现这个问题。

一个可行的办法,是制作平铺图的时候,在图像边缘留1个像素的重复像素。在拼接的时候,将两个相邻的纹理互相覆盖1个像素。

我把这个功能封装成了 display.newTiledBatchNode 方法:

 1-- 创建一个可平铺的 CCSpriteBatchNode,纹理的大小可以是非2的幂
 2-- @param __fileName 与 display.newSprite 的第一个参数相同
 3-- @param __texture plist文件,因为使用了BatchNode,必须传递plist文件
 4-- @param __size 一个CCSize对象
 5-- @param __hPadding 横向覆盖几个像素
 6-- @param __vPadding 纵向覆盖几个像素
 7-- @return a CCSpriteBatchNode
 8
 9function display.newTiledBatchNode(__fileName, __texture, __size, __hPadding, __vPadding)
10	__size = __size or cc.size(display.width, display.height)
11	__hPadding = __hPadding or 0
12	__vPadding = __vPadding or 0
13	local __sprite = display.newSprite(__fileName)
14	local __sliceSize = __sprite:getContentSize()
15	__sliceSize.width = __sliceSize.width - __hPadding
16	__sliceSize.height = __sliceSize.height - __vPadding
17	local __xRepeat = math.ceil(__size.width/__sliceSize.width)
18	local __yRepeat = math.ceil(__size.height/__sliceSize.height)
19	-- how maney sprites we need to fill in tiled node?
20	local __capacity = __xRepeat * __yRepeat
21	local __batch = display.newBatchNode(__texture, __capacity)
22	local __newSize = cc.size(0,0)
23	--printf("newTileNode xRepeat:%u, yRepeat:%u", __xRepeat, __yRepeat)
24	for y=0,__yRepeat-1 do
25		for x=0,__xRepeat-1 do
26			__newSize.width = __newSize.width + __sliceSize.width
27			__sprite = display.newSprite(__fileName)
28				:align(display.LEFT_BOTTOM,x*__sliceSize.width, y*__sliceSize.height)
29				:addTo(__batch)
30				--print("newTileNode:", x*__sliceSize.width, y*__sliceSize.height)
31		end
32		__newSize.height = __newSize.height + __sliceSize.height
33	end
34	__batch:setContentSize(__newSize)
35	return __batch, __newSize.width, __newSize.height
36end

这个方法已经加入了 quick 官方仓库的 develop 分支。

但是,这个方法无法处理这样的情景——平铺带有透明度的纹理。